feat(swap): added more explicit error messages

Closes #14956
This commit is contained in:
Dario Gabriel Lipicar 2024-07-19 00:36:36 -03:00 committed by dlipicar
parent 6eeb917cd7
commit 83db905e28
16 changed files with 283 additions and 52 deletions

View File

@ -70,7 +70,7 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_SUGGESTED_ROUTES_READY) do(e:Args):
let args = SuggestedRoutesArgs(e)
self.delegate.suggestedRoutesReady(args.uuid, args.suggestedRoutes)
self.delegate.suggestedRoutesReady(args.uuid, args.suggestedRoutes, args.errCode, args.errDescription)
self.events.on(SignalType.WalletSignTransactions.event) do(e:Args):
var data = WalletSignal(e)

View File

@ -37,7 +37,7 @@ method suggestedRoutes*(self: AccessInterface,
extraParamsTable: Table[string, string] = initTable[string, string]()) {.base.} =
raise newException(ValueError, "No implementation available")
method suggestedRoutesReady*(self: AccessInterface, uuid: string, suggestedRoutes: SuggestedRoutesDto) {.base.} =
method suggestedRoutesReady*(self: AccessInterface, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) {.base.} =
raise newException(ValueError, "No implementation available")
method authenticateAndTransfer*(self: AccessInterface, from_addr: string, to_addr: string, assetKey: string,

View File

@ -276,7 +276,7 @@ method transactionWasSent*(self: Module, chainId: int, txHash, uuid, error: stri
return
self.view.sendTransactionSentSignal(chainId, txHash, uuid, error)
method suggestedRoutesReady*(self: Module, uuid: string, suggestedRoutes: SuggestedRoutesDto) =
method suggestedRoutesReady*(self: Module, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) =
self.tmpSendTransactionDetails.paths = suggestedRoutes.best
self.tmpSendTransactionDetails.slippagePercentage = none(float)
let paths = suggestedRoutes.best.map(x => self.convertTransactionPathDtoToSuggestedRouteItem(x))
@ -294,7 +294,7 @@ method suggestedRoutesReady*(self: Module, uuid: string, suggestedRoutes: Sugges
amountToReceive = suggestedRoutes.amountToReceive,
toNetworksRouteModel = toNetworksRouteModel,
rawPaths = suggestedRoutes.rawBest)
self.view.setTransactionRoute(transactionRoutes)
self.view.setTransactionRoute(transactionRoutes, errCode, errDescription)
method suggestedRoutes*(self: Module,
uuid: string,

View File

@ -18,6 +18,8 @@ QtObject:
fromNetworksRouteModel: NetworkRouteModel
toNetworksRouteModel: NetworkRouteModel
transactionRoutes: TransactionRoutes
errCode: string
errDescription: string
selectedAssetKey: string
selectedToAssetKey: string
showUnPreferredChains: bool
@ -194,10 +196,12 @@ QtObject:
self.delegate.authenticateAndTransfer(self.selectedSenderAccountAddress, self.selectedRecipient, self.selectedAssetKey,
self.selectedToAssetKey, uuid, self.sendType, self.selectedTokenName, self.selectedTokenIsOwnerToken)
proc suggestedRoutesReady*(self: View, suggestedRoutes: QVariant) {.signal.}
proc setTransactionRoute*(self: View, routes: TransactionRoutes) =
proc suggestedRoutesReady*(self: View, suggestedRoutes: QVariant, errCode: string, errDescription: string) {.signal.}
proc setTransactionRoute*(self: View, routes: TransactionRoutes, errCode: string, errDescription: string) =
self.transactionRoutes = routes
self.suggestedRoutesReady(newQVariant(self.transactionRoutes))
self.errCode = errCode
self.errDescription = errDescription
self.suggestedRoutesReady(newQVariant(self.transactionRoutes), errCode, errDescription)
proc suggestedRoutes*(self: View, amountIn: string, amountOut: string, extraParamsJson: string) {.slot.} =
var extraParamsTable: Table[string, string]

View File

@ -113,6 +113,8 @@ type
SuggestedRoutesArgs* = ref object of Args
uuid*: string
suggestedRoutes*: SuggestedRoutesDto
errCode*: string
errDescription*: string
type
CryptoServicesArgs* = ref object of Args
@ -131,7 +133,7 @@ QtObject:
tokenService: token_service.Service
## Forward declarations
proc suggestedRoutesV2Ready(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, error: string, errCode: string)
proc suggestedRoutesV2Ready(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, errCode: string, errDescription: string)
proc delete*(self: Service) =
self.QObject.delete
@ -162,7 +164,7 @@ QtObject:
self.events.on(SignalType.WalletSuggestedRoutes.event) do(e:Args):
var data = WalletSignal(e)
self.suggestedRoutesV2Ready(data.uuid, data.bestRoute, data.bestRouteRaw, data.error, data.errorCode)
self.suggestedRoutesV2Ready(data.uuid, data.bestRoute, data.bestRouteRaw, data.errorCode, data.error)
self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args):
try:
@ -578,7 +580,7 @@ QtObject:
except Exception as e:
error "Error getting suggested fees", msg = e.msg
proc suggestedRoutesV2Ready(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, error: string, errCode: string) =
proc suggestedRoutesV2Ready(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, errCode: string, errDescription: string) =
# TODO: refactor sending modal part of the app, but for now since we're integrating the router v2 just map params to the old dto
var oldRoute = convertToOldRoute(route)
@ -590,7 +592,12 @@ QtObject:
amountToReceive: getTotalAmountToReceive(oldRoute),
toNetworks: getToNetworksList(oldRoute),
)
self.events.emit(SIGNAL_SUGGESTED_ROUTES_READY, SuggestedRoutesArgs(uuid: uuid, suggestedRoutes: suggestedDto))
self.events.emit(SIGNAL_SUGGESTED_ROUTES_READY, SuggestedRoutesArgs(
uuid: uuid,
suggestedRoutes: suggestedDto,
errCode: errCode,
errDescription: errDescription
))
proc suggestedRoutes*(self: Service,
uuid: string,

View File

@ -241,9 +241,11 @@ SplitView {
amountToReceive: txStore.amountToSend - (txStore.amountToSend*5/100),
toNetworksRouteModel: dummyEventData.toModel
}
let errCode = ""
let errDescription = ""
txStore.fromNetworksRouteModel.updateFromNetworks(dummyEventData.suggestesRoutes)
txStore.toNetworksRouteModel.updateToNetworks(dummyEventData.suggestesRoutes)
txStore.walletSectionSendInst.suggestedRoutesReady(txRoutes)
txStore.walletSectionSendInst.suggestedRoutesReady(txRoutes, errCode, errDescription)
txStore.suggestedRoutesCalled = false
}
}

