order sanity checks
This commit is contained in:
@@ -30,6 +30,7 @@ export function refreshOHLCSubs() {
|
||||
}
|
||||
keys.push(`${pool}|${period}`)
|
||||
}
|
||||
console.log('refreshing OHLC subs', keys)
|
||||
socket.emit('subOHLCs', chainId, keys)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,6 @@ export function allocationText(buy, weight, amount, baseSymbol, amountSymbol = n
|
||||
const hasWeight = weight !== null && weight !== undefined && weight !== 1
|
||||
if (hasWeight)
|
||||
weight = Number(weight)
|
||||
if (buy===undefined)
|
||||
console.error('allocation text buy', buy)
|
||||
let text = buy === undefined ? '' : buy ? 'Buy ' : 'Sell '
|
||||
if (hasWeight)
|
||||
text += `${(weight * 100).toFixed(1)}%`
|
||||
|
||||
@@ -70,7 +70,7 @@ import BuilderFactory from "@/components/chart/BuilderFactory.vue";
|
||||
import {builderFuncs, newBuilder, orderFuncs, useChartOrderStore} from "@/orderbuild.js";
|
||||
import {useOrderStore, useStore} from "@/store/store.js";
|
||||
import {computed, onUnmounted, onUpdated, ref, watchEffect} from "vue";
|
||||
import {lightenColor, lightenColor2} from "@/misc.js";
|
||||
import {lightenColor, lightenColor2, toPrecision} from "@/misc.js";
|
||||
import {useTheme} from "vuetify";
|
||||
import RowBar from "@/components/chart/RowBar.vue";
|
||||
import ColorBand from "@/components/chart/ColorBand.vue";
|
||||
@@ -114,7 +114,38 @@ function buildOrder() {
|
||||
const order = props.order
|
||||
console.log('buildOrder', order)
|
||||
|
||||
if (!order.amount) return null
|
||||
if (!order.amount)
|
||||
return {order: null, warnings: ['Amount must be greater than 0']}
|
||||
|
||||
const symbol = co.selectedSymbol
|
||||
const amountDec = order.amountIsTokenA ? symbol.base.d : symbol.quote.d
|
||||
const amount = BigInt(Math.trunc(order.amount * 10 ** amountDec))
|
||||
|
||||
let warnings = []
|
||||
const inAddr = order.buy ? symbol.quote.a : symbol.base.a
|
||||
const inDec = order.buy ? symbol.quote.d : symbol.base.d
|
||||
const available = s.getBalance(inAddr) / 10 ** inDec
|
||||
|
||||
let needed
|
||||
if (order.amountIsTokenA && order.buy)
|
||||
// need quote currency to buy an amount of base
|
||||
needed = order.amount * co.price
|
||||
else if (order.amountIsTokenA && !order.buy)
|
||||
// sell an exact amount of base
|
||||
needed = order.amount
|
||||
else if (!order.amountIsTokenA && order.buy)
|
||||
// need an exact amount of quote
|
||||
needed = order.amount
|
||||
else if (!order.amountIsTokenA && !order.buy)
|
||||
// sell a quote amount worth of base
|
||||
needed = order.amount / co.price
|
||||
else
|
||||
throw new Error('Invalid order')
|
||||
const deficit = needed - available
|
||||
if (deficit > 0) {
|
||||
const inSymbol = order.buy ? symbol.quote.s : symbol.base.s
|
||||
warnings.push(`Insufficient funds. Add ${toPrecision(deficit, 5)} ${inSymbol} to your vault to complete this order.`)
|
||||
}
|
||||
|
||||
// struct SwapOrder {
|
||||
// address tokenIn;
|
||||
@@ -127,20 +158,24 @@ function buildOrder() {
|
||||
// uint64 conditionalOrder; // use NO_CONDITIONAL_ORDER for no chaining. conditionalOrder index must be < than this order's index for safety (written first) and conditionalOrder state must be Template
|
||||
// Tranche[] tranches;
|
||||
// }
|
||||
const symbol = co.selectedSymbol
|
||||
const amountDec = order.amountIsTokenA ? symbol.base.d : symbol.quote.d
|
||||
const amount = BigInt(Math.trunc(order.amount * 10 ** amountDec))
|
||||
const amountIsInput = !!(order.amountIsTokenA ^ order.buy)
|
||||
|
||||
let tranches = []
|
||||
for (const builder of builders.value) {
|
||||
console.log('builder', builder)
|
||||
const ts = builderFuncs[builder.id]()
|
||||
const built = builderFuncs[builder.id]()
|
||||
const ts = built.tranches
|
||||
const ws = built.warnings
|
||||
console.log('tranches', ts)
|
||||
tranches = [...tranches, ...ts]
|
||||
warnings = [...warnings, ...ws]
|
||||
}
|
||||
|
||||
return newOrder(tokenIn.value.a, tokenOut.value.a, symbol.exchangeId, symbol.fee, amount, amountIsInput, symbol.inverted, tranches)
|
||||
return {
|
||||
warnings,
|
||||
order: newOrder(tokenIn.value.a, tokenOut.value.a, symbol.exchangeId, symbol.fee,
|
||||
amount, amountIsInput, symbol.inverted, tranches),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Place Dexorder
|
||||
</v-btn>
|
||||
<v-btn variant="text" prepend-icon="mdi-delete" v-if="co.orders.length>0"
|
||||
:disabled="!orderChanged" @click="cancelOrder">Reset</v-btn>
|
||||
:disabled="!orderChanged" @click="resetOrder">Reset</v-btn>
|
||||
</template>
|
||||
<div class="overflow-y-auto">
|
||||
<needs-chart>
|
||||
@@ -19,7 +19,21 @@
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
<v-btn @click="()=>showResetDialog=false">Keep Existing</v-btn>
|
||||
<v-btn @click="()=>{co.resetOrders(); showResetDialog=false}" color="red" text="Reset Order"/>
|
||||
<v-btn @click="doResetOrder" color="red" text="Reset Order"/>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="showWarnings" max-width="300">
|
||||
<v-card prepend-icon="mdi-warning" title="Order Warnings" text="Your order has the following warnings:">
|
||||
<v-card-text>
|
||||
<v-list>
|
||||
<v-list-item v-for="w of orderWarnings">{{w}}</v-list-item>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
<v-btn @click="()=>showWarnings=false">Back</v-btn>
|
||||
<v-btn @click="doPlaceOrder">Place Order</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
@@ -78,10 +92,19 @@ const valid = computed(()=>{
|
||||
|
||||
const orderChanged = computed(()=>!(co.orders.length===1 && co.orders[0].builders.length===0 && !co.orders[0].amount))
|
||||
|
||||
function cancelOrder() {
|
||||
const showWarnings = ref(false)
|
||||
const orderWarnings = ref([])
|
||||
|
||||
function resetOrder() {
|
||||
showResetDialog.value = true
|
||||
}
|
||||
|
||||
function doResetOrder() {
|
||||
co.resetOrders();
|
||||
orderWarnings.value = []
|
||||
showResetDialog.value = false
|
||||
}
|
||||
|
||||
watchEffect(()=>{
|
||||
const removable = []
|
||||
for (const order of ws.pendingOrders) {
|
||||
@@ -108,17 +131,31 @@ watchEffect(()=>{
|
||||
}
|
||||
})
|
||||
|
||||
let built = []
|
||||
|
||||
async function placeOrder() {
|
||||
const chartOrders = co.orders;
|
||||
const built = []
|
||||
const allWarns = []
|
||||
built = []
|
||||
for (const chartOrder of chartOrders) {
|
||||
console.log('chartOrder', chartOrder)
|
||||
const buildOrder = orderFuncs[chartOrder.id]
|
||||
const order = buildOrder()
|
||||
const {order, warnings} = buildOrder()
|
||||
built.push(order)
|
||||
allWarns.push(...warnings)
|
||||
}
|
||||
console.log('place orders', built)
|
||||
|
||||
if (allWarns.length > 0) {
|
||||
orderWarnings.value = allWarns
|
||||
showWarnings.value = true
|
||||
return
|
||||
}
|
||||
|
||||
await doPlaceOrder()
|
||||
}
|
||||
|
||||
async function doPlaceOrder() {
|
||||
console.log('place orders')
|
||||
if (ws.transaction!==null) {
|
||||
console.error('Transaction already in progress')
|
||||
}
|
||||
|
||||
@@ -85,8 +85,6 @@ const amountSymbol = computed(()=>props.order.amountIsTokenA ? co.selectedSymbol
|
||||
const allocationTexts = computed(()=>weights.value.map((w)=>allocationText(props.order.buy, w, w * props.order.amount, co.selectedSymbol.base.s, amountSymbol.value)))
|
||||
|
||||
const endTimes = computed(()=>{
|
||||
if (props.builder.rungs === 1)
|
||||
return DISTANT_FUTURE
|
||||
const ts = times.value
|
||||
const window = Math.max(MIN_EXECUTION_TIME, Math.floor((ts[ts.length-1]-ts[0])/props.builder.rungs))
|
||||
return ts.map((t)=>t+window)
|
||||
@@ -151,28 +149,28 @@ const timeEndpoints = computed({
|
||||
get() { return _timeEndpoints.value},
|
||||
set(v) {
|
||||
const [a, b] = v
|
||||
update(a,b)
|
||||
update(a,b, true, true)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function updateA(a) {
|
||||
update(a, _timeEndpoints.value[1], true)
|
||||
update(a, _timeEndpoints.value[1], true, false)
|
||||
}
|
||||
|
||||
|
||||
function updateB(b) {
|
||||
update(_timeEndpoints.value[0], b, false)
|
||||
update(_timeEndpoints.value[0], b, false, true)
|
||||
}
|
||||
|
||||
|
||||
function update(a, b, updatingA) {
|
||||
if (updatingA) {
|
||||
function update(a, b, updateA, updateB) {
|
||||
if (updateA) {
|
||||
const minB = a + minWidth.value
|
||||
if (b < minB)
|
||||
b = minB
|
||||
}
|
||||
else {
|
||||
if (updateB) {
|
||||
const maxA = b - minWidth.value
|
||||
if (a > maxA)
|
||||
a = maxA
|
||||
@@ -194,21 +192,27 @@ function buildTranches() {
|
||||
const order = props.order
|
||||
const builder = props.builder
|
||||
const tranches = []
|
||||
const warnings = []
|
||||
|
||||
console.log('buildTranches', builder, order, tranches)
|
||||
const ts = times.value
|
||||
const ets = endTimes.value
|
||||
const ws = weights.value
|
||||
console.log('buildTranches times ends weights', ts, ets, ws)
|
||||
for(let i=0; i<ts.length; i++) {
|
||||
const endTime = Math.max(ets[i],ts[i]+60);
|
||||
console.log('time check', endTime, s.clock)
|
||||
if (endTime <= s.clock)
|
||||
warnings.push(`Tranche already expired at ${new Date(endTime*1000)}`)
|
||||
const t = newTranche({
|
||||
fraction: ws[i] * MAX_FRACTION,
|
||||
startTime: ts[i],
|
||||
endTime: Math.max(ets[i],ts[i]+60), // always give at least 60 seconds of window to execute
|
||||
endTime, // always give at least 60 seconds of window to execute
|
||||
slippage: builder.slippage,
|
||||
})
|
||||
tranches.push(t)
|
||||
}
|
||||
return tranches
|
||||
return {tranches, warnings}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,7 +101,9 @@ import {computed, ref} from "vue";
|
||||
import {allocationText, DLine} from "@/charts/shape.js";
|
||||
import {vectorEquals, vectorInterpolate} from "@/vector.js";
|
||||
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
|
||||
import {useStore} from "@/store/store.js";
|
||||
|
||||
const s = useStore()
|
||||
const co = useChartOrderStore()
|
||||
const props = defineProps(['order', 'builder'])
|
||||
const emit = defineEmits(['update:builder'])
|
||||
@@ -132,6 +134,7 @@ function buildTranches() {
|
||||
const order = props.order
|
||||
const builder = props.builder
|
||||
const tranches = []
|
||||
const warnings = []
|
||||
|
||||
console.log('buildTranches', builder, order, _endpoints.value)
|
||||
const la = _endpoints.value[0] // use the flatline format which is a vector of length 4, useful for vectorInterpolate()
|
||||
@@ -149,6 +152,9 @@ function buildTranches() {
|
||||
t.startTime = reversed ? line[2] : line[0]
|
||||
if (reversed ? !el : !er)
|
||||
t.endTime = reversed ? line[0] : line[2]
|
||||
if (t.endTime <= s.clock)
|
||||
warnings.push(`Tranche already expired at ${new Date(t.endTime*1000)}`)
|
||||
|
||||
// console.log('tranche start/end',
|
||||
// t.startTime === DISTANT_PAST ? 'PAST' : t.startTime,
|
||||
// t.endTime === DISTANT_FUTURE ? 'FUTURE' : t.endTime)
|
||||
@@ -157,7 +163,7 @@ function buildTranches() {
|
||||
}
|
||||
// if( flipped.value )
|
||||
// tranches.reverse()
|
||||
return tranches
|
||||
return {tranches, warnings}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ function buildTranches() {
|
||||
const order = props.order
|
||||
const builder = props.builder
|
||||
const tranches = []
|
||||
const warnings = []
|
||||
|
||||
console.log('buildTranches', builder, order, tranches)
|
||||
const ps = prices.value
|
||||
@@ -90,6 +91,9 @@ function buildTranches() {
|
||||
const w = ws[i]
|
||||
const t = newTranche({
|
||||
// todo start/end
|
||||
// todo check expired
|
||||
// if (endTime <= s.clock)
|
||||
// warnings.push(`Tranche already expired at ${new Date(endTime*1000)}`)
|
||||
fraction: w * MAX_FRACTION,
|
||||
})
|
||||
const symbol = co.selectedSymbol
|
||||
@@ -99,7 +103,7 @@ function buildTranches() {
|
||||
}
|
||||
if (!flipped.value)
|
||||
tranches.reverse()
|
||||
return tranches
|
||||
return {tranches, warnings}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,14 @@ const slippage = computed({
|
||||
})
|
||||
|
||||
function buildTranches() {
|
||||
return [newTranche({slippage: slippage.value/100})]
|
||||
let warnings = []
|
||||
if (slippage.value < 0.01)
|
||||
warnings.push('Slippage will be set to the minimum of 0.01%')
|
||||
const slip = Math.min(slippage.value, 0.01)
|
||||
return {
|
||||
tranches: [newTranche({slippage: slip / 100})],
|
||||
warnings,
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => builderFuncs[props.builder.id] = buildTranches)
|
||||
|
||||
@@ -102,7 +102,6 @@ watchEffect(()=>{
|
||||
})
|
||||
|
||||
function setEndpoints(a, b) {
|
||||
// console.log('rb setting endpoints', devectorize(a), devectorize(b))
|
||||
endpoints.value = [devectorize(a), devectorize(b)]
|
||||
}
|
||||
|
||||
@@ -125,8 +124,7 @@ const rungs = computed({
|
||||
r = Number(r)
|
||||
const prevR = Number(props.builder.rungs)
|
||||
props.builder.rungs = r
|
||||
// console.log('set rungs', prevR, r, a, b)
|
||||
if ( r > 0 && vectorIsNull(b) ) {
|
||||
if ( prevR === 1 && r > 1 ) {
|
||||
// convert single shape to a range
|
||||
if (props.mode===0) {
|
||||
const width = vectorize(props.stdWidth)
|
||||
@@ -143,7 +141,7 @@ const rungs = computed({
|
||||
else
|
||||
throw Error(`Unknown rung mode ${props.mode}`)
|
||||
}
|
||||
else if ( r === 1 && !vectorIsNull(b) ) {
|
||||
else if ( prevR > 1 && r === 1 ) {
|
||||
// convert from a range to a single shape
|
||||
if (props.mode===0)
|
||||
a = vectorDiv(vectorAdd(a,b), 2)
|
||||
|
||||
@@ -56,7 +56,8 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
|
||||
if (!selectedSymbol.value)
|
||||
return null
|
||||
const s = useStore()
|
||||
let result = s.poolPrices[[s.chainId, selectedSymbol.address]]
|
||||
const key = [s.chainId, selectedSymbol.value.address];
|
||||
let result = s.poolPrices[key]
|
||||
if (selectedSymbol.value.inverted)
|
||||
result = 1 / result
|
||||
return result
|
||||
|
||||
@@ -133,6 +133,11 @@ export const useStore = defineStore('app', ()=> {
|
||||
this.extraTokens = extras
|
||||
}
|
||||
|
||||
function getBalance(tokenAddr) {
|
||||
const found = this.balances[tokenAddr]
|
||||
return found === undefined ? 0 : found
|
||||
}
|
||||
|
||||
return {
|
||||
connected,
|
||||
nav, chainId, chainInfo, chain, provider, providerRef, vaultInitCodeHash, account, vaults, vaultVersions,
|
||||
@@ -141,6 +146,7 @@ export const useStore = defineStore('app', ()=> {
|
||||
mockenv, mockCoins,
|
||||
removeTransactionSender, error, closeError, addToken, clock, timeZone, balances,
|
||||
approved, regionApproved, walletApproved,
|
||||
getBalance
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user