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