fix(liquidity): move quote details to confirmation

This commit is contained in:
Ricardo Guilherme Schmidt
2026-07-18 19:56:57 -03:00
parent 109d775084
commit 78fd86f56b
7 changed files with 245 additions and 132 deletions
@@ -4,6 +4,8 @@ import QtQuick
import QtQuick.Controls.Basic
import QtQuick.Layouts
import Logos.Controls
ColumnLayout {
id: root
@@ -75,8 +77,9 @@ ColumnLayout {
}
SummaryRow {
objectName: "confirmationDeposit"
Layout.fillWidth: true
label: qsTr("Deposit")
label: root.snapshot.depositLabel || qsTr("Deposit")
value: qsTr("%1 + %2")
.arg(root.snapshot.depositAText || "-")
.arg(root.snapshot.depositBText || "-")
@@ -84,11 +87,107 @@ ColumnLayout {
}
SummaryRow {
objectName: "confirmationInitialPrice"
Layout.fillWidth: true
visible: root.isMissingPool() && String(root.snapshot.initialPriceText || "").length > 0
label: qsTr("Initial price")
value: root.snapshot.initialPriceText || "-"
valueWrapAnywhere: true
}
SummaryRow {
objectName: "confirmationInversePrice"
Layout.fillWidth: true
visible: root.isMissingPool() && String(root.snapshot.inverseInitialPriceText || "").length > 0
label: qsTr("Inverse price")
value: root.snapshot.inverseInitialPriceText || "-"
valueWrapAnywhere: true
}
SummaryRow {
objectName: "confirmationDepositMultiplier"
Layout.fillWidth: true
visible: root.isMissingPool() && String(root.snapshot.depositMultiplierText || "").length > 0
label: qsTr("Deposit multiplier")
value: root.snapshot.depositMultiplierText || "-"
}
SummaryRow {
objectName: "confirmationDepositScale"
Layout.fillWidth: true
visible: root.isMissingPool() && String(root.snapshot.depositScaleText || "").length > 0
label: qsTr("Deposit scale")
value: root.snapshot.depositScaleText || "-"
}
SummaryRow {
objectName: "confirmationExpectedLp"
Layout.fillWidth: true
label: qsTr("Expected LP")
value: root.snapshot.expectedLpText || "-"
}
SummaryRow {
objectName: "confirmationLpGuard"
Layout.fillWidth: true
label: root.snapshot.lpGuardLabel || qsTr("Minimum LP")
value: root.snapshot.lpGuardText || "-"
}
SummaryRow {
objectName: "confirmationPool"
Layout.fillWidth: true
visible: String(root.snapshot.poolId || "").length > 0
label: qsTr("Pool")
value: String(root.snapshot.poolId || "")
valueWrapAnywhere: true
}
LogosButton {
id: accountPlanButton
objectName: "confirmationAccountPlan"
Layout.alignment: Qt.AlignLeft
visible: root.accountPlan().length > 0
text: qsTr("Account plan (%1)").arg(root.accountPlan().length)
property bool expanded: false
implicitWidth: 150
implicitHeight: 36
radius: 6
onClicked: expanded = !expanded
}
ColumnLayout {
Layout.fillWidth: true
spacing: 5
visible: accountPlanButton.visible && accountPlanButton.expanded
Repeater {
model: root.accountPlan()
SummaryRow {
required property var modelData
Layout.fillWidth: true
label: qsTr("%1. %2 · %3")
.arg(Number(modelData.order || 0) + 1)
.arg(String(modelData.role || "-"))
.arg(String(modelData.action || "-"))
value: modelData.accountId ? String(modelData.accountId)
: qsTr("Assigned by wallet")
valueWrapAnywhere: true
}
}
}
function isMissingPool() {
return root.snapshot.poolStatus === "missing_pool"
}
function accountPlan() {
return root.snapshot.accountPreview || []
}
function destinationRows() {
var rows = []
var options = root.snapshot.lpHoldingOptions || []
@@ -548,96 +548,6 @@ AmmActionCard {
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 9
visible: root.quotePayload.status === "ok"
&& root.quoteMatchesPair()
&& !root.quoteStale
Rectangle {
Layout.fillWidth: true
implicitHeight: 1
color: root.theme.colors.divider
}
LabelValueRow {
label: root.activePool ? qsTr("Expected spend") : qsTr("Opening deposit")
value: root.depositSummary()
}
LabelValueRow {
visible: root.missingPool
label: qsTr("Initial price")
value: root.initialPriceText(false)
}
LabelValueRow {
visible: root.missingPool
label: qsTr("Inverse price")
value: root.initialPriceText(true)
}
LabelValueRow {
visible: root.missingPool
label: qsTr("Deposit multiplier")
value: root.depositMultiplierValue()
}
LabelValueRow {
visible: root.missingPool
label: qsTr("Deposit scale")
value: root.depositBasisPointsText()
}
LabelValueRow {
label: qsTr("Expected LP")
value: root.rawLpText(root.quotePayload.expectedLpRaw)
}
LabelValueRow {
label: root.activePool ? qsTr("Minimum LP") : qsTr("Locked LP")
value: root.rawLpText(root.activePool
? root.quotePayload.minimumLpRaw
: root.quotePayload.lockedLpRaw)
}
LabelValueRow {
label: qsTr("Pool")
value: String(root.quotePayload.poolId || "")
valueWrapAnywhere: true
}
LogosButton {
id: accountPlanButton
text: qsTr("Account plan (%1)").arg(root.accountPreview().length)
enabled: root.accountPreview().length > 0
property bool checked: false
implicitWidth: 150
implicitHeight: 36
radius: 6
Layout.alignment: Qt.AlignLeft
onClicked: checked = !checked
}
ColumnLayout {
Layout.fillWidth: true
spacing: 5
visible: accountPlanButton.checked
Repeater {
model: root.accountPreview()
LabelValueRow {
required property var modelData
label: qsTr("%1. %2 · %3").arg(modelData.order + 1).arg(modelData.role).arg(modelData.action)
value: modelData.accountId ? modelData.accountId : qsTr("Assigned by wallet")
valueWrapAnywhere: true
}
}
}
}
Rectangle {
Layout.fillWidth: true
implicitHeight: warningTextItem.implicitHeight + 20
@@ -683,32 +593,6 @@ AmmActionCard {
}
}
component LabelValueRow: RowLayout {
required property string label
required property string value
property bool valueWrapAnywhere: false
Layout.fillWidth: true
spacing: 12
Text {
text: parent.label
color: root.theme.colors.textSecondary
font.pixelSize: 12
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Text {
text: parent.value
color: root.theme.colors.textPrimary
font.pixelSize: 12
font.weight: Font.Medium
horizontalAlignment: Text.AlignRight
wrapMode: parent.valueWrapAnywhere ? Text.WrapAnywhere : Text.Wrap
Layout.maximumWidth: root.compact ? 190 : 280
}
}
component PriceRatioAdjustment: RowLayout {
id: ratioAdjustment
@@ -1531,20 +1415,21 @@ AmmActionCard {
}
function quoteAmount(canonicalAField, canonicalBField, side) {
return root.quoteAmountFromQuote(root.quotePayload,
canonicalAField,
canonicalBField,
side)
}
function quoteAmountFromQuote(quote, canonicalAField, canonicalBField, side) {
var token = side === "A" ? root.tokenA : root.tokenB
var decimals = side === "A" ? root.decimalsA : root.decimalsB
var raw = root.displayRaw(canonicalAField, canonicalBField, side)
var raw = root.displayQuoteRaw(quote, canonicalAField, canonicalBField, side)
return raw.length > 0
? qsTr("%1 %2").arg(AmountMath.formatRaw(raw, decimals)).arg(root.shortTokenName(token))
: "—"
}
function depositSummary() {
var amountA = root.quoteAmount("actualAmountARaw", "actualAmountBRaw", "A")
var amountB = root.quoteAmount("actualAmountARaw", "actualAmountBRaw", "B")
return amountA + " + " + amountB
}
function initialPriceText(inverse) {
var price = inverse ? root.inverseInitialPrice : root.initialPrice
if (price.length === 0)
@@ -1603,19 +1488,59 @@ AmmActionCard {
return warnings.length > 0 ? root.issueText(warnings[0].code) : ""
}
function confirmationDetails(quote) {
var sourceQuote = quote || ({})
var status = String(sourceQuote.poolStatus || root.poolStatus || "")
var isActivePool = status === "active_pool"
var accountPlan = sourceQuote.accountPreview || []
return {
"poolStatus": status,
"depositLabel": isActivePool ? qsTr("Expected spend") : qsTr("Opening deposit"),
"depositAText": root.quoteAmountFromQuote(sourceQuote,
"actualAmountARaw",
"actualAmountBRaw",
"A"),
"depositBText": root.quoteAmountFromQuote(sourceQuote,
"actualAmountARaw",
"actualAmountBRaw",
"B"),
"initialPriceText": isActivePool ? "" : root.initialPriceText(false),
"inverseInitialPriceText": isActivePool ? "" : root.initialPriceText(true),
"depositMultiplierText": isActivePool ? "" : root.depositMultiplierValue(),
"depositScaleText": isActivePool ? "" : root.depositBasisPointsText(),
"expectedLpText": root.rawLpText(sourceQuote.expectedLpRaw),
"lpGuardLabel": isActivePool ? qsTr("Minimum LP") : qsTr("Locked LP"),
"lpGuardText": root.rawLpText(isActivePool
? sourceQuote.minimumLpRaw
: sourceQuote.lockedLpRaw),
"poolId": String(sourceQuote.poolId || ""),
"accountPreview": accountPlan
}
}
function refreshConfirmationSnapshot(snapshot) {
var refreshed = {}
for (var field in snapshot)
refreshed[field] = snapshot[field]
var sourceQuote = refreshed.quote || root.quotePayload
refreshed.quote = sourceQuote
var details = root.confirmationDetails(sourceQuote)
for (var detail in details)
refreshed[detail] = details[detail]
return refreshed
}
function submissionSnapshot() {
var built = root.buildQuoteRequest()
var poolProbe = root.poolProbeRequest(built.request)
poolProbe.poolId = String(root.quotePayload.poolId || "")
return {
return root.refreshConfirmationSnapshot({
"request": built.request,
"poolProbeRequest": poolProbe,
"quote": root.quotePayload,
"quoteHash": String(root.quotePayload.quoteHash || ""),
"pairText": qsTr("%1 / %2").arg(root.shortTokenName(root.tokenA)).arg(root.shortTokenName(root.tokenB)),
"feeText": root.feeLabel(root.selectedFeeBps),
"depositAText": root.quoteAmount("actualAmountARaw", "actualAmountBRaw", "A"),
"depositBText": root.quoteAmount("actualAmountARaw", "actualAmountBRaw", "B"),
"expectedLpText": root.rawLpText(root.quotePayload.expectedLpRaw),
"instruction": String(root.quotePayload.instruction || ""),
"lpHoldingOptions": root.quotePayload.lpHoldingOptions || [],
"selectedLpHoldingId": String(root.quotePayload.selectedLpHoldingId || ""),
@@ -1623,7 +1548,7 @@ AmmActionCard {
&& root.quotePayload.lpDestinationRequired !== true,
"lpDestinationRequired": root.quotePayload.lpDestinationRequired === true,
"quoteReady": root.quotePayload.canSubmit === true
}
})
}
function onlyLpDestinationBlocks() {
+1 -1
View File
@@ -253,7 +253,7 @@ Item {
}
function onConfirmationQuoteReady(snapshot) {
confirmationDialog.updateSnapshot(snapshot)
confirmationDialog.updateSnapshot(form.refreshConfirmationSnapshot(snapshot))
}
function onSubmitSucceeded() {
+1
View File
@@ -291,6 +291,7 @@ QtObject {
var refreshed = {}
for (var field in snapshot)
refreshed[field] = snapshot[field]
refreshed.quote = quote
refreshed.quoteHash = String(quote.quoteHash || "")
refreshed.expectedLpText = String(quote.expectedLpRaw || "") + " raw LP"
refreshed.instruction = String(quote.instruction || "")
@@ -79,4 +79,62 @@ TestCase {
verify(picker)
compare(picker.background.color, summary.theme.colors.panelBg)
}
function test_confirmationShowsQuoteDetails() {
var summary = createTemporaryObject(summaryComponent, testCase, {
"snapshot": {
"instruction": "NewDefinition",
"poolStatus": "missing_pool",
"depositLabel": "Opening deposit",
"depositAText": "2 Low",
"depositBText": "3 High",
"initialPriceText": "1 Low = 1.5 High",
"inverseInitialPriceText": "1 High = 0.66 Low",
"depositMultiplierText": "2x minimum",
"depositScaleText": "20000 basis points",
"expectedLpText": "10 raw LP",
"lpGuardLabel": "Locked LP",
"lpGuardText": "2 raw LP",
"poolId": "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE",
"accountPreview": [{
"order": 0,
"role": "LP holding",
"action": "create",
"accountId": "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE"
}]
}
})
verify(summary)
var deposit = findChild(summary, "confirmationDeposit")
var initialPrice = findChild(summary, "confirmationInitialPrice")
var inversePrice = findChild(summary, "confirmationInversePrice")
var multiplier = findChild(summary, "confirmationDepositMultiplier")
var scale = findChild(summary, "confirmationDepositScale")
var expectedLp = findChild(summary, "confirmationExpectedLp")
var lpGuard = findChild(summary, "confirmationLpGuard")
var pool = findChild(summary, "confirmationPool")
var accountPlan = findChild(summary, "confirmationAccountPlan")
verify(deposit)
verify(initialPrice)
verify(inversePrice)
verify(multiplier)
verify(scale)
verify(expectedLp)
verify(lpGuard)
verify(pool)
verify(accountPlan)
compare(deposit.label, "Opening deposit")
compare(deposit.value, "2 Low + 3 High")
compare(initialPrice.value, "1 Low = 1.5 High")
compare(inversePrice.value, "1 High = 0.66 Low")
compare(multiplier.value, "2x minimum")
compare(scale.value, "20000 basis points")
compare(expectedLp.value, "10 raw LP")
compare(lpGuard.label, "Locked LP")
compare(lpGuard.value, "2 raw LP")
compare(pool.value, "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE")
compare(accountPlan.text, "Account plan (1)")
}
}
+18 -1
View File
@@ -289,7 +289,14 @@ TestCase {
"request": ({ "schema": "new-position.v2" }),
"quoteHash": "sha256:stale",
"expectedLpText": "10 raw LP",
"instruction": "AddLiquidity"
"instruction": "AddLiquidity",
"poolId": "11111111111111111111111111111111",
"accountPreview": [{
"order": 0,
"role": "LP holding",
"action": "create",
"accountId": "11111111111111111111111111111111"
}]
})
tryCompare(dialog, "opened", true)
@@ -307,6 +314,13 @@ TestCase {
"quoteHash": "sha256:fresh",
"expectedLpRaw": "20",
"instruction": "AddLiquidity",
"poolId": "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE",
"accountPreview": [{
"order": 0,
"role": "LP holding",
"action": "reuse",
"accountId": "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE"
}],
"lpHoldingOptions": [],
"selectedLpHoldingId": "",
"requiresFreshLp": true,
@@ -319,6 +333,9 @@ TestCase {
tryCompare(dialog, "opened", true)
compare(dialog.snapshot.quoteHash, "sha256:fresh")
compare(dialog.snapshot.expectedLpText, "20 raw LP")
compare(dialog.snapshot.poolId, "1thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE")
compare(dialog.snapshot.accountPreview.length, 1)
compare(dialog.snapshot.accountPreview[0].action, "reuse")
compare(dialog.snapshot.quoteReady, true)
compare(page.flow.flowErrorCode, "")
}
+14 -1
View File
@@ -657,13 +657,26 @@ TestCase {
"quoteHash": "sha256:expected",
"actualAmountARaw": "2000000",
"actualAmountBRaw": "3",
"expectedLpRaw": "10"
"expectedLpRaw": "10",
"lockedLpRaw": "2",
"accountPreview": [{
"order": 0,
"role": "LP holding",
"action": "create",
"accountId": submittedTransactionId
}]
})
wait(0)
var snapshot = form.submissionSnapshot()
compare(snapshot.poolProbeRequest.poolId, submittedTransactionId)
verify(snapshot.request.poolId === undefined)
compare(snapshot.depositLabel, "Opening deposit")
compare(snapshot.lpGuardLabel, "Locked LP")
compare(snapshot.lpGuardText, "2 raw LP")
compare(snapshot.poolId, submittedTransactionId)
compare(snapshot.accountPreview.length, 1)
compare(snapshot.accountPreview[0].accountId, submittedTransactionId)
}
function test_staleQuoteErrorsDoNotMarkCurrentDraft() {