View File

@ -72,7 +72,7 @@ SplitView {
SwapStore {
id: dSwapStore
signal suggestedRoutesReady(var txRoutes)
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success)
@ -278,7 +278,7 @@ SplitView {
swapInput.text = "0.2"
fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 250, () => {
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRouteNoApproval)
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRouteNoApproval, "", "")
})()
}
}
@ -292,7 +292,7 @@ SplitView {
swapInput.text = "0.1"
fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 1000, () => {
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded)
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded, "", "")
})()
Backpressure.debounce(this, 1500, () => {approveTxButton.clicked()})()
authenticateAndTransferSpy.wait()
@ -304,7 +304,7 @@ SplitView {
})()
fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 1000, () => {
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRouteNoApproval)
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRouteNoApproval, "", "")
})()
}
}
@ -317,7 +317,7 @@ SplitView {
swapInput.text = "0.2"
fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 250, () => {
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txNoRoutes)
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txNoRoutes, "ERR-123", "Fetching proposal error")
})()
}
@ -332,7 +332,7 @@ SplitView {
swapInput.text = "0.1"
fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 1000, () => {
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded)
dSwapStore.suggestedRoutesReady(d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded, "", "")
})()
Backpressure.debounce(this, 1500, () => {approveTxButton.clicked()})()
authenticateAndTransferSpy.wait()
@ -351,12 +351,26 @@ SplitView {
checked: false
}
ComboBox {
id: routerErrorComboBox
model: [
{name: "errNotEnoughTokenBalance", value: Constants.swap.errorCodes.errNotEnoughTokenBalance},
{name: "errNotEnoughNativeBalance", value: Constants.swap.errorCodes.errNotEnoughNativeBalance},
{name: "errPriceTimeout", value: Constants.swap.errorCodes.errPriceTimeout},
{name: "errNotEnoughLiquidity", value: Constants.swap.errorCodes.errNotEnoughLiquidity}
]
textRole: "name"
valueRole: "value"
currentIndex: 0
visible: advancedSignalsCheckBox.checked
}
Button {
text: "emit no routes found event"
text: "emit no routes found event with error"
onClicked: {
const txRoutes = d.dummySwapTransactionRoutes.txNoRoutes
txRoutes.uuid = d.uuid
dSwapStore.suggestedRoutesReady(txRoutes)
dSwapStore.suggestedRoutesReady(txRoutes, routerErrorComboBox.currentValue, "")
}
visible: advancedSignalsCheckBox.checked
}
@ -366,7 +380,7 @@ SplitView {
onClicked: {
const txRoutes = d.dummySwapTransactionRoutes.txHasRouteNoApproval
txRoutes.uuid = d.uuid
dSwapStore.suggestedRoutesReady(txRoutes)
dSwapStore.suggestedRoutesReady(txRoutes, "", "")
}
visible: advancedSignalsCheckBox.checked
}
@ -376,7 +390,7 @@ SplitView {
onClicked: {
const txRoutes = d.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
txRoutes.uuid = d.uuid
dSwapStore.suggestedRoutesReady(txRoutes)
dSwapStore.suggestedRoutesReady(txRoutes, "", "")
}
visible: advancedSignalsCheckBox.checked
}

