diagonal line support

This commit is contained in:
Tim Olson
2023-12-19 17:07:08 -04:00
parent 9199d31e77
commit 8007f63469
10 changed files with 170 additions and 52 deletions

View File

@@ -4,31 +4,43 @@
<div class="title">Line Point A</div>
<v-divider/>
<time-entry v-model="time1" class="mb-0" hide-details="true"/>
<limit-price v-model="price1" label="Price A" :required="true"/>
<limit-price v-model="price1" label="Price A" :required="true" :show-price="false"/>
<div class="title">Line Point B</div>
<v-divider/>
<time-entry v-model="time2" hide-details="true"/>
<limit-price v-model="price2" label="Price B" :required="true"/>
<div><i>Backend support for diagonal lines is coming soon...</i></div>
<limit-price v-model="price2" label="Price B" :required="true" :show-price="false"/>
<div v-if="curLimit">
<v-row>
<v-col cols="6">
<span>Current line value</span>&nbsp;<span class="text-green">{{curLimit ? curLimit.toPrecision(5) : curLimit}}</span>
</v-col>
<v-col cols="6">
<span>Current price</span>&nbsp;<route-price class="text-green"/>
</v-col>
</v-row>
</div>
{{os.limitIsMinimum}}
</order>
</template>
<script setup>
import {useOrderStore} from "@/store/store";
import {useOrderStore, useStore} from "@/store/store";
import LimitPrice from "@/components/LimitPrice.vue";
import Order from "@/components/Order.vue";
import {computed, ref} from "vue";
import {applyLimit, applyLinePoints} from "@/orderbuild.js";
import {validateRequired, validateTranches} from "@/validate.js";
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import {applyLinePoints, linePointsValue} from "@/orderbuild.js";
import {newTranche} from "@/blockchain/orderlib.js";
import TimeEntry from "@/components/TimeEntry.vue";
import RoutePrice from "@/components/RoutePrice.vue";
const s = useStore()
const os = useOrderStore()
const time1 = ref(new Date())
const price1 = ref(null)
const time2 = ref(new Date())
const price2 = ref(null)
const curLimit = computed(()=>linePointsValue(time1.value, price1.value, time2.value, price2.value, s.time))
function buildTranches() {
const t = newTranche();
@@ -37,7 +49,7 @@ function buildTranches() {
}
function validOrder() {
return false
return time1.value && (price1.value || price1.value===0) && time2.value && (price2.value || price2.value===0)
}
</script>

View File

@@ -24,8 +24,8 @@
</suspense>
</template>
<template v-slot:item.avg="{ item }">
{{ pairPrice(item.order.tokenIn, item.order.tokenOut, vaultAddr, item.avg) }}
<btn v-if="pairPrice(item.order.tokenIn, item.order.tokenOut, vaultAddr, item.avg)!==''" size="small"
{{ pairPrice(item.order.tokenIn, item.order.tokenOut, item.avg) }}
<btn v-if="pairPrice(item.order.tokenIn, item.order.tokenOut, item.avg)!==''" size="small"
variant="plain"
@click="inverted[[vaultAddr,item.index]] = !inverted[[vaultAddr,item.index]]">
{{ pair(item.order.tokenIn, item.order.tokenOut, vaultAddr, item.index) }}
@@ -117,7 +117,7 @@ const inverted = reactive({})
// todo create a Price component that keeps inversion flags in the store and defaults to stablecoins as the quote
function pairPrice(inTokenAddr, outTokenAddr, vaultAddr, price) {
function pairPrice(inTokenAddr, outTokenAddr, price) {
if( price === null )
return ''
const inToken = token(inTokenAddr)
@@ -125,7 +125,7 @@ function pairPrice(inTokenAddr, outTokenAddr, vaultAddr, price) {
if( !inToken || !outToken )
return ''
const decimals = outToken.decimals-inToken.decimals
const decimals = inToken.decimals-outToken.decimals
if( decimals > 0 )
price /= 10 ** decimals
else
@@ -268,11 +268,14 @@ function describeTrancheTime(st, isStart, t) {
}
function describeTrancheLine(st, isMin, b, m) {
if( b===0 && m===0 ) return ''
// todo slopes
console.log('tranche line', isMin, b, m)
// todo make this a PairPrice
return (isMin === st.order.amountIsInput ? 'dont-chase ' : 'limit ') + pairPrice(st.order.tokenIn, st.order.tokenOut, s.vault, b)
if( b===0 && m===0 ) return ''
// console.log('tranche line', isMin, b, m)
if( m !== 0 ) {
const limit = b + m * s.time
return 'diagonal ' + pairPrice(st.order.tokenIn, st.order.tokenOut, limit)
}
return (isMin === st.order.amountIsInput ? 'dont-chase ' : 'limit ') + pairPrice(st.order.tokenIn, st.order.tokenOut, b)
}
</script>

View File

@@ -0,0 +1,45 @@
<template>
<span>{{adjValue}}</span>
<!-- todo optional pair label and inversion button -->
</template>
<script setup>
import {usePrefStore, useStore} from "@/store/store";
import {computed} from "vue";
import {token} from "@/blockchain/token.js";
const props = defineProps(['value','tokenA','tokenB','addrA','addrB',])
const s = useStore()
const prefs = usePrefStore()
const adjValue = computed(()=>{
const a = props.tokenA ? props.tokenA : token(s.chainId,props.addrA)
const b = props.tokenB ? props.tokenB : token(s.chainId,props.addrB)
if( !a || !b )
return ''
let price = props.value
const decimals = b.decimals-a.decimals
if( decimals > 0 )
price /= 10 ** decimals
else
price *= 10 ** -decimals
const token0 = a.address < b.address ? a.address : b.address
const token1 = a.address > b.address ? a.address : b.address
const invertedKey = [token0, token1];
if( !(invertedKey in prefs.inverted) ) {
// todo prefer stablecoins as the quote asset
prefs.inverted[invertedKey] = false
}
if( prefs.inverted[invertedKey] )
price = 1/price
return price.toPrecision(5)
})
</script>
<style scoped lang="scss">
@use "src/styles/vars" as *;
</style>

View File

@@ -3,24 +3,27 @@
</template>
<script setup>
import {useStore} from "@/store/store";
import {useOrderStore, useStore} from "@/store/store";
import {subPrices, unsubPrices, WIDE_PRICE_FORMAT} from "@/blockchain/prices.js";
import {computed, onBeforeUnmount} from "vue";
import {FixedNumber} from "ethers";
import {routeInverted} from "@/misc.js";
const s = useStore()
const os = useOrderStore()
const props = defineProps({
route: {type: Object, required:true},
inverted: {type: Boolean, required:true},
route: {type: Object, required:false},
inverted: {type: Boolean, required:false},
precision: {type: Number, default:5, required:false},
})
const route = computed(()=>props.route ? props.route : os.route)
const price = computed(()=>{
const route = props.route;
if( !route )
if( !route.value )
return ''
const routeKey = [route.chainId, route.pool]
const routeKey = [route.value.chainId, route.value.pool]
if( !(routeKey in s.poolPrices) )
return ''
let p = s.poolPrices[routeKey]
@@ -28,19 +31,20 @@ const price = computed(()=>{
if( !p )
return ''
p = FixedNumber.fromString(p, WIDE_PRICE_FORMAT).toUnsafeFloat()
if( props.inverted )
const inverted = props.inverted === undefined ? routeInverted(route.value) : props.inverted;
if( inverted )
p = 1/p
return p.toPrecision(props.precision)
})
if( props.route )
subPrices([props.route])
if( route.value )
subPrices([route.value])
else
console.log('route is empty: no price')
onBeforeUnmount(() => {
if( props.route )
unsubPrices([props.route])
if( route.value )
unsubPrices([route.value])
})

View File

@@ -30,7 +30,18 @@ const year = computed({
set(v) { update(v, month.value, day.value, time.value)},
})
const time = computed({
get() { return '' + (s.utc ? `${props.modelValue.getUTCHours()}:${props.modelValue.getUTCMinutes()}` : `${props.modelValue.getHours()}:${props.modelValue.getMinutes()}` ) },
get() {
let hour, min
if( s.utc ) {
hour = props.modelValue.getUTCHours()
min = props.modelValue.getUTCMinutes()
}
else {
hour = props.modelValue.getHours()
min = props.modelValue.getMinutes()
}
return hour.toString().padStart(2,'0') + ':' + min.toString().padStart(2,'0')
},
set(v) { update(year.value, month.value, day.value, v) }
})
@@ -45,7 +56,6 @@ const monthItems = monthsForLocale(undefined, 'short').map((v)=>{return {title:v
function buildDate(y, m, d, t) {
const [hours,minutes] = t.split(':')
console.log('buildDate', y, m, d, hours, minutes)
return s.utc ? new Date(Date.UTC(y, m, d, hours, minutes))
: new Date(y, m, d, hours, minutes);
}