diff --git a/src/blockchain/ohlcs.js b/src/blockchain/ohlcs.js index afafc14..ef5e987 100644 --- a/src/blockchain/ohlcs.js +++ b/src/blockchain/ohlcs.js @@ -30,6 +30,7 @@ export function refreshOHLCSubs() { } keys.push(`${pool}|${period}`) } + console.log('refreshing OHLC subs', keys) socket.emit('subOHLCs', chainId, keys) } diff --git a/src/charts/shape.js b/src/charts/shape.js index c21a7c7..2a27548 100644 --- a/src/charts/shape.js +++ b/src/charts/shape.js @@ -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)}%` diff --git a/src/components/chart/ChartOrder.vue b/src/components/chart/ChartOrder.vue index 4243461..ac0d571 100644 --- a/src/components/chart/ChartOrder.vue +++ b/src/components/chart/ChartOrder.vue @@ -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), + } } diff --git a/src/components/chart/ChartPlaceOrder.vue b/src/components/chart/ChartPlaceOrder.vue index a9622a9..767aa19 100644 --- a/src/components/chart/ChartPlaceOrder.vue +++ b/src/components/chart/ChartPlaceOrder.vue @@ -7,7 +7,7 @@ Place Dexorder Reset + :disabled="!orderChanged" @click="resetOrder">Reset
@@ -19,7 +19,21 @@ Keep Existing - + + + + + + + + + {{w}} + + + + + Back + Place Order @@ -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') } diff --git a/src/components/chart/DCABuilder.vue b/src/components/chart/DCABuilder.vue index dad28ed..b714b2f 100644 --- a/src/components/chart/DCABuilder.vue +++ b/src/components/chart/DCABuilder.vue @@ -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 builderFuncs[props.builder.id] = buildTranches) diff --git a/src/components/chart/RungBuilder.vue b/src/components/chart/RungBuilder.vue index 0331641..b0d0e15 100644 --- a/src/components/chart/RungBuilder.vue +++ b/src/components/chart/RungBuilder.vue @@ -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) diff --git a/src/orderbuild.js b/src/orderbuild.js index a59c0d5..b3e98e5 100644 --- a/src/orderbuild.js +++ b/src/orderbuild.js @@ -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 diff --git a/src/store/store.js b/src/store/store.js index 5963dba..74320ee 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -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 } })