View File

@ -27,7 +27,7 @@ Item {
readonly property var dummySwapTransactionRoutes: SwapTransactionRoutes {}
readonly property var swapStore: SwapStore {
signal suggestedRoutesReady(var txRoutes)
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId,var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success)
@ -596,8 +596,8 @@ Item {
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event that no routes were found
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes)
// emit event that no routes were found with unknown error
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes, "NO_ROUTES", "No routes found")
// verify loading state was removed and that error was displayed
verify(!root.swapAdaptor.validSwapProposalReceived)
@ -633,9 +633,155 @@ Item {
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event that no routes were found due to not enough token balance
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes, Constants.swap.errorCodes.errNotEnoughTokenBalance, "errNotEnoughTokenBalance")
// verify loading state was removed and that error was displayed
verify(!root.swapAdaptor.validSwapProposalReceived)
verify(!root.swapAdaptor.swapProposalLoading)
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Insufficient funds for swap"))
verify(!signButton.enabled)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
verify(!payPanel.mainInputLoading)
verify(!payPanel.bottomTextLoading)
verify(!receivePanel.mainInputLoading)
verify(!receivePanel.bottomTextLoading)
verify(!receivePanel.interactive)
compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey)
compare(receivePanel.value, 0)
compare(receivePanel.rawValue, "0")
// edit some params to retry swap
root.swapFormData.fromTokenAmount = "0.00012"
waitForRendering(receivePanel)
formValuesChanged.wait()
// wait for fetchSuggestedRoutes function to be called
fetchSuggestedRoutesCalled.wait()
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event that no routes were found due to not enough eth balance
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes, Constants.swap.errorCodes.errNotEnoughNativeBalance, "errNotEnoughNativeBalance")
// verify loading state was removed and that error was displayed
verify(!root.swapAdaptor.validSwapProposalReceived)
verify(!root.swapAdaptor.swapProposalLoading)
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Insufficient funds to pay gas fees"))
verify(!signButton.enabled)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
verify(!payPanel.mainInputLoading)
verify(!payPanel.bottomTextLoading)
verify(!receivePanel.mainInputLoading)
verify(!receivePanel.bottomTextLoading)
verify(!receivePanel.interactive)
compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey)
compare(receivePanel.value, 0)
compare(receivePanel.rawValue, "0")
// edit some params to retry swap
root.swapFormData.fromTokenAmount = "0.00013"
waitForRendering(receivePanel)
formValuesChanged.wait()
// wait for fetchSuggestedRoutes function to be called
fetchSuggestedRoutesCalled.wait()
// wait for fetchSuggestedRoutes function to be called
fetchSuggestedRoutesCalled.wait()
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event that no routes were found due to price timeout
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes, Constants.swap.errorCodes.errPriceTimeout, "errPriceTimeout")
// verify loading state was removed and that error was displayed
verify(!root.swapAdaptor.validSwapProposalReceived)
verify(!root.swapAdaptor.swapProposalLoading)
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Fetching the price took longer than expected. Please, try again later."))
verify(!signButton.enabled)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
verify(!payPanel.mainInputLoading)
verify(!payPanel.bottomTextLoading)
verify(!receivePanel.mainInputLoading)
verify(!receivePanel.bottomTextLoading)
verify(!receivePanel.interactive)
compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey)
compare(receivePanel.value, 0)
compare(receivePanel.rawValue, "0")
// edit some params to retry swap
root.swapFormData.fromTokenAmount = "0.00013"
waitForRendering(receivePanel)
formValuesChanged.wait()
// wait for fetchSuggestedRoutes function to be called
fetchSuggestedRoutesCalled.wait()
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event that no routes were found due to not enough liquidity
root.swapStore.suggestedRoutesReady(root.dummySwapTransactionRoutes.txNoRoutes, Constants.swap.errorCodes.errNotEnoughLiquidity, "errNotEnoughLiquidity")
// verify loading state was removed and that error was displayed
verify(!root.swapAdaptor.validSwapProposalReceived)
verify(!root.swapAdaptor.swapProposalLoading)
compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.toTokenAmount, "")
compare(root.swapAdaptor.swapOutputData.totalFees, 0)
compare(root.swapAdaptor.swapOutputData.approvalNeeded, false)
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Not enough liquidity. Lower token amount or try again later."))
verify(!signButton.enabled)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
verify(!payPanel.mainInputLoading)
verify(!payPanel.bottomTextLoading)
verify(!receivePanel.mainInputLoading)
verify(!receivePanel.bottomTextLoading)
verify(!receivePanel.interactive)
compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey)
compare(receivePanel.value, 0)
compare(receivePanel.rawValue, "0")
// edit some params to retry swap
root.swapFormData.fromTokenAmount = "0.00014"
waitForRendering(receivePanel)
formValuesChanged.wait()
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
// emit event with route that needs no approval
let txRoutes = root.dummySwapTransactionRoutes.txHasRouteNoApproval
root.swapStore.suggestedRoutesReady(txRoutes)
root.swapStore.suggestedRoutesReady(txRoutes, "", "")
// verify loading state removed and data is displayed as expected on the Modal
verify(root.swapAdaptor.validSwapProposalReceived)
@ -684,7 +830,7 @@ Item {
// emit event with route that needs no approval
let txRoutes2 = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
root.swapStore.suggestedRoutesReady(txRoutes2)
root.swapStore.suggestedRoutesReady(txRoutes2, "", "")
// verify loading state removed and data ius displayed as expected on the Modal
verify(root.swapAdaptor.validSwapProposalReceived)
@ -1330,7 +1476,7 @@ Item {
// emit event with route that needs no approval
let txRoutes = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
txRoutes.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txRoutes)
root.swapStore.suggestedRoutesReady(txRoutes, "", "")
// calculation needed for total fees
let gasTimeEstimate = txRoutes.gasTimeEstimate
@ -1426,7 +1572,7 @@ Item {
let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval
txHasRouteNoApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval)
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "")
verify(!root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful)
@ -1601,7 +1747,7 @@ Item {
// emit routes ready
let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval
txHasRouteNoApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval)
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "")
// check if fetch occurs automatically after 15 seconds
fetchSuggestedRoutesCalled.wait()

