mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-24 04:28:58 +00:00
parent
a12a6a4894
commit
8d6d6bdd84
@ -53,6 +53,7 @@ SplitView {
|
|||||||
}
|
}
|
||||||
currencyStore: CurrenciesStore {}
|
currencyStore: CurrenciesStore {}
|
||||||
swapFormData: d.swapInputParamsForm
|
swapFormData: d.swapInputParamsForm
|
||||||
|
swapOutputData: SwapOutputData {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@ SplitView {
|
|||||||
}
|
}
|
||||||
return selectedChain
|
return selectedChain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property SwapTransactionRoutes dummySwapTransactionRoutes: SwapTransactionRoutes{}
|
||||||
}
|
}
|
||||||
|
|
||||||
PopupBackground {
|
PopupBackground {
|
||||||
@ -71,6 +73,45 @@ SplitView {
|
|||||||
toTokenAmount: swapOutputAmount.text
|
toTokenAmount: swapOutputAmount.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwapModalAdaptor {
|
||||||
|
id: swapModalAdaptor
|
||||||
|
swapStore: SwapStore {
|
||||||
|
signal suggestedRoutesReady(var txRoutes)
|
||||||
|
readonly property var accounts: d.accountsModel
|
||||||
|
readonly property var flatNetworks: d.flatNetworksModel
|
||||||
|
readonly property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked
|
||||||
|
|
||||||
|
function fetchSuggestedRoutes(accountFrom, accountTo, amount, tokenFrom, tokenTo,
|
||||||
|
disabledFromChainIDs, disabledToChainIDs, preferredChainIDs, sendType, lockedInAmounts) {
|
||||||
|
console.debug("fetchSuggestedRoutes called >> accountFrom = ",accountFrom, " accountTo =",
|
||||||
|
accountTo, "amount = ",amount, " tokenFrom = ",tokenFrom, " tokenTo = ", tokenTo,
|
||||||
|
" disabledFromChainIDs = ",disabledFromChainIDs, " disabledToChainIDs = ",disabledToChainIDs,
|
||||||
|
" preferredChainIDs = ",preferredChainIDs, " sendType =", sendType, " lockedInAmounts = ",lockedInAmounts)
|
||||||
|
}
|
||||||
|
function authenticateAndTransfer(uuid, accountFrom, accountTo, tokenFrom,
|
||||||
|
tokenTo, sendType, tokenName, tokenIsOwnerToken, paths) {
|
||||||
|
console.debug("authenticateAndTransfer called >> uuid ", uuid, " accountFrom = ",accountFrom, " accountTo =",
|
||||||
|
accountTo, "tokenFrom = ",tokenFrom, " tokenTo = ",tokenTo, " sendType = ", sendType,
|
||||||
|
" tokenName = ", tokenName, " tokenIsOwnerToken = ", tokenIsOwnerToken, " paths = ", paths)
|
||||||
|
}
|
||||||
|
function getWei2Eth(wei, decimals) {
|
||||||
|
return wei/(10**decimals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walletAssetsStore: WalletAssetsStore {
|
||||||
|
id: thisWalletAssetStore
|
||||||
|
walletTokensStore: TokensStore {
|
||||||
|
readonly property var plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||||
|
getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => 0
|
||||||
|
}
|
||||||
|
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||||
|
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||||
|
}
|
||||||
|
currencyStore: CurrenciesStore {}
|
||||||
|
swapFormData: swapInputForm
|
||||||
|
swapOutputData: SwapOutputData{}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: swapModal
|
id: swapModal
|
||||||
SwapModal {
|
SwapModal {
|
||||||
@ -79,32 +120,7 @@ SplitView {
|
|||||||
closePolicy: Popup.CloseOnEscape
|
closePolicy: Popup.CloseOnEscape
|
||||||
destroyOnClose: true
|
destroyOnClose: true
|
||||||
swapInputParamsForm: swapInputForm
|
swapInputParamsForm: swapInputForm
|
||||||
swapAdaptor: SwapModalAdaptor {
|
swapAdaptor: swapModalAdaptor
|
||||||
swapProposalLoading: loadingCheckBox.checked
|
|
||||||
swapProposalReady: swapProposalReadyCheckBox.checked
|
|
||||||
swapStore: SwapStore {
|
|
||||||
readonly property var accounts: d.accountsModel
|
|
||||||
readonly property var flatNetworks: d.flatNetworksModel
|
|
||||||
readonly property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked
|
|
||||||
|
|
||||||
signal suggestedRoutesReady(var txRoutes)
|
|
||||||
|
|
||||||
function fetchSuggestedRoutes(accountFrom, accountTo, amount, tokenFrom, tokenTo,
|
|
||||||
disabledFromChainIDs, disabledToChainIDs, preferredChainIDs, sendType, lockedInAmounts) {}
|
|
||||||
function authenticateAndTransfer(uuid, accountFrom, accountTo,
|
|
||||||
tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths) {}
|
|
||||||
}
|
|
||||||
walletAssetsStore: WalletAssetsStore {
|
|
||||||
id: thisWalletAssetStore
|
|
||||||
walletTokensStore: TokensStore {
|
|
||||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
|
||||||
}
|
|
||||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
|
||||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
|
||||||
}
|
|
||||||
currencyStore: CurrenciesStore {}
|
|
||||||
swapFormData: swapInputForm
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,23 +203,25 @@ SplitView {
|
|||||||
currentIndex: 1
|
currentIndex: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusInput {
|
Button {
|
||||||
id: swapOutputAmount
|
text: "emit no routes found event"
|
||||||
Layout.preferredWidth: 100
|
onClicked: {
|
||||||
label: "Token amount to receive"
|
swapModalAdaptor.swapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txNoRoutes)
|
||||||
text: "100"
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
Button {
|
||||||
id: loadingCheckBox
|
text: "emit no approval needed route"
|
||||||
text: "swap proposal loading"
|
onClicked: {
|
||||||
checked: false
|
swapModalAdaptor.swapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRouteNoApproval)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
Button {
|
||||||
id: swapProposalReadyCheckBox
|
text: "emit approval needed route"
|
||||||
text: "swap proposal ready"
|
onClicked: {
|
||||||
checked: false
|
swapModalAdaptor.swapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ Item {
|
|||||||
}
|
}
|
||||||
currencyStore: CurrenciesStore {}
|
currencyStore: CurrenciesStore {}
|
||||||
swapFormData: SwapInputParamsForm {}
|
swapFormData: SwapInputParamsForm {}
|
||||||
|
swapOutputData: SwapOutputData {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtTest 1.15
|
import QtTest 1.15
|
||||||
|
|
||||||
import StatusQ 0.1 // See #10218
|
import StatusQ 0.1 // See #10218
|
||||||
@ -22,10 +22,18 @@ Item {
|
|||||||
width: 600
|
width: 600
|
||||||
height: 400
|
height: 400
|
||||||
|
|
||||||
|
readonly property var dummySwapTransactionRoutes: SwapTransactionRoutes {}
|
||||||
|
|
||||||
readonly property var swapStore: SwapStore {
|
readonly property var swapStore: SwapStore {
|
||||||
|
signal suggestedRoutesReady(var txRoutes)
|
||||||
readonly property var accounts: WalletAccountsModel {}
|
readonly property var accounts: WalletAccountsModel {}
|
||||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||||
readonly property bool areTestNetworksEnabled: true
|
readonly property bool areTestNetworksEnabled: true
|
||||||
|
function getWei2Eth(wei, decimals) {
|
||||||
|
return wei/(10**decimals)
|
||||||
|
}
|
||||||
|
function fetchSuggestedRoutes(accountFrom, accountTo, amount, tokenFrom, tokenTo,
|
||||||
|
disabledFromChainIDs, disabledToChainIDs, preferredChainIDs, sendType, lockedInAmounts) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var swapAdaptor: SwapModalAdaptor {
|
readonly property var swapAdaptor: SwapModalAdaptor {
|
||||||
@ -34,12 +42,14 @@ Item {
|
|||||||
id: thisWalletAssetStore
|
id: thisWalletAssetStore
|
||||||
walletTokensStore: TokensStore {
|
walletTokensStore: TokensStore {
|
||||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||||
|
getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => 0
|
||||||
}
|
}
|
||||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||||
}
|
}
|
||||||
swapStore: root.swapStore
|
swapStore: root.swapStore
|
||||||
swapFormData: root.swapFormData
|
swapFormData: root.swapFormData
|
||||||
|
swapOutputData: SwapOutputData{}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var swapFormData: SwapInputParamsForm {}
|
readonly property var swapFormData: SwapInputParamsForm {}
|
||||||
@ -58,8 +68,19 @@ Item {
|
|||||||
|
|
||||||
property SwapModal controlUnderTest: null
|
property SwapModal controlUnderTest: null
|
||||||
|
|
||||||
|
readonly property SignalSpy formValuesChanged: SignalSpy {
|
||||||
|
target: root.swapFormData
|
||||||
|
signalName: "formValuesChanged"
|
||||||
|
}
|
||||||
|
|
||||||
// helper functions -------------------------------------------------------------
|
// helper functions -------------------------------------------------------------
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||||
|
}
|
||||||
|
|
||||||
function launchAndVerfyModal() {
|
function launchAndVerfyModal() {
|
||||||
|
formValuesChanged.clear()
|
||||||
verify(!!controlUnderTest)
|
verify(!!controlUnderTest)
|
||||||
controlUnderTest.open()
|
controlUnderTest.open()
|
||||||
verify(!!controlUnderTest.opened)
|
verify(!!controlUnderTest.opened)
|
||||||
@ -69,6 +90,7 @@ Item {
|
|||||||
verify(!!controlUnderTest)
|
verify(!!controlUnderTest)
|
||||||
controlUnderTest.close()
|
controlUnderTest.close()
|
||||||
verify(!controlUnderTest.opened)
|
verify(!controlUnderTest.opened)
|
||||||
|
formValuesChanged.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAndVerifyAccountsModalHeader() {
|
function getAndVerifyAccountsModalHeader() {
|
||||||
@ -85,11 +107,19 @@ Item {
|
|||||||
verify(!!accountsModalHeader.control.popup.opened)
|
verify(!!accountsModalHeader.control.popup.opened)
|
||||||
return accountsModalHeader
|
return accountsModalHeader
|
||||||
}
|
}
|
||||||
// end helper functions -------------------------------------------------------------
|
|
||||||
|
|
||||||
function init() {
|
function verifyLoadingAndNoErrorsState() {
|
||||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
// verify loading state was set and no errors currently
|
||||||
|
verify(!root.swapAdaptor.validSwapProposalReceived)
|
||||||
|
verify(root.swapAdaptor.swapProposalLoading)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.bestRoutes, [])
|
||||||
|
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.hasError, false)
|
||||||
}
|
}
|
||||||
|
// end helper functions -------------------------------------------------------------
|
||||||
|
|
||||||
function test_floating_header_default_account() {
|
function test_floating_header_default_account() {
|
||||||
verify(!!controlUnderTest)
|
verify(!!controlUnderTest)
|
||||||
@ -408,7 +438,7 @@ Item {
|
|||||||
verify(!editSlippagePanel.visible)
|
verify(!editSlippagePanel.visible)
|
||||||
|
|
||||||
// set swap proposal to ready and check state of the edit slippage buttons and max slippage values
|
// set swap proposal to ready and check state of the edit slippage buttons and max slippage values
|
||||||
root.swapAdaptor.swapProposalReady = true
|
root.swapAdaptor.validSwapProposalReceived = true
|
||||||
compare(maxSlippageValue.text, "%1%".arg(0.5))
|
compare(maxSlippageValue.text, "%1%".arg(0.5))
|
||||||
verify(editSlippageButton.visible)
|
verify(editSlippageButton.visible)
|
||||||
|
|
||||||
@ -444,5 +474,131 @@ Item {
|
|||||||
verify(!!signButton)
|
verify(!!signButton)
|
||||||
verify(signButton.enabled)
|
verify(signButton.enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_modal_swap_proposal_setup() {
|
||||||
|
// by default the max slippage button should show no values and the edit button shouldnt be visible
|
||||||
|
|
||||||
|
root.swapAdaptor.reset()
|
||||||
|
|
||||||
|
// Launch popup
|
||||||
|
launchAndVerfyModal()
|
||||||
|
|
||||||
|
const maxFeesText = findChild(controlUnderTest, "maxFeesText")
|
||||||
|
verify(!!maxFeesText)
|
||||||
|
|
||||||
|
const maxFeesValue = findChild(controlUnderTest, "maxFeesValue")
|
||||||
|
verify(!!maxFeesValue)
|
||||||
|
|
||||||
|
const signButton = findChild(controlUnderTest, "signButton")
|
||||||
|
verify(!!signButton)
|
||||||
|
|
||||||
|
const errorTag = findChild(controlUnderTest, "errorTag")
|
||||||
|
verify(!!errorTag)
|
||||||
|
|
||||||
|
// Check max fees values and sign button state when nothing is set
|
||||||
|
compare(maxFeesText.text, qsTr("Max fees:"))
|
||||||
|
compare(maxFeesValue.text, "--")
|
||||||
|
verify(!signButton.enabled)
|
||||||
|
verify(!errorTag.visible)
|
||||||
|
|
||||||
|
// set input values in the form correctly
|
||||||
|
root.swapFormData.fromTokensKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(0).key
|
||||||
|
compare(formValuesChanged.count, 1)
|
||||||
|
root.swapFormData.toTokenKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(1).key
|
||||||
|
compare(formValuesChanged.count, 2)
|
||||||
|
root.swapFormData.fromTokenAmount = 10
|
||||||
|
compare(formValuesChanged.count, 3)
|
||||||
|
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||||
|
compare(formValuesChanged.count, 4)
|
||||||
|
|
||||||
|
// wait for fetchSuggestedRoutes function to be called
|
||||||
|
wait(1000)
|
||||||
|
|
||||||
|
// verify loading state was set and no errors currently
|
||||||
|
verifyLoadingAndNoErrorsState()
|
||||||
|
|
||||||
|
// emit event that no routes were found
|
||||||
|
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes)
|
||||||
|
|
||||||
|
// verify loading state was removed and that error was displayed
|
||||||
|
verify(!root.swapAdaptor.validSwapProposalReceived)
|
||||||
|
verify(!root.swapAdaptor.swapProposalLoading)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.bestRoutes, [])
|
||||||
|
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.hasError, true)
|
||||||
|
verify(errorTag.visible)
|
||||||
|
verify(errorTag.text, qsTr("An error has occured, please try again"))
|
||||||
|
verify(!signButton.enabled)
|
||||||
|
compare(signButton.text, qsTr("Swap"))
|
||||||
|
|
||||||
|
// edit some params to retry swap
|
||||||
|
root.swapFormData.fromTokenAmount = 11
|
||||||
|
compare(formValuesChanged.count, 5)
|
||||||
|
|
||||||
|
// wait for fetchSuggestedRoutes function to be called
|
||||||
|
wait(1000)
|
||||||
|
|
||||||
|
// verify loading state was set and no errors currently
|
||||||
|
verifyLoadingAndNoErrorsState()
|
||||||
|
|
||||||
|
// emit event with route that needs no approval
|
||||||
|
let txRoutes = root.dummySwapTransactionRoutes.txHasRouteNoApproval
|
||||||
|
root.swapStore.suggestedRoutesReady(txRoutes)
|
||||||
|
|
||||||
|
// verify loading state removed and data ius displayed as expected on the Modal
|
||||||
|
verify(root.swapAdaptor.validSwapProposalReceived)
|
||||||
|
verify(!root.swapAdaptor.swapProposalLoading)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.toTokenAmount, root.swapStore.getWei2Eth(txRoutes.amountToReceive, root.swapAdaptor.toToken.decimals).toString())
|
||||||
|
|
||||||
|
// calculation needed for total fees
|
||||||
|
let gasTimeEstimate = txRoutes.gasTimeEstimate
|
||||||
|
let totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.swapAdaptor.fromToken.marketDetails.currencyPrice.amount
|
||||||
|
let totalFees = root.swapAdaptor.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat
|
||||||
|
|
||||||
|
compare(root.swapAdaptor.swapOutputData.totalFees, totalFees)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.bestRoutes, txRoutes.suggestedRoutes)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.hasError, false)
|
||||||
|
verify(!errorTag.visible)
|
||||||
|
verify(signButton.enabled)
|
||||||
|
compare(signButton.text, qsTr("Swap"))
|
||||||
|
|
||||||
|
// edit some params to retry swap
|
||||||
|
root.swapFormData.fromTokenAmount = 1
|
||||||
|
compare(formValuesChanged.count, 6)
|
||||||
|
|
||||||
|
// wait for fetchSuggestedRoutes function to be called
|
||||||
|
wait(1000)
|
||||||
|
|
||||||
|
// verify loading state was set and no errors currently
|
||||||
|
verifyLoadingAndNoErrorsState()
|
||||||
|
|
||||||
|
// emit event with route that needs no approval
|
||||||
|
let txRoutes2 = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
|
||||||
|
root.swapStore.suggestedRoutesReady(txRoutes2)
|
||||||
|
|
||||||
|
// verify loading state removed and data ius displayed as expected on the Modal
|
||||||
|
verify(root.swapAdaptor.validSwapProposalReceived)
|
||||||
|
verify(!root.swapAdaptor.swapProposalLoading)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "0")
|
||||||
|
compare(root.swapAdaptor.swapOutputData.toTokenAmount, root.swapStore.getWei2Eth(txRoutes2.amountToReceive, root.swapAdaptor.toToken.decimals).toString())
|
||||||
|
|
||||||
|
// calculation needed for total fees
|
||||||
|
gasTimeEstimate = txRoutes2.gasTimeEstimate
|
||||||
|
totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.swapAdaptor.fromToken.marketDetails.currencyPrice.amount
|
||||||
|
totalFees = root.swapAdaptor.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat
|
||||||
|
|
||||||
|
compare(root.swapAdaptor.swapOutputData.totalFees, totalFees)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.bestRoutes, txRoutes2.suggestedRoutes)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.approvalNeeded, true)
|
||||||
|
compare(root.swapAdaptor.swapOutputData.hasError, false)
|
||||||
|
verify(!errorTag.visible)
|
||||||
|
verify(signButton.enabled)
|
||||||
|
compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
144
storybook/src/Models/SwapTransactionRoutes.qml
Normal file
144
storybook/src/Models/SwapTransactionRoutes.qml
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
import StatusQ 0.1
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var txNoRoutes: ({
|
||||||
|
suggestedRoutes: root.noRoutes,
|
||||||
|
gasTimeEstimate: {
|
||||||
|
totalFeesInEth:0.0,
|
||||||
|
totalTokenFees:0.0,
|
||||||
|
totalTime:0
|
||||||
|
},
|
||||||
|
amountToReceive:"0",
|
||||||
|
toNetworksModel:[],
|
||||||
|
error:""
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
property var txHasRouteNoApproval: ({
|
||||||
|
suggestedRoutes: root.goodRouteNoApprovalNeeded,
|
||||||
|
gasTimeEstimate:{
|
||||||
|
totalFeesInEth:0.0005032000000000001,
|
||||||
|
totalTokenFees:-0.004508663259772343,
|
||||||
|
totalTime:2
|
||||||
|
},
|
||||||
|
amountToReceive: 379295138519599728000,
|
||||||
|
toNetworksModel: root.toModel
|
||||||
|
})
|
||||||
|
|
||||||
|
property var txHasRoutesApprovalNeeded: ({
|
||||||
|
suggestedRoutes: root.goodRouteApprovalNeeded,
|
||||||
|
gasTimeEstimate:{
|
||||||
|
totalFeesInEth:0.0005032000000000001,
|
||||||
|
totalTokenFees:-0.004508663259772343,
|
||||||
|
totalTime:2
|
||||||
|
},
|
||||||
|
amountToReceive: 379295138519599728000,
|
||||||
|
toNetworksModel: root.toModel
|
||||||
|
})
|
||||||
|
|
||||||
|
property ListModel toModel: ListModel {
|
||||||
|
ListElement {
|
||||||
|
chainId: 420
|
||||||
|
chainName: "Optimism"
|
||||||
|
iconUrl: "network/Network=Optimism"
|
||||||
|
amountOut: "3003845308235848343"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property ListModel goodRouteNoApprovalNeeded: ListModel {
|
||||||
|
function rowCount() {
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: append(suggestesRoutes)
|
||||||
|
|
||||||
|
property var suggestesRoutes: [
|
||||||
|
{
|
||||||
|
route: {
|
||||||
|
bridgeName:"Paraswap",
|
||||||
|
fromNetwork: NetworksModel.flatNetworks.get(1),
|
||||||
|
toNetwork: NetworksModel.flatNetworks.get(1),
|
||||||
|
maxAmountIn:"22562169837824631",
|
||||||
|
amountIn:"100000000000000",
|
||||||
|
amountOut:"379295138519599728",
|
||||||
|
gasAmount:169300,
|
||||||
|
gasFees:{
|
||||||
|
gasPrice:0.061734012,
|
||||||
|
baseFee:0.055187939,
|
||||||
|
maxPriorityFeePerGas:0.001,
|
||||||
|
maxFeePerGasL:0.059980417,
|
||||||
|
maxFeePerGasM:0.060071775,
|
||||||
|
maxFeePerGasH:0.110375878,
|
||||||
|
l1GasFee:318800.0,
|
||||||
|
eip1559Enabled:true
|
||||||
|
},
|
||||||
|
tokenFees:0.0,
|
||||||
|
bonderFees:"0x0",
|
||||||
|
cost:1211911824.038662,
|
||||||
|
estimatedTime:3,
|
||||||
|
amountInLocked:false,
|
||||||
|
isFirstSimpleTx:true,
|
||||||
|
isFirstBridgeTx:true,
|
||||||
|
approvalRequired:false,
|
||||||
|
approvalGasFees:0.0,
|
||||||
|
approvalAmountRequired:"0",
|
||||||
|
approvalContractAddress:"0x216b4b4ba9f3e719726886d34a177484278bfcae"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
property ListModel goodRouteApprovalNeeded: ListModel {
|
||||||
|
function rowCount() {
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: append(suggestesRoutes)
|
||||||
|
|
||||||
|
property var suggestesRoutes: [
|
||||||
|
{
|
||||||
|
route: {
|
||||||
|
bridgeName:"Paraswap",
|
||||||
|
fromNetwork: NetworksModel.flatNetworks.get(1),
|
||||||
|
toNetwork: NetworksModel.flatNetworks.get(1),
|
||||||
|
maxAmountIn:"22562169837824631",
|
||||||
|
amountIn:"100000000000000",
|
||||||
|
amountOut:"379295138519599728",
|
||||||
|
gasAmount:169300,
|
||||||
|
gasFees:{
|
||||||
|
gasPrice:0.061734012,
|
||||||
|
baseFee:0.055187939,
|
||||||
|
maxPriorityFeePerGas:0.001,
|
||||||
|
maxFeePerGasL:0.059980417,
|
||||||
|
maxFeePerGasM:0.060071775,
|
||||||
|
maxFeePerGasH:0.110375878,
|
||||||
|
l1GasFee:318800.0,
|
||||||
|
eip1559Enabled:true
|
||||||
|
},
|
||||||
|
tokenFees:0.0,
|
||||||
|
bonderFees:"0x0",
|
||||||
|
cost:1211911824.038662,
|
||||||
|
estimatedTime:3,
|
||||||
|
amountInLocked:false,
|
||||||
|
isFirstSimpleTx:true,
|
||||||
|
isFirstBridgeTx:true,
|
||||||
|
approvalRequired:true,
|
||||||
|
approvalGasFees:0.0,
|
||||||
|
approvalAmountRequired:"0",
|
||||||
|
approvalContractAddress:"0x216b4b4ba9f3e719726886d34a177484278bfcae"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
property ListModel noRoutes: ListModel {
|
||||||
|
function rowCount() {
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ GroupedAccountsAssetsModel 1.0 GroupedAccountsAssetsModel.qml
|
|||||||
TokensBySymbolModel 1.0 TokensBySymbolModel.qml
|
TokensBySymbolModel 1.0 TokensBySymbolModel.qml
|
||||||
CommunitiesModel 1.0 CommunitiesModel.qml
|
CommunitiesModel 1.0 CommunitiesModel.qml
|
||||||
OnRampProvidersModel 1.0 OnRampProvidersModel.qml
|
OnRampProvidersModel 1.0 OnRampProvidersModel.qml
|
||||||
|
SwapTransactionRoutes 1.0 SwapTransactionRoutes.qml
|
||||||
|
|
||||||
singleton ModelsData 1.0 ModelsData.qml
|
singleton ModelsData 1.0 ModelsData.qml
|
||||||
singleton NetworksModel 1.0 NetworksModel.qml
|
singleton NetworksModel 1.0 NetworksModel.qml
|
||||||
|
@ -219,6 +219,7 @@ Item {
|
|||||||
d.swapFormData.selectedAccountIndex = d.selectedAccountIndex
|
d.swapFormData.selectedAccountIndex = d.selectedAccountIndex
|
||||||
d.swapFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
|
d.swapFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
|
||||||
d.swapFormData.fromTokensKey = tokensKey
|
d.swapFormData.fromTokensKey = tokensKey
|
||||||
|
d.swapFormData.toTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
|
||||||
Global.openSwapModalRequested(d.swapFormData)
|
Global.openSwapModalRequested(d.swapFormData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,6 +340,7 @@ Item {
|
|||||||
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
|
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
|
||||||
d.swapFormData.fromTokensKey = walletStore.currentViewedHoldingTokensKey
|
d.swapFormData.fromTokensKey = walletStore.currentViewedHoldingTokensKey
|
||||||
}
|
}
|
||||||
|
d.swapFormData.toTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
|
||||||
Global.openSwapModalRequested(d.swapFormData)
|
Global.openSwapModalRequested(d.swapFormData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import StatusQ.Popups 0.1
|
|||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||||
|
|
||||||
import shared.controls 1.0
|
import shared.controls 1.0
|
||||||
|
|
||||||
@ -94,8 +95,11 @@ Control {
|
|||||||
}
|
}
|
||||||
StatusTextWithLoadingState {
|
StatusTextWithLoadingState {
|
||||||
text: {
|
text: {
|
||||||
let amount = parseFloat(root.toTokenAmount)
|
let amount = !!root.toTokenAmount ? SQUtils.AmountsArithmetic.fromString(root.toTokenAmount) : NaN
|
||||||
let percentageAmount = (amount - ((amount/100) * slippageSelector.value))
|
let percentageAmount = 0
|
||||||
|
if(!Number.isNaN(amount)) {
|
||||||
|
percentageAmount = (amount - ((amount/100) * slippageSelector.value))
|
||||||
|
}
|
||||||
return ("%1 %2").arg(LocaleUtils.numberToLocaleString(percentageAmount)).arg(d.selectedToTokenSymbol)
|
return ("%1 %2").arg(LocaleUtils.numberToLocaleString(percentageAmount)).arg(d.selectedToTokenSymbol)
|
||||||
}
|
}
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import QtQml 2.15
|
import QtQml 2.15
|
||||||
|
|
||||||
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||||
|
|
||||||
/* This is used so that there is an easy way to fill in the data
|
/* This is used so that there is an easy way to fill in the data
|
||||||
needed to launch the Swap Modal with pre-filled requisites. */
|
needed to launch the Swap Modal with pre-filled requisites. */
|
||||||
QtObject {
|
QtObject {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
signal formValuesChanged()
|
||||||
|
|
||||||
property int selectedAccountIndex: 0
|
property int selectedAccountIndex: 0
|
||||||
property int selectedNetworkChainId: -1
|
property int selectedNetworkChainId: -1
|
||||||
property string fromTokensKey: ""
|
property string fromTokensKey: ""
|
||||||
@ -11,4 +16,34 @@ QtObject {
|
|||||||
property string toTokenKey: ""
|
property string toTokenKey: ""
|
||||||
property string toTokenAmount: "0"
|
property string toTokenAmount: "0"
|
||||||
property double selectedSlippage: 0.5
|
property double selectedSlippage: 0.5
|
||||||
|
|
||||||
|
onSelectedAccountIndexChanged: root.formValuesChanged()
|
||||||
|
onSelectedNetworkChainIdChanged: root.formValuesChanged()
|
||||||
|
onFromTokensKeyChanged: root.formValuesChanged()
|
||||||
|
onFromTokenAmountChanged: root.formValuesChanged()
|
||||||
|
onToTokenKeyChanged: root.formValuesChanged()
|
||||||
|
onToTokenAmountChanged: root.formValuesChanged()
|
||||||
|
|
||||||
|
function resetFormData() {
|
||||||
|
selectedAccountIndex = 0
|
||||||
|
selectedNetworkChainId = -1
|
||||||
|
fromTokensKey = ""
|
||||||
|
fromTokenAmount = "0"
|
||||||
|
toTokenKey = ""
|
||||||
|
toTokenAmount = "0"
|
||||||
|
selectedSlippage = 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFormFilledCorrectly() {
|
||||||
|
return root.selectedAccountIndex >= 0 &&
|
||||||
|
root.selectedNetworkChainId !== -1 &&
|
||||||
|
!!root.fromTokensKey && !!root.toTokenKey &&
|
||||||
|
((!!root.fromTokenAmount &&
|
||||||
|
!isNaN(SQUtils.AmountsArithmetic.fromString(root.fromTokenAmount)) &&
|
||||||
|
SQUtils.AmountsArithmetic.fromString(root.fromTokenAmount) > 0) ||
|
||||||
|
(!!root.toTokenAmount &&
|
||||||
|
!isNaN(SQUtils.AmountsArithmetic.fromString(root.toTokenAmount)) &&
|
||||||
|
SQUtils.AmountsArithmetic.fromString(root.toTokenAmount) > 0 )) &&
|
||||||
|
root.selectedSlippage > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import StatusQ.Popups.Dialog 0.1
|
|||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
import shared.popups.send.controls 1.0
|
import shared.popups.send.controls 1.0
|
||||||
|
import shared.controls 1.0
|
||||||
|
|
||||||
import AppLayouts.Wallet.controls 1.0
|
import AppLayouts.Wallet.controls 1.0
|
||||||
|
|
||||||
@ -32,10 +33,27 @@ StatusDialog {
|
|||||||
rightPadding: Style.current.xlPadding
|
rightPadding: Style.current.xlPadding
|
||||||
backgroundColor: Theme.palette.baseColor3
|
backgroundColor: Theme.palette.baseColor3
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
property var fetchSuggestedRoutes: Backpressure.debounce(root, 1000, function() {
|
||||||
|
root.swapAdaptor.fetchSuggestedRoutes()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.swapInputParamsForm
|
||||||
|
function onFormValuesChanged() {
|
||||||
|
root.swapAdaptor.swapProposalLoading = true
|
||||||
|
d.fetchSuggestedRoutes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
NumberAnimation { duration: 1000; easing.type: Easing.OutExpo; alwaysRunToEnd: true}
|
NumberAnimation { duration: 1000; easing.type: Easing.OutExpo; alwaysRunToEnd: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClosed: root.swapAdaptor.reset()
|
||||||
|
|
||||||
header: AccountsModalHeader {
|
header: AccountsModalHeader {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: -height - 18
|
anchors.topMargin: -height - 18
|
||||||
@ -52,91 +70,101 @@ StatusDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: 5
|
spacing: Style.current.padding
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
RowLayout {
|
// without this Column, the whole popup resizing when the network selector popup is clicked
|
||||||
|
Column {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 12
|
spacing: 0
|
||||||
HeaderTitleText {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
width: parent.width
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
spacing: 12
|
||||||
id: modalHeader
|
HeaderTitleText {
|
||||||
text: qsTr("Swap")
|
Layout.fillWidth: true
|
||||||
}
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
StatusBaseText {
|
id: modalHeader
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
text: qsTr("Swap")
|
||||||
text: qsTr("On:")
|
}
|
||||||
color: Theme.palette.baseColor1
|
StatusBaseText {
|
||||||
font.pixelSize: 13
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
lineHeight: 38
|
text: qsTr("On:")
|
||||||
lineHeightMode: Text.FixedHeight
|
color: Theme.palette.baseColor1
|
||||||
verticalAlignment: Text.AlignVCenter
|
font.pixelSize: 13
|
||||||
}
|
lineHeight: 38
|
||||||
// TODO: update this once https://github.com/status-im/status-desktop/issues/14780 is ready
|
lineHeightMode: Text.FixedHeight
|
||||||
NetworkFilter {
|
verticalAlignment: Text.AlignVCenter
|
||||||
id: networkFilter
|
}
|
||||||
objectName: "networkFilter"
|
// TODO: update this once https://github.com/status-im/status-desktop/issues/14780 is ready
|
||||||
Layout.alignment: Qt.AlignVCenter
|
NetworkFilter {
|
||||||
multiSelection: false
|
id: networkFilter
|
||||||
showRadioButtons: false
|
objectName: "networkFilter"
|
||||||
showTitle: false
|
Layout.alignment: Qt.AlignVCenter
|
||||||
flatNetworks: root.swapAdaptor.filteredFlatNetworksModel
|
multiSelection: false
|
||||||
onToggleNetwork: (network) => {
|
showRadioButtons: false
|
||||||
root.swapInputParamsForm.selectedNetworkChainId = network.chainId
|
showTitle: false
|
||||||
}
|
flatNetworks: root.swapAdaptor.filteredFlatNetworksModel
|
||||||
Component.onCompleted: {
|
onToggleNetwork: (network) => {
|
||||||
if(root.swapInputParamsForm.selectedNetworkChainId !== -1)
|
root.swapInputParamsForm.selectedNetworkChainId = network.chainId
|
||||||
networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
if(root.swapInputParamsForm.selectedNetworkChainId !== -1)
|
||||||
|
networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a temporary placeholder while each of the components are being added.
|
// This is a temporary placeholder while each of the components are being added.
|
||||||
StatusBaseText {
|
ColumnLayout {
|
||||||
topPadding: Style.current.padding
|
|
||||||
text: qsTr("This area is a temporary placeholder")
|
|
||||||
font.bold: true
|
|
||||||
}
|
|
||||||
StatusBaseText {
|
|
||||||
text: qsTr("Selected from token: %1").arg(swapInputParamsForm.fromTokensKey)
|
|
||||||
}
|
|
||||||
StatusBaseText {
|
|
||||||
text: qsTr("from token amount: %1").arg(swapInputParamsForm.fromTokenAmount)
|
|
||||||
}
|
|
||||||
StatusBaseText {
|
|
||||||
text: qsTr("Selected to token: %1").arg(swapInputParamsForm.toTokenKey)
|
|
||||||
}
|
|
||||||
StatusBaseText {
|
|
||||||
text: qsTr("to token amount: %1").arg(swapInputParamsForm.toTokenAmount)
|
|
||||||
}
|
|
||||||
StatusButton {
|
|
||||||
text: "Fetch Suggested Routes"
|
|
||||||
onClicked: {
|
|
||||||
swapAdaptor.fetchSuggestedRoutes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusButton {
|
|
||||||
text: "Send Approve Tx"
|
|
||||||
onClicked: {
|
|
||||||
swapAdaptor.sendApproveTx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusButton {
|
|
||||||
text: "Send Swap Tx"
|
|
||||||
onClicked: {
|
|
||||||
swapAdaptor.sendSwapTx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusScrollView {
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 200
|
spacing: 0
|
||||||
|
StatusBaseText {
|
||||||
StatusTextArea {
|
text: "This area is a temporary placeholder"
|
||||||
text: {
|
font.bold: true
|
||||||
let routes = SQUtils.ModelUtils.modelToArray(swapAdaptor.suggestedRoutes)
|
}
|
||||||
let routesString = JSON.stringify(routes, null, " ")
|
/* TODO: Will be swapped out under https://github.com/status-im/status-desktop/issues/14825
|
||||||
return qsTr("Suggested routes: \n%1").arg(routesString)
|
Will also handle that if one input is being edited the other one should be in loading state in that task */
|
||||||
|
StatusBaseText {
|
||||||
|
text: qsTr("Selected from token: %1").arg(swapInputParamsForm.fromTokensKey)
|
||||||
|
}
|
||||||
|
StatusInput {
|
||||||
|
id: fromTokenAmountInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: swapInputParamsForm.fromTokenAmount
|
||||||
|
onTextChanged: {
|
||||||
|
swapInputParamsForm.fromTokenAmount = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: Will be swapped out under https://github.com/status-im/status-desktop/issues/14826
|
||||||
|
Will also handle that if one input is being edited the other one should be in loading state in that task */
|
||||||
|
StatusBaseText {
|
||||||
|
text: qsTr("Selected to token: %1").arg(swapInputParamsForm.toTokenKey)
|
||||||
|
}
|
||||||
|
StatusInput {
|
||||||
|
id: toTokenAmountInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.swapAdaptor.validSwapProposalReceived && root.swapAdaptor.toToken ?
|
||||||
|
root.swapAdaptor.formatCurrencyAmount(root.swapAdaptor.swapOutputData.toTokenAmount,
|
||||||
|
root.swapAdaptor.toToken.symbol,
|
||||||
|
{"minDecimals": root.swapAdaptor.toToken.decimals,
|
||||||
|
"stripTrailingZeroes": true, "noSymbol": true}) :
|
||||||
|
root.swapInputParamsForm.toTokenAmount
|
||||||
|
onTextChanged: {
|
||||||
|
if (!root.swapAdaptor.validSwapProposalReceived) {
|
||||||
|
swapInputParamsForm.toTokenAmount = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: keep this input as disabled until the work for adding a param to handle to
|
||||||
|
and from tokens inputed is supported by backend */
|
||||||
|
input.edit.enabled: false
|
||||||
|
}
|
||||||
|
/* Needed only till sign after approval is implemented under
|
||||||
|
https://github.com/status-im/status-desktop/issues/14833 */
|
||||||
|
StatusButton {
|
||||||
|
text: "Final Swap after Approval"
|
||||||
|
onClicked: {
|
||||||
|
swapAdaptor.sendSwapTx()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,12 +177,20 @@ StatusDialog {
|
|||||||
Layout.topMargin: Style.current.padding
|
Layout.topMargin: Style.current.padding
|
||||||
visible: editSlippageButton.checked
|
visible: editSlippageButton.checked
|
||||||
selectedToToken: root.swapAdaptor.toToken
|
selectedToToken: root.swapAdaptor.toToken
|
||||||
toTokenAmount: root.swapInputParamsForm.toTokenAmount
|
toTokenAmount: root.swapAdaptor.swapOutputData.toTokenAmount
|
||||||
loading: root.swapAdaptor.swapProposalLoading
|
loading: root.swapAdaptor.swapProposalLoading
|
||||||
onSlippageValueChanged: {
|
onSlippageValueChanged: {
|
||||||
root.swapInputParamsForm.selectedSlippage = slippageValue
|
root.swapInputParamsForm.selectedSlippage = slippageValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorTag {
|
||||||
|
objectName: "errorTag"
|
||||||
|
visible: root.swapAdaptor.swapOutputData.hasError
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Style.current.smallPadding
|
||||||
|
text: qsTr("An error has occured, please try again")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer: StatusDialogFooter {
|
footer: StatusDialogFooter {
|
||||||
@ -199,13 +235,20 @@ StatusDialog {
|
|||||||
spacing: Style.current.bigPadding
|
spacing: Style.current.bigPadding
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
text:qsTr("Max fees:")
|
objectName: "maxFeesText"
|
||||||
|
text: qsTr("Max fees:")
|
||||||
color: Theme.palette.directColor5
|
color: Theme.palette.directColor5
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
StatusTextWithLoadingState {
|
StatusTextWithLoadingState {
|
||||||
text: loading ? Constants.dummyText : "--"
|
objectName: "maxFeesValue"
|
||||||
|
text: loading ? Constants.dummyText :
|
||||||
|
root.swapAdaptor.validSwapProposalReceived ?
|
||||||
|
root.swapAdaptor.currencyStore.formatCurrencyAmount(
|
||||||
|
root.swapAdaptor.swapOutputData.totalFees,
|
||||||
|
root.swapAdaptor.currencyStore.currentCurrency) :
|
||||||
|
"--"
|
||||||
customColor: Theme.palette.directColor4
|
customColor: Theme.palette.directColor4
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@ -214,12 +257,26 @@ StatusDialog {
|
|||||||
}
|
}
|
||||||
StatusButton {
|
StatusButton {
|
||||||
objectName: "signButton"
|
objectName: "signButton"
|
||||||
/* TODO: there maybe a different icon shown here in case of approval of spending cap
|
|
||||||
needed TBD under https://github.com/status-im/status-desktop/issues/14833 */
|
|
||||||
icon.name: "password"
|
icon.name: "password"
|
||||||
text: qsTr("Swap")
|
/* TODO: Handling the next step agter approval of spending cap TBD under
|
||||||
|
https://github.com/status-im/status-desktop/issues/14833 */
|
||||||
|
text: root.swapAdaptor.validSwapProposalReceived &&
|
||||||
|
root.swapAdaptor.swapOutputData.approvalNeeded ?
|
||||||
|
qsTr("Approve %1").arg(!!root.swapAdaptor.fromToken ? root.swapAdaptor.fromToken.symbol: "") :
|
||||||
|
qsTr("Swap")
|
||||||
disabledColor: Theme.palette.directColor8
|
disabledColor: Theme.palette.directColor8
|
||||||
enabled: root.swapAdaptor.swapProposalReady && editSlippagePanel.valid
|
enabled: root.swapAdaptor.validSwapProposalReceived && editSlippagePanel.valid
|
||||||
|
onClicked: {
|
||||||
|
if (root.swapAdaptor.validSwapProposalReceived ){
|
||||||
|
if(root.swapAdaptor.swapOutputData.approvalNeeded) {
|
||||||
|
swapAdaptor.sendApproveTx()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
swapAdaptor.sendSwapTx()
|
||||||
|
}
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ QObject {
|
|||||||
required property WalletStore.WalletAssetsStore walletAssetsStore
|
required property WalletStore.WalletAssetsStore walletAssetsStore
|
||||||
required property WalletStore.SwapStore swapStore
|
required property WalletStore.SwapStore swapStore
|
||||||
required property SwapInputParamsForm swapFormData
|
required property SwapInputParamsForm swapFormData
|
||||||
|
required property SwapOutputData swapOutputData
|
||||||
|
|
||||||
/* TODO: link to the actually api to get swap proposal from backend under
|
// the below 2 properties holds the state of finding a swap proposal
|
||||||
https://github.com/status-im/status-desktop/issues/14828 */
|
property bool validSwapProposalReceived: false
|
||||||
property bool swapProposalReady: false
|
|
||||||
property bool swapProposalLoading: false
|
property bool swapProposalLoading: false
|
||||||
|
|
||||||
property bool showCommunityTokens
|
property bool showCommunityTokens
|
||||||
@ -28,28 +28,6 @@ QObject {
|
|||||||
readonly property var fromToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.fromTokensKey)
|
readonly property var fromToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.fromTokensKey)
|
||||||
readonly property var toToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.toTokenKey)
|
readonly property var toToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.toTokenKey)
|
||||||
|
|
||||||
readonly property alias suggestedRoutes: d.suggestedRoutes
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
|
|
||||||
property string uuid
|
|
||||||
// TODO: Remove these properties swap proposal is properly handled
|
|
||||||
property var suggestedRoutes
|
|
||||||
property string rawPaths
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.swapStore
|
|
||||||
function onSuggestedRoutesReady(txRoutes) {
|
|
||||||
root.swapProposalReady = txRoutes.suggestedRoutes.count > 0
|
|
||||||
root.swapProposalLoading = false
|
|
||||||
|
|
||||||
d.suggestedRoutes = txRoutes.suggestedRoutes
|
|
||||||
d.rawPaths = txRoutes.rawPaths
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var nonWatchAccounts: SortFilterProxyModel {
|
readonly property var nonWatchAccounts: SortFilterProxyModel {
|
||||||
sourceModel: root.swapStore.accounts
|
sourceModel: root.swapStore.accounts
|
||||||
filters: ValueFilter {
|
filters: ValueFilter {
|
||||||
@ -61,7 +39,7 @@ QObject {
|
|||||||
proxyRoles: [
|
proxyRoles: [
|
||||||
FastExpressionRole {
|
FastExpressionRole {
|
||||||
name: "accountBalance"
|
name: "accountBalance"
|
||||||
expression: __processAccountBalance(model.address)
|
expression: d.processAccountBalance(model.address)
|
||||||
expectedRoles: ["address"]
|
expectedRoles: ["address"]
|
||||||
},
|
},
|
||||||
FastExpressionRole {
|
FastExpressionRole {
|
||||||
@ -76,6 +54,155 @@ QObject {
|
|||||||
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
|
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Model prepared to provide filtered and sorted assets as per the advanced Settings in token management
|
||||||
|
readonly property var processedAssetsModel: SortFilterProxyModel {
|
||||||
|
property real displayAssetsBelowBalanceThresholdAmount: root.walletAssetsStore.walletTokensStore.getDisplayAssetsBelowBalanceThresholdDisplayAmount()
|
||||||
|
sourceModel: d.assetsWithFilteredBalances
|
||||||
|
proxyRoles: [
|
||||||
|
FastExpressionRole {
|
||||||
|
name: "currentBalance"
|
||||||
|
expression: {
|
||||||
|
// FIXME recalc when selectedNetworkChainId changes
|
||||||
|
root.swapFormData.selectedNetworkChainId
|
||||||
|
return d.getTotalBalance(model.balances, model.decimals)
|
||||||
|
}
|
||||||
|
expectedRoles: ["balances", "decimals"]
|
||||||
|
},
|
||||||
|
FastExpressionRole {
|
||||||
|
name: "currentCurrencyBalance"
|
||||||
|
expression: {
|
||||||
|
if (!!model.marketDetails) {
|
||||||
|
return model.currentBalance * model.marketDetails.currencyPrice.amount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
expectedRoles: ["marketDetails", "currentBalance"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
filters: [
|
||||||
|
FastExpressionFilter {
|
||||||
|
expression: {
|
||||||
|
root.walletAssetsStore.assetsController.revision
|
||||||
|
|
||||||
|
if (!root.walletAssetsStore.assetsController.filterAcceptsSymbol(model.symbol)) // explicitely hidden
|
||||||
|
return false
|
||||||
|
if (!!model.communityId)
|
||||||
|
return root.showCommunityTokens
|
||||||
|
if (root.walletAssetsStore.walletTokensStore.displayAssetsBelowBalance)
|
||||||
|
return model.currentCurrencyBalance > processedAssetsModel.displayAssetsBelowBalanceThresholdAmount
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
expectedRoles: ["symbol", "communityId", "currentCurrencyBalance"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// FIXME sort by assetsController instead, to have the sorting/order as in the main wallet view
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property string uuid
|
||||||
|
|
||||||
|
// Internal model filtering balances by the account selected in the AccountsModalHeader
|
||||||
|
readonly property SubmodelProxyModel assetsWithFilteredBalances: SubmodelProxyModel {
|
||||||
|
sourceModel: root.walletAssetsStore.groupedAccountAssetsModel
|
||||||
|
submodelRoleName: "balances"
|
||||||
|
delegateModel: SortFilterProxyModel {
|
||||||
|
sourceModel: submodel
|
||||||
|
|
||||||
|
filters: [
|
||||||
|
ValueFilter {
|
||||||
|
roleName: "chainId"
|
||||||
|
value: root.swapFormData.selectedNetworkChainId
|
||||||
|
enabled: root.swapFormData.selectedNetworkChainId !== -1
|
||||||
|
}/*,
|
||||||
|
// TODO enable once AccountsModalHeader is reworked!!
|
||||||
|
ValueFilter {
|
||||||
|
roleName: "account"
|
||||||
|
value: root.selectedSenderAccount.address
|
||||||
|
}*/
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property SubmodelProxyModel filteredBalancesModel: SubmodelProxyModel {
|
||||||
|
sourceModel: root.walletAssetsStore.baseGroupedAccountAssetModel
|
||||||
|
submodelRoleName: "balances"
|
||||||
|
delegateModel: SortFilterProxyModel {
|
||||||
|
sourceModel: joinModel
|
||||||
|
filters: ValueFilter {
|
||||||
|
roleName: "chainId"
|
||||||
|
value: root.swapFormData.selectedNetworkChainId
|
||||||
|
}
|
||||||
|
readonly property LeftJoinModel joinModel: LeftJoinModel {
|
||||||
|
leftModel: submodel
|
||||||
|
rightModel: root.swapStore.flatNetworks
|
||||||
|
|
||||||
|
joinRole: "chainId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processAccountBalance(address) {
|
||||||
|
let network = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", root.swapFormData.selectedNetworkChainId)
|
||||||
|
if(!!network) {
|
||||||
|
let balancesModel = ModelUtils.getByKey(filteredBalancesModel, "tokensKey", root.swapFormData.fromTokensKey, "balances")
|
||||||
|
let accountBalance = ModelUtils.getByKey(balancesModel, "account", address)
|
||||||
|
if(!accountBalance) {
|
||||||
|
return {
|
||||||
|
balance: "0",
|
||||||
|
iconUrl: network.iconUrl,
|
||||||
|
chainColor: network.chainColor}
|
||||||
|
}
|
||||||
|
return accountBalance
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function to calculate total balance */
|
||||||
|
function getTotalBalance(balances, decimals, chainIds = [root.swapFormData.selectedNetworkChainId]) {
|
||||||
|
let totalBalance = 0
|
||||||
|
for(let i=0; i<balances.count; i++) {
|
||||||
|
let balancePerAddressPerChain = ModelUtils.get(balances, i)
|
||||||
|
if (chainIds.includes(-1) || chainIds.includes(balancePerAddressPerChain.chainId))
|
||||||
|
totalBalance += AmountsArithmetic.toNumber(balancePerAddressPerChain.balance, decimals)
|
||||||
|
}
|
||||||
|
return totalBalance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.swapStore
|
||||||
|
function onSuggestedRoutesReady(txRoutes) {
|
||||||
|
root.swapOutputData.reset()
|
||||||
|
root.validSwapProposalReceived = false
|
||||||
|
root.swapProposalLoading = false
|
||||||
|
root.swapOutputData.rawPaths = txRoutes.rawPaths
|
||||||
|
// if valid route was found
|
||||||
|
if(txRoutes.suggestedRoutes.count === 1) {
|
||||||
|
root.validSwapProposalReceived = true
|
||||||
|
root.swapOutputData.bestRoutes = txRoutes.suggestedRoutes
|
||||||
|
root.swapOutputData.toTokenAmount = root.swapStore.getWei2Eth(txRoutes.amountToReceive, root.toToken.decimals).toString()
|
||||||
|
let gasTimeEstimate = txRoutes.gasTimeEstimate
|
||||||
|
let totalTokenFeesInFiat = 0
|
||||||
|
if (!!root.fromToken && !!root.fromToken .marketDetails && !!root.fromToken.marketDetails.currencyPrice)
|
||||||
|
totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.fromToken.marketDetails.currencyPrice.amount
|
||||||
|
root.swapOutputData.totalFees = root.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat
|
||||||
|
root.swapOutputData.approvalNeeded = ModelUtils.get(root.swapOutputData.bestRoutes, 0, "route").approvalRequired
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
root.swapOutputData.hasError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
root.swapFormData.resetFormData()
|
||||||
|
root.swapOutputData.reset()
|
||||||
|
root.validSwapProposalReceived = false
|
||||||
|
root.swapProposalLoading = false
|
||||||
|
}
|
||||||
|
|
||||||
function getNetworkShortNames(chainIds) {
|
function getNetworkShortNames(chainIds) {
|
||||||
var networkString = ""
|
var networkString = ""
|
||||||
let chainIdsArray = chainIds.split(":")
|
let chainIdsArray = chainIds.split(":")
|
||||||
@ -119,140 +246,33 @@ QObject {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Model prepared to provide filtered and sorted assets as per the advanced Settings in token management
|
|
||||||
readonly property var processedAssetsModel: SortFilterProxyModel {
|
|
||||||
property real displayAssetsBelowBalanceThresholdAmount: root.walletAssetsStore.walletTokensStore.getDisplayAssetsBelowBalanceThresholdDisplayAmount()
|
|
||||||
sourceModel: __assetsWithFilteredBalances
|
|
||||||
proxyRoles: [
|
|
||||||
FastExpressionRole {
|
|
||||||
name: "currentBalance"
|
|
||||||
expression: {
|
|
||||||
// FIXME recalc when selectedNetworkChainId changes
|
|
||||||
root.swapFormData.selectedNetworkChainId
|
|
||||||
return __getTotalBalance(model.balances, model.decimals)
|
|
||||||
}
|
|
||||||
expectedRoles: ["balances", "decimals"]
|
|
||||||
},
|
|
||||||
FastExpressionRole {
|
|
||||||
name: "currentCurrencyBalance"
|
|
||||||
expression: {
|
|
||||||
if (!!model.marketDetails) {
|
|
||||||
return model.currentBalance * model.marketDetails.currencyPrice.amount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
expectedRoles: ["marketDetails", "currentBalance"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
filters: [
|
|
||||||
FastExpressionFilter {
|
|
||||||
expression: {
|
|
||||||
root.walletAssetsStore.assetsController.revision
|
|
||||||
|
|
||||||
if (!root.walletAssetsStore.assetsController.filterAcceptsSymbol(model.symbol)) // explicitely hidden
|
|
||||||
return false
|
|
||||||
if (!!model.communityId)
|
|
||||||
return root.showCommunityTokens
|
|
||||||
if (root.walletAssetsStore.walletTokensStore.displayAssetsBelowBalance)
|
|
||||||
return model.currentCurrencyBalance > processedAssetsModel.displayAssetsBelowBalanceThresholdAmount
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
expectedRoles: ["symbol", "communityId", "currentCurrencyBalance"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
// FIXME sort by assetsController instead, to have the sorting/order as in the main wallet view
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal properties and functions -----------------------------------------------------------------------------------------------------------------------------
|
|
||||||
readonly property var __fromToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.fromTokensKey)
|
|
||||||
|
|
||||||
// Internal model filtering balances by the account selected in the AccountsModalHeader
|
|
||||||
SubmodelProxyModel {
|
|
||||||
id: __assetsWithFilteredBalances
|
|
||||||
sourceModel: root.walletAssetsStore.groupedAccountAssetsModel
|
|
||||||
submodelRoleName: "balances"
|
|
||||||
delegateModel: SortFilterProxyModel {
|
|
||||||
sourceModel: submodel
|
|
||||||
|
|
||||||
filters: [
|
|
||||||
ValueFilter {
|
|
||||||
roleName: "chainId"
|
|
||||||
value: root.swapFormData.selectedNetworkChainId
|
|
||||||
enabled: root.swapFormData.selectedNetworkChainId !== -1
|
|
||||||
}/*,
|
|
||||||
// TODO enable once AccountsModalHeader is reworked!!
|
|
||||||
ValueFilter {
|
|
||||||
roleName: "account"
|
|
||||||
value: root.selectedSenderAccount.address
|
|
||||||
}*/
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SubmodelProxyModel {
|
|
||||||
id: filteredBalancesModel
|
|
||||||
sourceModel: root.walletAssetsStore.baseGroupedAccountAssetModel
|
|
||||||
submodelRoleName: "balances"
|
|
||||||
delegateModel: SortFilterProxyModel {
|
|
||||||
sourceModel: joinModel
|
|
||||||
filters: ValueFilter {
|
|
||||||
roleName: "chainId"
|
|
||||||
value: root.swapFormData.selectedNetworkChainId
|
|
||||||
}
|
|
||||||
readonly property LeftJoinModel joinModel: LeftJoinModel {
|
|
||||||
leftModel: submodel
|
|
||||||
rightModel: root.swapStore.flatNetworks
|
|
||||||
|
|
||||||
joinRole: "chainId"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function __processAccountBalance(address) {
|
|
||||||
let network = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", root.swapFormData.selectedNetworkChainId)
|
|
||||||
if(!!network) {
|
|
||||||
let balancesModel = ModelUtils.getByKey(filteredBalancesModel, "tokensKey", root.swapFormData.fromTokensKey, "balances")
|
|
||||||
let accountBalance = ModelUtils.getByKey(balancesModel, "account", address)
|
|
||||||
if(!accountBalance) {
|
|
||||||
return {
|
|
||||||
balance: "0",
|
|
||||||
iconUrl: network.iconUrl,
|
|
||||||
chainColor: network.chainColor}
|
|
||||||
}
|
|
||||||
return accountBalance
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Internal function to calculate total balance */
|
|
||||||
function __getTotalBalance(balances, decimals, chainIds = [root.swapFormData.selectedNetworkChainId]) {
|
|
||||||
let totalBalance = 0
|
|
||||||
for(let i=0; i<balances.count; i++) {
|
|
||||||
let balancePerAddressPerChain = ModelUtils.get(balances, i)
|
|
||||||
if (chainIds.includes(-1) || chainIds.includes(balancePerAddressPerChain.chainId))
|
|
||||||
totalBalance += AmountsArithmetic.toNumber(balancePerAddressPerChain.balance, decimals)
|
|
||||||
}
|
|
||||||
return totalBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchSuggestedRoutes() {
|
function fetchSuggestedRoutes() {
|
||||||
root.swapProposalReady = false
|
let amount = !!root.swapFormData.fromTokenAmount ? AmountsArithmetic.fromString(root.swapFormData.fromTokenAmount): NaN
|
||||||
root.swapProposalLoading = true
|
root.swapOutputData.reset()
|
||||||
|
|
||||||
// Identify new swap with a different uuid
|
if(!isNaN(amount) && !!root.fromToken && root.swapFormData.isFormFilledCorrectly()) {
|
||||||
d.uuid = Utils.uuid()
|
let fromTokenAmountInWei = AmountsArithmetic.fromNumber(amount, !!root.fromToken ? root.fromToken.decimals: 18).toString()
|
||||||
|
|
||||||
let account = getSelectedAccount(root.swapFormData.selectedAccountIndex)
|
root.validSwapProposalReceived = false
|
||||||
let accountAddress = account.address
|
|
||||||
let disabledChainIds = getDisabledChainIds(root.swapFormData.selectedNetworkChainId)
|
|
||||||
let preferedChainIds = getAllChainIds()
|
|
||||||
|
|
||||||
// TODO #14825: amount should be in BigInt string representation (fromTokenAmount * 10^decimals)
|
// Identify new swap with a different uuid
|
||||||
// Make sure that's replaced when the input component is integrated
|
d.uuid = Utils.uuid()
|
||||||
root.swapStore.fetchSuggestedRoutes(accountAddress, accountAddress,
|
|
||||||
root.swapFormData.fromTokenAmount, root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
let account = getSelectedAccount(root.swapFormData.selectedAccountIndex)
|
||||||
disabledChainIds, disabledChainIds, preferedChainIds,
|
let accountAddress = account.address
|
||||||
Constants.SendType.Swap, "")
|
let disabledChainIds = getDisabledChainIds(root.swapFormData.selectedNetworkChainId)
|
||||||
|
let preferedChainIds = getAllChainIds()
|
||||||
|
|
||||||
|
// TODO #14825: amount should be in BigInt string representation (fromTokenAmount * 10^decimals)
|
||||||
|
// Make sure that's replaced when the input component is integrated
|
||||||
|
root.swapStore.fetchSuggestedRoutes(accountAddress, accountAddress,
|
||||||
|
fromTokenAmountInWei, root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
||||||
|
disabledChainIds, disabledChainIds, preferedChainIds,
|
||||||
|
Constants.SendType.Swap, "")
|
||||||
|
} else {
|
||||||
|
root.validSwapProposalReceived = false
|
||||||
|
root.swapProposalLoading = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendApproveTx() {
|
function sendApproveTx() {
|
||||||
@ -261,7 +281,7 @@ QObject {
|
|||||||
|
|
||||||
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
||||||
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
||||||
Constants.SendType.Approve, "", false, d.rawPaths)
|
Constants.SendType.Approve, "", false, root.swapOutputData.rawPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendSwapTx() {
|
function sendSwapTx() {
|
||||||
@ -270,6 +290,6 @@ QObject {
|
|||||||
|
|
||||||
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
||||||
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
||||||
Constants.SendType.Swap, "", false, d.rawPaths)
|
Constants.SendType.Swap, "", false, root.swapOutputData.rawPaths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
ui/app/AppLayouts/Wallet/popups/swap/SwapOutputData.qml
Normal file
26
ui/app/AppLayouts/Wallet/popups/swap/SwapOutputData.qml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
/* This is so that all the data from the response
|
||||||
|
to the swap request can be placed here at one place. */
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string fromTokenAmount: "0"
|
||||||
|
property string toTokenAmount: "0"
|
||||||
|
property real totalFees: 0
|
||||||
|
property var bestRoutes: []
|
||||||
|
property bool approvalNeeded
|
||||||
|
property bool hasError
|
||||||
|
property var rawPaths: []
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
root.fromTokenAmount = "0"
|
||||||
|
root.toTokenAmount = "0"
|
||||||
|
root.totalFees = 0
|
||||||
|
root.bestRoutes = []
|
||||||
|
root.approvalNeeded = false
|
||||||
|
root.hasError = false
|
||||||
|
root.rawPaths = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
SwapModal 1.0 SwapModal.qml
|
SwapModal 1.0 SwapModal.qml
|
||||||
SwapInputParamsForm 1.0 SwapInputParamsForm.qml
|
SwapInputParamsForm 1.0 SwapInputParamsForm.qml
|
||||||
SwapModalAdaptor 1.0 SwapModalAdaptor.qml
|
SwapModalAdaptor 1.0 SwapModalAdaptor.qml
|
||||||
|
SwapOutputData 1.0 SwapOutputData.qml
|
||||||
|
@ -37,4 +37,8 @@ QtObject {
|
|||||||
root.walletSectionSendInst.authenticateAndTransferWithParameters(uuid, accountFrom, accountTo,
|
root.walletSectionSendInst.authenticateAndTransferWithParameters(uuid, accountFrom, accountTo,
|
||||||
tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths)
|
tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWei2Eth(wei, decimals) {
|
||||||
|
return globalUtils.wei2Eth(wei, decimals)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1251,6 +1251,7 @@ QtObject {
|
|||||||
walletAssetsStore: root.walletAssetsStore
|
walletAssetsStore: root.walletAssetsStore
|
||||||
currencyStore: root.currencyStore
|
currencyStore: root.currencyStore
|
||||||
swapFormData: swapInputParamsForm
|
swapFormData: swapInputParamsForm
|
||||||
|
swapOutputData: SwapOutputData{}
|
||||||
}
|
}
|
||||||
onClosed: destroy()
|
onClosed: destroy()
|
||||||
}
|
}
|
||||||
|
@ -1317,4 +1317,11 @@ QtObject {
|
|||||||
InProgress = 1,
|
InProgress = 1,
|
||||||
Done = 2
|
Done = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property QtObject swap: QtObject {
|
||||||
|
/* We should be very careful here, this is the token key for Status network token currently,
|
||||||
|
but in case the logic for keys changes in the backend, it should be updated here as well */
|
||||||
|
readonly property string testStatusTokenKey: "STT"
|
||||||
|
readonly property string mainnetStatusTokenKey: "SNT"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user