mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-05-18 15:09:51 +00:00
chore(amm-ui): swap form activates exact input or output based on the fields updated
closes #56
This commit is contained in:
parent
3df3c3d7c4
commit
476087a36b
@ -11,7 +11,9 @@ Rectangle {
|
||||
property var tokens: []
|
||||
property var sellToken: null
|
||||
property var buyToken: null
|
||||
property string sellAmount: ""
|
||||
property string sellInput: ""
|
||||
property string buyInput: ""
|
||||
property string editingSide: "sell"
|
||||
property real slippageTolerancePercent: 0.5
|
||||
|
||||
DummySwapState {
|
||||
@ -28,27 +30,44 @@ Rectangle {
|
||||
}
|
||||
|
||||
function resetAmounts() {
|
||||
root.sellAmount = ""
|
||||
root.sellInput = ""
|
||||
root.buyInput = ""
|
||||
root.editingSide = "sell"
|
||||
}
|
||||
|
||||
readonly property real sellReserve: sellToken ? (sellToken.reserve || 0) : 0
|
||||
readonly property real buyReserve: buyToken ? (buyToken.reserve || 0) : 0
|
||||
|
||||
readonly property real parsedSellAmount: {
|
||||
var amt = parseFloat(sellAmount)
|
||||
readonly property real parsedSellInput: {
|
||||
var amt = parseFloat(sellInput)
|
||||
return isNaN(amt) || amt < 0 ? 0 : amt
|
||||
}
|
||||
|
||||
readonly property real parsedBuyAmount: swapState.amountOutFor(parsedSellAmount, sellReserve, buyReserve)
|
||||
readonly property real parsedBuyInput: {
|
||||
var amt = parseFloat(buyInput)
|
||||
return isNaN(amt) || amt < 0 ? 0 : amt
|
||||
}
|
||||
|
||||
readonly property real parsedSellAmount: editingSide === "sell"
|
||||
? parsedSellInput
|
||||
: swapState.amountInFor(parsedBuyInput, sellReserve, buyReserve)
|
||||
|
||||
readonly property real parsedBuyAmount: editingSide === "buy"
|
||||
? parsedBuyInput
|
||||
: swapState.amountOutFor(parsedSellInput, sellReserve, buyReserve)
|
||||
|
||||
readonly property real feeAmount: swapState.feeAmount(parsedSellAmount)
|
||||
readonly property real minReceivedAmount: swapState.minReceived(parsedBuyAmount, slippageTolerancePercent)
|
||||
readonly property real priceImpactPercent: swapState.priceImpactPercent(parsedSellAmount, parsedBuyAmount, sellReserve, buyReserve)
|
||||
|
||||
readonly property bool hasAmount: parsedSellAmount > 0
|
||||
readonly property string swapMode: editingSide === "buy" ? "swap-exact-output" : "swap-exact-input"
|
||||
readonly property string swapModeText: editingSide === "buy" ? qsTr("Exact output") : qsTr("Exact input")
|
||||
|
||||
readonly property bool hasAmount: editingSide === "sell" ? parsedSellInput > 0 : parsedBuyInput > 0
|
||||
readonly property bool tokensSelected: sellToken !== null && buyToken !== null
|
||||
readonly property bool insufficientBalance: hasAmount && sellToken !== null && parsedSellAmount > (sellToken.balance || 0)
|
||||
readonly property bool insufficientLiquidity: hasAmount && buyToken !== null && parsedBuyAmount > (buyToken.reserve || 0)
|
||||
readonly property bool canSubmit: tokensSelected && hasAmount && !insufficientBalance && !insufficientLiquidity
|
||||
readonly property bool canSubmit: tokensSelected && hasAmount && parsedSellAmount > 0 && parsedBuyAmount > 0 && !insufficientBalance && !insufficientLiquidity
|
||||
|
||||
readonly property string submitButtonText: {
|
||||
if (!hasAmount || !tokensSelected) return qsTr("Enter an amount")
|
||||
@ -63,21 +82,22 @@ Rectangle {
|
||||
return val.toFixed(8)
|
||||
}
|
||||
|
||||
readonly property string buyAmount: {
|
||||
if (!sellToken || !buyToken || sellAmount === "") return ""
|
||||
if (parsedSellAmount <= 0) return ""
|
||||
return formatAmountValue(parsedBuyAmount)
|
||||
}
|
||||
readonly property string sellDisplay: editingSide === "sell"
|
||||
? sellInput
|
||||
: (parsedSellAmount > 0 ? formatAmountValue(parsedSellAmount) : "")
|
||||
|
||||
readonly property string buyDisplay: editingSide === "buy"
|
||||
? buyInput
|
||||
: (parsedBuyAmount > 0 ? formatAmountValue(parsedBuyAmount) : "")
|
||||
|
||||
readonly property string sellUsd: {
|
||||
if (!sellToken || sellAmount === "") return ""
|
||||
if (parsedSellAmount <= 0) return ""
|
||||
if (!sellToken || parsedSellAmount <= 0) return ""
|
||||
var val = parsedSellAmount * sellToken.usdPrice
|
||||
return "~$" + val.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
|
||||
}
|
||||
|
||||
readonly property string buyUsd: {
|
||||
if (!buyToken || buyAmount === "") return ""
|
||||
if (!buyToken || parsedBuyAmount <= 0) return ""
|
||||
var val = parsedBuyAmount * buyToken.usdPrice
|
||||
return "~$" + val.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
|
||||
}
|
||||
@ -92,7 +112,9 @@ Rectangle {
|
||||
"feeAmount": swapState.formatTokenAmount(feeAmount, sellToken ? sellToken.symbol : ""),
|
||||
"priceImpactPercent": swapState.formatPercent(priceImpactPercent),
|
||||
"priceImpactPercentValue": priceImpactPercent,
|
||||
"slippageTolerance": swapState.formatSlippagePercent(slippageTolerancePercent)
|
||||
"slippageTolerance": swapState.formatSlippagePercent(slippageTolerancePercent),
|
||||
"swapMode": swapMode,
|
||||
"swapModeText": swapModeText
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,11 +139,14 @@ Rectangle {
|
||||
Layout.fillWidth: true
|
||||
theme: root.theme
|
||||
label: "Sell"
|
||||
amount: root.sellAmount
|
||||
amount: root.sellDisplay
|
||||
usdValue: root.sellUsd
|
||||
token: root.sellToken
|
||||
readOnly: false
|
||||
onInputEdited: function(v) { root.sellAmount = v }
|
||||
active: root.editingSide === "sell"
|
||||
onInputEdited: function(v) {
|
||||
root.sellInput = v
|
||||
if (root.editingSide !== "sell") root.editingSide = "sell"
|
||||
}
|
||||
onTokenClicked: root.requestTokenSelect("sell")
|
||||
}
|
||||
|
||||
@ -170,10 +195,14 @@ Rectangle {
|
||||
Layout.fillWidth: true
|
||||
theme: root.theme
|
||||
label: "Buy"
|
||||
amount: root.buyAmount
|
||||
amount: root.buyDisplay
|
||||
usdValue: root.buyUsd
|
||||
token: root.buyToken
|
||||
readOnly: true
|
||||
active: root.editingSide === "buy"
|
||||
onInputEdited: function(v) {
|
||||
root.buyInput = v
|
||||
if (root.editingSide !== "buy") root.editingSide = "buy"
|
||||
}
|
||||
onTokenClicked: root.requestTokenSelect("buy")
|
||||
}
|
||||
|
||||
@ -184,6 +213,7 @@ Rectangle {
|
||||
Layout.rightMargin: 16
|
||||
theme: root.theme
|
||||
visible: root.tokensSelected && root.hasAmount
|
||||
swapModeText: root.swapModeText
|
||||
feeText: swapState.formatTokenAmount(root.feeAmount, root.sellToken ? root.sellToken.symbol : "")
|
||||
priceImpactText: swapState.formatPercent(root.priceImpactPercent)
|
||||
priceImpactPercent: root.priceImpactPercent
|
||||
|
||||
@ -9,7 +9,7 @@ Rectangle {
|
||||
property string amount: ""
|
||||
property string usdValue: ""
|
||||
property var token: null
|
||||
property bool readOnly: false
|
||||
property bool active: true
|
||||
|
||||
signal tokenClicked()
|
||||
signal inputEdited(string newValue)
|
||||
@ -18,11 +18,10 @@ Rectangle {
|
||||
target: tiInput
|
||||
property: "text"
|
||||
value: root.amount
|
||||
when: root.readOnly
|
||||
}
|
||||
|
||||
radius: 16
|
||||
color: theme.colors.inputBg
|
||||
color: root.active ? theme.colors.inputBg : theme.colors.panelBg
|
||||
implicitHeight: 110
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 300 } }
|
||||
@ -52,13 +51,12 @@ Rectangle {
|
||||
TextInput {
|
||||
id: tiInput
|
||||
anchors.fill: parent
|
||||
color: theme.colors.textPrimary
|
||||
color: root.active ? theme.colors.textPrimary : theme.colors.textSecondary
|
||||
font.pixelSize: 36
|
||||
font.weight: Font.Bold
|
||||
readOnly: root.readOnly
|
||||
selectionColor: theme.colors.selection
|
||||
clip: true
|
||||
onTextChanged: { if (!root.readOnly) root.inputEdited(text) }
|
||||
onTextEdited: root.inputEdited(text)
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: /^[0-9]*\.?[0-9]*$/
|
||||
}
|
||||
|
||||
@ -144,6 +144,7 @@ FocusScope {
|
||||
SwapSummary {
|
||||
Layout.fillWidth: true
|
||||
theme: root.theme
|
||||
swapModeText: root.snapshot.swapModeText || ""
|
||||
feeText: root.snapshot.feeAmount || ""
|
||||
priceImpactText: root.snapshot.priceImpactPercent || ""
|
||||
priceImpactPercent: Number(root.snapshot.priceImpactPercentValue) || 0
|
||||
|
||||
@ -5,6 +5,7 @@ Item {
|
||||
id: root
|
||||
|
||||
property var theme
|
||||
property string swapModeText: ""
|
||||
property string feeText: ""
|
||||
property string priceImpactText: ""
|
||||
property real priceImpactPercent: 0
|
||||
@ -25,6 +26,30 @@ Item {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
Item {
|
||||
implicitHeight: 18
|
||||
visible: root.swapModeText.length > 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.theme.colors.textSecondary
|
||||
font.pixelSize: 12
|
||||
text: qsTr("Type of swap")
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.theme.colors.textPrimary
|
||||
font.bold: true
|
||||
font.pixelSize: 12
|
||||
text: root.swapModeText
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
implicitHeight: 18
|
||||
|
||||
|
||||
@ -30,6 +30,22 @@ QtObject {
|
||||
return safeReserveOut * amountInAfterFee / (safeReserveIn + amountInAfterFee);
|
||||
}
|
||||
|
||||
function amountInFor(amountOut, reserveIn, reserveOut) {
|
||||
const safeAmountOut = parseAmount(amountOut);
|
||||
const safeReserveIn = parseAmount(reserveIn);
|
||||
const safeReserveOut = parseAmount(reserveOut);
|
||||
|
||||
if (safeAmountOut <= 0 || safeReserveIn <= 0 || safeReserveOut <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (safeAmountOut >= safeReserveOut) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const amountInAfterFee = safeAmountOut * safeReserveIn / (safeReserveOut - safeAmountOut);
|
||||
return amountInAfterFee * 10000 / (10000 - root.feeBps);
|
||||
}
|
||||
|
||||
function priceImpactPercent(amountIn, amountOut, reserveIn, reserveOut) {
|
||||
const safeAmountIn = parseAmount(amountIn);
|
||||
const safeAmountOut = parseAmount(amountOut);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user