View File

@ -48,7 +48,7 @@ QtObject {
readonly property QtObject walletSectionSendInst: QtObject {
signal transactionSent(var chainId, var txHash, var uuid, var error)
signal suggestedRoutesReady(var txRoutes)
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
}
readonly property QtObject mainModuleInst: QtObject {
signal resolvedENS(var resolvedPubKey, var resolvedAddress, var uuid)

View File

@ -55,6 +55,8 @@ StatusDialog {
root.swapAdaptor.swapOutputData.resetPathInfoAndError()
debounceFetchSuggestedRoutes()
}
readonly property bool isError: root.swapAdaptor.errorMessage !== ""
}
Connections {
@ -227,6 +229,9 @@ StatusDialog {
root.swapInputParamsForm.fromTokenAmount = amount
}
}
onAmountEnteredGreaterThanBalanceChanged: {
root.swapAdaptor.amountEnteredGreaterThanBalance = payPanel.amountEnteredGreaterThanBalance
}
}
SwapInputPanel {
@ -301,18 +306,12 @@ StatusDialog {
ErrorTag {
objectName: "errorTag"
visible: root.swapAdaptor.swapOutputData.hasError || payPanel.amountEnteredGreaterThanBalance
visible: d.isError
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Style.current.smallPadding
text: {
if (root.swapAdaptor.swapOutputData.hasError) {
return qsTr("An error has occured, please try again")
} else if (payPanel.amountEnteredGreaterThanBalance) {
return qsTr("Insufficient funds for swap")
}
}
buttonText: qsTr("Buy crypto")
buttonVisible: !root.swapAdaptor.swapOutputData.hasError && payPanel.amountEnteredGreaterThanBalance
text: root.swapAdaptor.errorMessage
buttonText: root.swapAdaptor.isTokenBalanceInsufficient ? qsTr("Buy crypto") : qsTr("Buy ETH")
buttonVisible: visible && (root.swapAdaptor.isTokenBalanceInsufficient || root.swapAdaptor.isEthBalanceInsufficient)
onButtonClicked: Global.openBuyCryptoModalRequested()
}
}
@ -407,7 +406,7 @@ StatusDialog {
disabledColor: Theme.palette.directColor8
enabled: root.swapAdaptor.validSwapProposalReceived &&
editSlippagePanel.valid &&
!payPanel.amountEnteredGreaterThanBalance &&
!d.isError &&
!root.swapAdaptor.approvalPending
onClicked: {
if (root.swapAdaptor.validSwapProposalReceived) {

View File

@ -27,6 +27,9 @@ QObject {
property bool approvalPending: false
property bool approvalSuccessful: false
// the below property holds internal checks done by the SwapModal
property bool amountEnteredGreaterThanBalance: false
// To expose the selected from and to Token from the SwapModal
readonly property var fromToken: fromTokenEntry.item
readonly property var toToken: toTokenEntry.item
@ -89,6 +92,10 @@ QObject {
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
}
readonly property string errorMessage: d.errorMessage
readonly property bool isEthBalanceInsufficient: d.isEthBalanceInsufficient
readonly property bool isTokenBalanceInsufficient: d.isTokenBalanceInsufficient
signal suggestedRoutesReady()
QtObject {
@ -141,6 +148,45 @@ QObject {
formattedBalance: "0 %1".arg(root.fromToken.symbol)
}
}
// Properties to handle error states
readonly property bool isRouteEthBalanceInsufficient: root.validSwapProposalReceived && root.swapOutputData.errCode === Constants.swap.errorCodes.errNotEnoughNativeBalance
readonly property bool isRouteTokenBalanceInsufficient: root.validSwapProposalReceived && root.swapOutputData.errCode === Constants.swap.errorCodes.errNotEnoughTokenBalance
readonly property bool isTokenBalanceInsufficient: {
return (root.amountEnteredGreaterThanBalance || isRouteTokenBalanceInsufficient) &&
root.fromToken.symbol !== Constants.ethToken
}
readonly property bool isEthBalanceInsufficient: {
return (root.amountEnteredGreaterThanBalance && root.fromToken.symbol === Constants.ethToken) ||
isRouteEthBalanceInsufficient
}
readonly property bool isBalanceInsufficientForSwap: {
return (root.amountEnteredGreaterThanBalance && root.fromToken.symbol === Constants.ethToken) ||
(isTokenBalanceInsufficient && root.fromToken.symbol !== Constants.ethToken)
}
readonly property bool isBalanceInsufficientForFees: !isBalanceInsufficientForSwap && isEthBalanceInsufficient
property string errorMessage: {
if (isBalanceInsufficientForSwap) {
return qsTr("Insufficient funds for swap")
} else if (isBalanceInsufficientForFees) {
return qsTr("Insufficient funds to pay gas fees")
} else if (root.swapOutputData.hasError) {
switch (root.swapOutputData.errCode) {
case Constants.swap.errorCodes.errPriceTimeout:
return qsTr("Fetching the price took longer than expected. Please, try again later.")
case Constants.swap.errorCodes.errNotEnoughLiquidity:
return qsTr("Not enough liquidity. Lower token amount or try again later.")
}
return qsTr("Something went wrong. Change amount, token or try again later.")
}
return ""
}
}
ModelEntry {
@ -166,7 +212,7 @@ QObject {
Connections {
target: root.swapStore
function onSuggestedRoutesReady(txRoutes) {
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
if (txRoutes.uuid !== d.uuid) {
// Suggested routes for a different fetch, ignore
return
@ -175,8 +221,10 @@ QObject {
root.validSwapProposalReceived = false
root.swapProposalLoading = false
root.swapOutputData.rawPaths = txRoutes.rawPaths
root.swapOutputData.errCode = errCode
root.swapOutputData.errDescription = errDescription
// if valid route was found
if(txRoutes.suggestedRoutes.count === 1) {
if(txRoutes.suggestedRoutes.count > 0) {
root.validSwapProposalReceived = true
root.swapOutputData.toTokenAmount = AmountsArithmetic.div(AmountsArithmetic.fromString(txRoutes.amountToReceive), AmountsArithmetic.fromNumber(1, root.toToken.decimals)).toString()
@ -192,10 +240,10 @@ QObject {
root.swapOutputData.approvalContractAddress = !!bestPath ? bestPath.approvalContractAddress: ""
root.swapOutputData.estimatedTime = !!bestPath ? bestPath.estimatedTime: Constants.TransactionEstimatedTime.Unknown
root.swapOutputData.txProviderName = !!bestPath ? bestPath.bridgeName: ""
}
else {
} else {
root.swapOutputData.hasError = true
}
root.swapOutputData.hasError = root.swapOutputData.hasError || root.swapOutputData.errCode !== ""
root.suggestedRoutesReady()
}

View File

@ -12,6 +12,8 @@ QtObject {
// TODO: this should be string but backend gas_estimate_item.nim passes this as float
property real totalFees: 0
property bool hasError
property string errCode
property string errDescription
property var rawPaths: []
// need to check how this is done in new router v2, right now it is Enum type
property int estimatedTime
@ -23,6 +25,8 @@ QtObject {
function resetPathInfoAndError() {
root.hasError = false
root.errCode = ""
root.errDescription = ""
root.rawPaths = []
}

View File

@ -16,14 +16,14 @@ QtObject {
Remove these and use the new TransactorStore in SwapModalAdaptor when that happens. */
readonly property var walletSectionSendInst: walletSectionSend
signal suggestedRoutesReady(var txRoutes)
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success)
readonly property Connections walletSectionSendConnections: Connections {
target: root.walletSectionSendInst
function onSuggestedRoutesReady(txRoutes) {
root.suggestedRoutesReady(txRoutes)
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
root.suggestedRoutesReady(txRoutes, errCode, errDescription)
}
function onTransactionSent(chainId, txHash, uuid, error) {
root.transactionSent(chainId, txHash, uuid, error)

View File

@ -644,7 +644,7 @@ StatusDialog {
Connections {
target: popup.store.walletSectionSendInst
function onSuggestedRoutesReady(txRoutes) {
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
popup.bestRoutes = txRoutes.suggestedRoutes
let gasTimeEstimate = txRoutes.gasTimeEstimate
d.totalTimeEstimate = WalletUtils.getLabelForEstimatedTxTime(gasTimeEstimate.totalTime)

View File

@ -1335,6 +1335,13 @@ QtObject {
this list dynamically */
readonly property string paraswapIcon: "paraswap"
readonly property string paraswapUrl: "app.paraswap.io"
readonly property QtObject errorCodes: QtObject {
readonly property string errNotEnoughTokenBalance: "WR-016"
readonly property string errNotEnoughNativeBalance: "WR-017"
readonly property string errPriceTimeout: "WPP-037"
readonly property string errNotEnoughLiquidity: "WPP-038"
}
}
// Mirrors src/app_service/service/transaction/service.nim -> EstimatedTime

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit d07f9b5b162c078f71bf19a189e2e26c118a0db4
Subproject commit afc6e7bcb9e70e8ece8744dfab1b23ba5d087e6e