mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-07-25 08:13:12 +00:00
143 lines
5.5 KiB
QML
143 lines
5.5 KiB
QML
import QtQuick 2.15
|
|
|
|
QtObject {
|
|
id: root
|
|
|
|
property int feeBps: 30
|
|
|
|
function parseAmount(value) {
|
|
return Math.max(0, Number(value) || 0);
|
|
}
|
|
|
|
function clampSlippagePercent(value) {
|
|
return Math.max(0, Math.min(50, Number(value) || 0));
|
|
}
|
|
|
|
function feeAmount(amountIn) {
|
|
return parseAmount(amountIn) * root.feeBps / 10000;
|
|
}
|
|
|
|
function amountOutFor(amountIn, reserveIn, reserveOut) {
|
|
const safeAmountIn = parseAmount(amountIn);
|
|
const safeReserveIn = parseAmount(reserveIn);
|
|
const safeReserveOut = parseAmount(reserveOut);
|
|
|
|
if (safeAmountIn <= 0 || safeReserveIn <= 0 || safeReserveOut <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
const amountInAfterFee = safeAmountIn * (10000 - root.feeBps) / 10000;
|
|
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);
|
|
const safeReserveIn = parseAmount(reserveIn);
|
|
const safeReserveOut = parseAmount(reserveOut);
|
|
|
|
if (safeAmountIn <= 0 || safeAmountOut <= 0) {
|
|
return 0;
|
|
}
|
|
if (safeReserveIn <= 0 || safeReserveOut <= 0) {
|
|
return 0;
|
|
}
|
|
if (safeReserveOut - safeAmountOut <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
const priceBefore = safeReserveIn / safeReserveOut;
|
|
const priceAfter = (safeReserveIn + safeAmountIn) / (safeReserveOut - safeAmountOut);
|
|
return (priceAfter - priceBefore) / priceBefore * 100;
|
|
}
|
|
|
|
function minReceived(amountOut, slippagePercent) {
|
|
const safeAmount = parseAmount(amountOut);
|
|
const safeSlippage = clampSlippagePercent(slippagePercent);
|
|
return safeAmount * (1 - safeSlippage / 100);
|
|
}
|
|
|
|
// Exact-integer minimum-received (base units) for a SwapExactInput, used as
|
|
// the on-chain slippage floor that is actually submitted. Computed in BigInt
|
|
// (arbitrary precision, mirroring the on-chain u256 math): base units for
|
|
// 18-decimal tokens exceed 2^53 and even overflow u128 intermediates, so JS
|
|
// doubles silently lose precision and would understate min_out — weakening
|
|
// the user's price protection. amountIn/reserveIn/reserveOut are base-unit
|
|
// integer strings; returns a decimal string. Falls back to the double
|
|
// estimate only if BigInt is unavailable in this Qt build.
|
|
function minOutBaseUnits(amountIn, reserveIn, reserveOut, slippagePercent) {
|
|
if (typeof BigInt !== "undefined") {
|
|
var toBig = function (x) {
|
|
var s = String(x).trim();
|
|
return /^[0-9]+$/.test(s) ? BigInt(s) : BigInt(0);
|
|
};
|
|
var zero = BigInt(0);
|
|
var denom = BigInt(10000);
|
|
var amtIn = toBig(amountIn);
|
|
var resIn = toBig(reserveIn);
|
|
var resOut = toBig(reserveOut);
|
|
if (amtIn <= zero || resIn <= zero || resOut <= zero)
|
|
return "0";
|
|
|
|
var feeBps = BigInt(Math.round(Math.min(10000, Math.max(0, Number(root.feeBps) || 0))));
|
|
var amtInAfterFee = amtIn * (denom - feeBps) / denom; // floor
|
|
if (amtInAfterFee <= zero)
|
|
return "0";
|
|
var out = resOut * amtInAfterFee / (resIn + amtInAfterFee); // floor
|
|
var slipBps = BigInt(Math.round(clampSlippagePercent(slippagePercent) * 100));
|
|
if (slipBps < zero) slipBps = zero;
|
|
if (slipBps > denom) slipBps = denom;
|
|
var minOut = out * (denom - slipBps) / denom; // floor
|
|
return minOut.toString();
|
|
}
|
|
// Legacy double fallback (no worse than before if BigInt is missing).
|
|
var estOut = amountOutFor(amountIn, reserveIn, reserveOut);
|
|
return String(Math.floor(Math.max(0, minReceived(estOut, slippagePercent))));
|
|
}
|
|
|
|
function maxSent(amountIn, slippagePercent) {
|
|
const safeAmount = parseAmount(amountIn);
|
|
const safeSlippage = clampSlippagePercent(slippagePercent);
|
|
return safeAmount * (1 + safeSlippage / 100);
|
|
}
|
|
|
|
function formatAmountValue(value) {
|
|
const amount = Math.max(0, Number(value) || 0);
|
|
if (amount >= 1) return amount.toFixed(2);
|
|
if (amount >= 0.0001) return amount.toFixed(6);
|
|
return amount.toFixed(8);
|
|
}
|
|
|
|
function formatTokenAmount(value, symbol) {
|
|
const formatted = formatAmountValue(value);
|
|
return symbol ? formatted + " " + symbol : formatted;
|
|
}
|
|
|
|
function formatPercent(value) {
|
|
const amount = Number(value) || 0;
|
|
if (amount > 0 && amount < 0.01) return "<0.01%";
|
|
return amount.toFixed(2) + "%";
|
|
}
|
|
|
|
function formatSlippagePercent(value) {
|
|
const amount = clampSlippagePercent(value);
|
|
return amount.toFixed(2).replace(/0+$/, "").replace(/[.]$/, "") + "%";
|
|
}
|
|
}
|