Skip to content

Commit

Permalink
feat(@desktop/wallet): Swap changes needed for -1.33
Browse files Browse the repository at this point in the history
1. Max button functionality
2. Hardcode swap modal to swap USDT <-> WETH
3. Fixing some issues found
4. Not limiting number entered by user

fixes #17198, #17200
  • Loading branch information
Khushboo-dev-cpp committed Feb 6, 2025
1 parent d3e7654 commit 8d5dbaf
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 81 deletions.
3 changes: 2 additions & 1 deletion storybook/pages/SwapInputPanelPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ SplitView {
fromTokenAmount: ctrlFromTokenAmount.text
toTokenKey: ctrlToTokenKey.text
toTokenAmount: ctrlToTokenAmount.text
defaultToTokenKey: "STT"
defaultFromTokenKey: Constants.swap.usdtTokenKey
defaultToTokenKey: Constants.swap.wethTokenKey
}

readonly property SwapModalAdaptor adaptor: SwapModalAdaptor {
Expand Down
24 changes: 5 additions & 19 deletions storybook/pages/SwapModalPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ SplitView {

function resetValues() {
accountComboBox.currentIndex = 0
fromTokenComboBox.currentIndex = 0
swapInput.text = ""
fetchSuggestedRoutesSpy.clear()
authenticateAndTransferSpy.clear()
Expand Down Expand Up @@ -145,7 +144,8 @@ SplitView {
}
}
swapFormData: SwapInputParamsForm {
defaultToTokenKey: Constants.swap.testStatusTokenKey
defaultFromTokenKey: Constants.swap.usdtTokenKey
defaultToTokenKey: Constants.swap.wethTokenKey
onSelectedAccountAddressChanged: {
if (selectedAccountAddress !== accountComboBox.currentValue)
accountComboBox.currentIndex = accountComboBox.indexOfValue(selectedAccountAddress)
Expand Down Expand Up @@ -190,21 +190,6 @@ SplitView {
property: "fromTokenAmount"
value: swapInput.text
}
Binding {
target: swapInputParamsForm
property: "selectedNetworkChainId"
value: networksComboBox.currentValue ?? -1
}
Binding {
target: swapInputParamsForm
property: "selectedAccountAddress"
value: accountComboBox.currentValue ?? ""
}
Binding {
target: swapInputParamsForm
property: "fromTokenAmount"
value: swapInput.text
}

Connections {
target: approveTxButton
Expand Down Expand Up @@ -263,6 +248,7 @@ SplitView {
textRole: "name"
valueRole: "key"
model: d.tokenBySymbolModel
currentIndex: d.tokenBySymbolModel.count - 1
}

StatusInput {
Expand All @@ -275,12 +261,12 @@ SplitView {
StatusBaseText {
text: "To Token"
}
ComboBox {
ComboBox {
id: toTokenComboBox
textRole: "name"
valueRole: "key"
model: d.tokenBySymbolModel
currentIndex: 1
currentIndex: d.tokenBySymbolModel.count - 2
}

Button {
Expand Down
8 changes: 4 additions & 4 deletions storybook/qmlTests/tests/tst_AmountToSend.qml
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ Item {
// exceeding maxium allowed integral part
amountToSend.setValue("1234567890000")
compare(textField.text, "1234567890000")
compare(amountToSend.amount, "0")
compare(amountToSend.valid, false)
compare(amountToSend.amount, "1234567890000000")
verify(amountToSend.valid)
}

function test_settingValueInFiatMode() {
Expand Down Expand Up @@ -133,8 +133,8 @@ Item {
// exceeding maxium allowed integral part
amountToSend.setValue("1234567890000")
compare(textField.text, "1234567890000.00")
compare(amountToSend.amount, "0")
compare(amountToSend.valid, false)
compare(amountToSend.amount, "2469135780000000")
compare(amountToSend.valid, true)
}

function test_switchingMode() {
Expand Down
11 changes: 3 additions & 8 deletions storybook/qmlTests/tests/tst_SwapInputPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,7 @@ Item {
verify(!maxTagButton.text.endsWith("ETH"))
}

// FIXME: This should be enabled after #15709 is resolved
function test_clickingMaxButton() {
skip("maxTabButton is disabled")
controlUnderTest = createTemporaryObject(componentUnderTest, root, {tokenKey: "ETH"})
verify(!!controlUnderTest)
waitForRendering(controlUnderTest)
Expand Down Expand Up @@ -357,8 +355,7 @@ Item {

waitForRendering(controlUnderTest)
verify(maxTagButton.visible)
// FIXME: maxTagButton should be enabled after #15709 is resolved
verify(!maxTagButton.enabled)
verify(maxTagButton.enabled)
verify(!maxTagButton.text.endsWith(modelItemToTest.symbol))
tryCompare(maxTagButton, "type", modelItemToTest.currentBalance === 0 ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal)

Expand All @@ -370,10 +367,8 @@ Item {
tryCompare(amountToSendInput, "text", modelItemToTest.currentBalance === 0 ? "" : maxTagButton.maxSafeValue.toString())
tryCompare(controlUnderTest, "value", maxTagButton.maxSafeValue)
verify(modelItemToTest.currentBalance === 0 ? !controlUnderTest.valueValid : controlUnderTest.valueValid)
const marketPrice = amountToSendInput.price
compare(bottomItemText.text, d.adaptor.formatCurrencyAmount(
maxTagButton.maxSafeValue * marketPrice,
d.adaptor.currencyStore.currentCurrency))
compare(bottomItemText.text, d.adaptor.currencyStore.formatCurrencyAmount(
maxTagButton.maxSafeValue * amountToSendInput.price, d.adaptor.currencyStore.currentCurrency))
}
amountToSendInput.clear()
}
Expand Down
57 changes: 41 additions & 16 deletions storybook/qmlTests/tests/tst_SwapModal.qml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ Item {
}

property SwapInputParamsForm swapFormData: SwapInputParamsForm {
defaultToTokenKey: Constants.swap.testStatusTokenKey
defaultFromTokenKey: Constants.swap.usdtTokenKey
defaultToTokenKey: Constants.swap.wethTokenKey
}

Component {
Expand Down Expand Up @@ -901,10 +902,10 @@ Item {
verify(amountToSendInput.cursorVisible)
compare(amountToSendInput.placeholderText, LocaleUtils.numberToLocaleString(0))
compare(bottomItemText.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(0, root.swapAdaptor.currencyStore.currentCurrency))
compare(holdingSelector.currentTokensKey, "")
compare(tokenSelectorContentItemText.text, qsTr("Select asset"))
verify(!maxTagButton.visible)
compare(payPanel.selectedHoldingId, "")
compare(holdingSelector.currentTokensKey, Constants.swap.usdtTokenKey)
compare(tokenSelectorContentItemText.text, Constants.swap.usdtTokenKey)
verify(maxTagButton.visible)
compare(payPanel.selectedHoldingId, Constants.swap.usdtTokenKey)
compare(payPanel.value, 0)
compare(payPanel.rawValue, "0")
verify(!payPanel.valueValid)
Expand Down Expand Up @@ -981,8 +982,8 @@ Item {
// try setting value before popup is launched and check values
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey =
root.swapFormData.fromTokenAmount = invalidValue
root.swapFormData.fromTokensKey = invalidValue
root.swapFormData.fromTokenAmount = invalidValue

// Launch popup
launchAndVerfyModal()
Expand All @@ -997,8 +998,6 @@ Item {
verify(!!holdingSelector)
const maxTagButton = findChild(payPanel, "maxTagButton")
verify(!!maxTagButton)
const tokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText")
verify(!!tokenSelectorContentItemText)

waitForRendering(payPanel)

Expand All @@ -1008,6 +1007,8 @@ Item {
verify(amountToSendInput.cursorVisible)
compare(bottomItemText.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(0, root.swapAdaptor.currencyStore.currentCurrency))
compare(holdingSelector.currentTokensKey, "")
const tokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText")
verify(!!tokenSelectorContentItemText)
compare(tokenSelectorContentItemText.text, "Select asset")
verify(!maxTagButton.visible)
compare(payPanel.selectedHoldingId, "")
Expand Down Expand Up @@ -1102,10 +1103,10 @@ Item {
verify(!amountToSendInput.cursorVisible)
compare(amountToSendInput.placeholderText, LocaleUtils.numberToLocaleString(0))
compare(bottomItemText.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(0, root.swapAdaptor.currencyStore.currentCurrency))
compare(holdingSelector.currentTokensKey, "STT")
compare(tokenSelectorContentItemText.text, "STT")
compare(holdingSelector.currentTokensKey, Constants.swap.wethTokenKey)
compare(tokenSelectorContentItemText.text, Constants.swap.wethTokenKey)
verify(!maxTagButton.visible)
compare(receivePanel.selectedHoldingId, "STT")
compare(receivePanel.selectedHoldingId, Constants.swap.wethTokenKey)
compare(receivePanel.value, 0)
compare(receivePanel.rawValue, "0")
verify(!receivePanel.valueValid)
Expand Down Expand Up @@ -1208,7 +1209,7 @@ Item {
// check states for the pay input selector
verify(maxTagButton.visible)
// FIXME: maxTagButton should be enabled after #15709 is resolved
verify(!maxTagButton.enabled);
verify(maxTagButton.enabled);
let maxPossibleValue = WalletUtils.calculateMaxSafeSendAmount(expectedToken.currentBalance, expectedToken.symbol)
let truncmaxPossibleValue = Math.trunc(maxPossibleValue*100)/100
compare(maxTagButton.text, qsTr("Max. %1").arg(truncmaxPossibleValue === 0 ? Qt.locale().zeroDigit
Expand All @@ -1230,6 +1231,29 @@ Item {
tryCompare(amountToSendInput, "text", maxPossibleValue === 0 ? "" : maxPossibleValue.toLocaleString(Qt.locale(), 'f', -128))
tryCompare(bottomItemText, "text", root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue * expectedToken.marketDetails.currencyPrice.amount, root.swapAdaptor.currencyStore.currentCurrency))
}

// After a valid route is returned, the max value should be calculated based on the fees returned
// emit event with route that needs no approval
let txRoutes = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
txRoutes.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txRoutes, "", "")

let totalMaxFees = (Math.ceil(txRoutes.gasFees.baseFee) + Math.ceil(txRoutes.gasFees.maxPriorityFeePerGas)) * txRoutes.gasAmount
let amountToReserve = SQUtils.AmountsArithmetic.times(
SQUtils.AmountsArithmetic.div(
SQUtils.AmountsArithmetic.fromString(totalMaxFees),
SQUtils.AmountsArithmetic.fromNumber(1, 9)),
SQUtils.AmountsArithmetic.fromExponent(18)).toString()
compare(root.swapAdaptor.swapOutputData.maxFeesToReserveRaw, amountToReserve)

maxPossibleValue = WalletUtils.calculateMaxSafeSendAmount(expectedToken.currentBalance, expectedToken.symbol, reserveForFees)
truncmaxPossibleValue = Math.trunc(maxPossibleValue*100)/100
compare(maxTagButton.text,
qsTr("Max. %1").arg(
truncmaxPossibleValue === 0 ? Qt.locale().zeroDigit
: root.swapAdaptor.currencyStore.formatCurrencyAmount(truncmaxPossibleValue, expectedToken.symbol, {noSymbol: true, roundingMode: LocaleUtils.RoundingMode.Down})))


closeAndVerfyModal()
}

Expand Down Expand Up @@ -1326,7 +1350,7 @@ Item {
for (let i=0; i< walletAccounts.count; i++) {
root.swapFormData.selectedAccountAddress = walletAccounts.get(i).address

waitForItemPolished(controlUnderTest.contentItem)
waitForRendering(payPanel)

const payTokenModel = findChild(payPanel, "TokenSelectorViewAdaptor_outputAssetsModel")
verify(!!payTokenModel)
Expand All @@ -1336,7 +1360,8 @@ Item {
// check states for the pay input selector
tryCompare(maxTagButton, "visible", true)
let maxPossibleValue = WalletUtils.calculateMaxSafeSendAmount(expectedToken.currentBalance, expectedToken.symbol)
tryCompare(maxTagButton, "text", qsTr("Max. %1").arg(maxPossibleValue === 0 ? Qt.locale().zeroDigit : root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue, expectedToken.symbol, {noSymbol: true, roundingMode: LocaleUtils.RoundingMode.Down})))
tryCompare(maxTagButton, "text", qsTr("Max. %1").arg(maxPossibleValue === 0 ? Qt.locale().zeroDigit :
root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue, expectedToken.symbol, {noSymbol: true, roundingMode: LocaleUtils.RoundingMode.Down})))
compare(payPanel.selectedHoldingId, expectedToken.symbol)
tryCompare(payPanel, "valueValid", !!valueToExchangeString && valueToExchange <= maxPossibleValue)

Expand Down Expand Up @@ -1841,10 +1866,10 @@ Item {
}

function test_deleteing_input_characters(data) {
root.swapFormData.fromTokenAmount = data.input
root.swapFormData.selectedAccountAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
root.swapFormData.selectedNetworkChainId = 11155111
root.swapFormData.fromTokensKey = "ETH"
root.swapFormData.fromTokenAmount = data.input

const amountToSendInput = findChild(controlUnderTest, "amountToSendInput")
verify(!!amountToSendInput)
Expand Down
66 changes: 65 additions & 1 deletion storybook/src/Models/TokensBySymbolModel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,71 @@ ListModel {
},
detailsLoading: false,
marketDetailsLoading: false
}
},
{
key: "WETH",
name: "Wrapped Ether",
symbol: "WETH",
sources: ";" + nativeSource + ";",
addressPerChain: [
{ chainId: 1, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 5, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 10, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 11155420, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 42161, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 421614, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
{ chainId: 11155111, address: "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374"},
],
decimals: 18,
type: 1,
communityId: "",
description: "Wrapped Ethereum is a decentralized, open-source blockchain platform",
websiteUrl: "https://www.wrapped-ethereum.org/",
marketDetails: {
marketCap: ({amount: 250980621528.3937, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
highDay: ({amount: 2090.658790484828, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
lowDay: ({amount: 2059.795033958552, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
changePctHour: 0.3655439934313061,
changePctDay: 1.19243897022671,
changePct24hour: 0.05209315257442912,
change24hour: 0.9121310349524345,
currencyPrice: ({amount: 2098.790000016801, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false})
},
detailsLoading: false,
marketDetailsLoading: false,
},
{
key: "USDT",
name: "Tether USD",
symbol: "USDT",
sources: ";" + nativeSource + ";",
addressPerChain: [
{ chainId: 1, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 5, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 10, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 11155420, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 42161, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 421614, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
{ chainId: 11155111, address: "0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"},
],
decimals: 6,
type: 1,
communityId: "",
description: "Tether USD is a decentralized, open-source blockchain platform",
websiteUrl: "https://www.tether-usdt.org/",
marketDetails: {
marketCap: ({amount: 250980621528.3937, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
highDay: ({amount: 2090.658790484828, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
lowDay: ({amount: 2059.795033958552, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false}),
changePctHour: 0.3655439934313061,
changePctDay: 1.19243897022671,
changePct24hour: 0.05209315257442912,
change24hour: 0.9121310349524345,
currencyPrice: ({amount: 2098.790000016801, symbol: "USD", displayDecimals: 2, stripTrailingZeroes: false})
},
detailsLoading: false,
marketDetailsLoading: false,
},
]

Component.onCompleted: append(data)
Expand Down
7 changes: 4 additions & 3 deletions ui/app/AppLayouts/Wallet/WalletLayout.qml
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ Item {
d.swapFormData.selectedAccountAddress = d.getSelectedOrFirstNonWatchedAddress()
d.swapFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
d.swapFormData.fromTokensKey = tokensKey
d.swapFormData.defaultToTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
d.swapFormData.defaultFromTokenKey = Constants.swap.usdtTokenKey
d.swapFormData.defaultToTokenKey = Constants.swap.wethTokenKey
Global.openSwapModalRequested(d.swapFormData, (popup) => {
popup.Component.destruction.connect(() => {
d.swapFormData.resetFormData()
Expand Down Expand Up @@ -386,13 +387,13 @@ Item {
walletStore.currentViewedHoldingType)
}
onLaunchSwapModal: {
d.swapFormData.fromTokensKey = ""
d.swapFormData.defaultFromTokenKey = Constants.swap.usdtTokenKey
d.swapFormData.defaultToTokenKey = Constants.swap.wethTokenKey
d.swapFormData.selectedAccountAddress = d.getSelectedOrFirstNonWatchedAddress()
d.swapFormData.selectedNetworkChainId = StatusQUtils.ModelUtils.getByKey(RootStore.filteredFlatModel, "layer", 1, "chainId")
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
d.swapFormData.fromTokensKey = walletStore.currentViewedHoldingTokensKey
}
d.swapFormData.defaultToTokenKey = RootStore.areTestNetworksEnabled ? Constants.swap.testStatusTokenKey : Constants.swap.mainnetStatusTokenKey
Global.openSwapModalRequested(d.swapFormData, (popup) => {
popup.Component.destruction.connect(() => {
d.swapFormData.resetFormData()
Expand Down
Loading

0 comments on commit 8d5dbaf

Please sign in to comment.