complete store refactor; moved form inputs into store; refactored components out of TimedOrderEntry
This commit is contained in:
26
src/components/Amount.vue
Normal file
26
src/components/Amount.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
|
||||
v-model="s.amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
||||
<template v-slot:append-inner>
|
||||
<v-btn @click="s.amountIsTokenA=!s.amountIsTokenA" variant="outlined" class="mr-2">
|
||||
{{ s.amountIsTokenA ? s.tokenA.symbol : s.tokenB.symbol }}
|
||||
</v-btn>
|
||||
<v-btn :text="s.amountIsTotal ? 'total' : 'per tranche'" variant="outlined"
|
||||
@click="s.amountIsTotal=!s.amountIsTotal" class="total"/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store";
|
||||
import {validateRequired, validateAmount, vAutoSelect} from "@/misc.js";
|
||||
|
||||
const s = useStore()
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "src/styles/vars" as *;
|
||||
|
||||
</style>
|
||||
@@ -44,7 +44,7 @@ const tokenA = computed({
|
||||
},
|
||||
set(value) {
|
||||
if( !s.tokenA || s.tokenA.address !== value.address ) {
|
||||
s.tokenA.value = value
|
||||
s.tokenA = value
|
||||
routeFinder.invoke()
|
||||
}
|
||||
}
|
||||
@@ -64,25 +64,25 @@ const tokenB = computed({
|
||||
|
||||
const routes = computed({
|
||||
get() {
|
||||
return s.routes.value
|
||||
return s.routes
|
||||
},
|
||||
set(value) {
|
||||
console.log('setting new routes', s.routes.value, value)
|
||||
s.routes.value = value
|
||||
console.log('setting new routes', s.routes, value)
|
||||
s.routes = value
|
||||
}
|
||||
})
|
||||
|
||||
async function componentFindRoute() {
|
||||
const tokenA = s.tokenA
|
||||
const tokenB = s.tokenB
|
||||
console.log('finding route', tokenA, tokenB)
|
||||
// console.log('finding route', tokenA, tokenB)
|
||||
s.routes = []
|
||||
if (!tokenA || !tokenB)
|
||||
return
|
||||
s.routesPending = true
|
||||
try {
|
||||
const result = await findRoute(tokenA, tokenB)
|
||||
console.log('found route', result)
|
||||
// console.log('found route', result)
|
||||
s.routes = result
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
@@ -21,7 +21,7 @@ const price = computed(()=>{
|
||||
if( !route || !(route.pool in s.poolPrices) )
|
||||
return ''
|
||||
let p = s.poolPrices[route.pool]
|
||||
console.log('pool price is',typeof p, p)
|
||||
// console.log('pool price is',typeof p, p)
|
||||
if( !p )
|
||||
return ''
|
||||
p = FixedNumber.fromString(p, WIDE_PRICE_FORMAT).toUnsafeFloat()
|
||||
|
||||
@@ -6,26 +6,13 @@
|
||||
<v-card-item>
|
||||
<pair-choice/>
|
||||
<div v-if="s.route && !s.routesPending">
|
||||
<v-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
|
||||
v-model="amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
||||
<template v-slot:append-inner>
|
||||
<v-btn @click="amountIsTokenA=!amountIsTokenA" variant="outlined" class="mr-2">
|
||||
{{ amountIsTokenA ? s.tokenA.symbol : s.tokenB.symbol }}
|
||||
</v-btn>
|
||||
<v-btn :text="amountIsTotal ? 'total' : 'per tranche'" variant="outlined"
|
||||
@click="amountIsTotal=!amountIsTotal" class="total"/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<amount/>
|
||||
<v-text-field label="Tranches" type="number" variant="outlined" aria-valuemin="1" min="1" max="255"
|
||||
v-model="tranches" :rules="[validateRequired,validateTranches]" v-auto-select>
|
||||
<!-- <template v-slot:prepend-inner>-->
|
||||
<!-- <div>{{ amountIsTotal ? 'Split into' : 'Times' }}</div>-->
|
||||
<!-- </template>-->
|
||||
<template v-slot:append-inner>tranches</template>
|
||||
</v-text-field>
|
||||
<v-text-field type="number" variant="outlined" :min="1" v-model="interval" class="interval"
|
||||
:label="intervalIsTotal ? 'Completion time' : 'Time between tranches'" v-auto-select>
|
||||
<!-- <template v-slot:append>APART</template>-->
|
||||
<template v-slot:prepend-inner>
|
||||
<v-btn variant="outlined" :text="intervalIsTotal ? 'Within' : 'Spaced apart'" class="within mr-2"
|
||||
@click="intervalIsTotal=!intervalIsTotal"/>
|
||||
@@ -34,11 +21,11 @@
|
||||
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
||||
<v-text-field v-model="s.limitPrice" :label="(s.limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
||||
variant="outlined" aria-valuemin="0" min="0"
|
||||
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
||||
<template v-slot:append-inner>
|
||||
<v-btn variant="outlined" @click="inverted=!inverted">
|
||||
<v-btn variant="outlined" @click="s.inverted=!s.inverted">
|
||||
{{s.pairSymbol}}
|
||||
</v-btn>
|
||||
</template>
|
||||
@@ -64,9 +51,10 @@
|
||||
import {useStore} from "@/store/store";
|
||||
import {computed, ref} from "vue";
|
||||
import PhoneCard from "@/components/PhoneCard.vue";
|
||||
import Amount from "@/components/Amount.vue"
|
||||
// noinspection ES6UnusedImports
|
||||
import {routeInverted, SingletonCoroutine, vAutoSelect} from "@/misc.js";
|
||||
import {newLimitConstraint, newOrder, newTimeConstraint, sqrtX96, TimeMode} from "@/blockchain/orderlib.js";
|
||||
import {isEmpty, routeInverted, SingletonCoroutine, vAutoSelect, validateRequired, validateAmount} from "@/misc.js";
|
||||
import {newLimitConstraint, newOrder, newTimeConstraint, TimeMode} from "@/blockchain/orderlib.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {pendOrder} from "@/blockchain/wallet.js";
|
||||
import NeedsProvider from "@/components/NeedsProvider.vue";
|
||||
@@ -76,21 +64,14 @@ import PairChoice from "@/components/PairChoice.vue";
|
||||
|
||||
const s = useStore()
|
||||
|
||||
const amount = ref(100) // todo 0
|
||||
const amountIsTokenA = ref(false)
|
||||
const amountIsTotal = ref(true)
|
||||
const tranches = ref(3)
|
||||
const inverted = ref(false)
|
||||
const minPrice = ref(null)
|
||||
const maxPrice = ref(null)
|
||||
const limitPrice = ref(null)
|
||||
const interval = ref(1)
|
||||
const intervalIsTotal = ref(true)
|
||||
const timeUnits = ['minutes', 'hours', 'days']
|
||||
const timeUnitIndex = ref(0)
|
||||
const limitIsMinimum = computed(() => !(s.buy ^ s.inverted))
|
||||
const validOrder = computed(()=>amount.value > 0 && s.routes.length > 0 )
|
||||
|
||||
const validOrder = computed(()=>s.validOrder)
|
||||
|
||||
function toggleTimeUnits() {
|
||||
timeUnitIndex.value++
|
||||
@@ -99,18 +80,6 @@ function toggleTimeUnits() {
|
||||
}
|
||||
|
||||
|
||||
function isEmpty(v) {
|
||||
return v === null || typeof v === 'string' && v.trim() === ''
|
||||
}
|
||||
|
||||
|
||||
function validateRequired(v) {
|
||||
if (isEmpty(v))
|
||||
return 'Required'
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
function validateTranches(v) {
|
||||
const i = parseInt(v)
|
||||
if (parseFloat(v) !== i)
|
||||
@@ -123,17 +92,6 @@ function validateTranches(v) {
|
||||
}
|
||||
|
||||
|
||||
function validateAmount(v) {
|
||||
if (isEmpty(v))
|
||||
return true
|
||||
const floatRegex = /^-?\d*(?:[.,]\d*?)?$/
|
||||
if (!floatRegex.test(v))
|
||||
return 'Amount must be a number'
|
||||
if (parseFloat(v) <= 0)
|
||||
return 'Amount must be positive'
|
||||
return true
|
||||
}
|
||||
|
||||
function validateMax(v) {
|
||||
if (!isEmpty(minPrice.value) && !isEmpty(v) && parseFloat(v) < parseFloat(minPrice.value))
|
||||
return 'Must be greater than the minimum price'
|
||||
@@ -152,9 +110,7 @@ function placeOrder() {
|
||||
const tokenIn = s.buy ? tb.address : ta.address
|
||||
const tokenOut = s.buy ? ta.address : tb.address
|
||||
const route = s.route
|
||||
const amountToken = amountIsTokenA.value ? ta : tb
|
||||
const amt = FixedNumber.fromString(amount.value.toString(), {decimals: amountToken.decimals}).value
|
||||
const amountIsInput = amountIsTokenA.value !== s.buy
|
||||
const amt = FixedNumber.fromString(s.amount.toString(), {decimals: s.amountToken.decimals}).value
|
||||
|
||||
// build tranches
|
||||
const n = tranches.value // num tranches
|
||||
@@ -173,20 +129,18 @@ function placeOrder() {
|
||||
const ceil = oneHundredPercent % BigInt(n) ? 1n : 0n
|
||||
const amtPerTranche = oneHundredPercent / BigInt(n) + ceil
|
||||
duration -= 15 // subtract 15 seconds so the last tranche completes before the deadline
|
||||
console.log('duration', duration)
|
||||
let priceConstraint = null
|
||||
if( limitPrice.value ) {
|
||||
if( s.limitPrice ) {
|
||||
const inverted = routeInverted(route)
|
||||
const isAbove = limitIsMinimum.value ^ inverted
|
||||
const isAbove = s.limitIsMinimum ^ inverted
|
||||
const isRatio = false // todo ratios
|
||||
const decimals = 10 ** (s.tokenA.decimals - s.tokenB.decimals)
|
||||
const limit = inverted ? decimals/limitPrice.value : limitPrice.value/decimals
|
||||
priceConstraint = !limitPrice.value ? null : newLimitConstraint(isAbove, isRatio, limit)
|
||||
const limit = inverted ? decimals/s.limitPrice : s.limitPrice/decimals
|
||||
priceConstraint = !s.limitPrice ? null : newLimitConstraint(isAbove, isRatio, limit)
|
||||
}
|
||||
for (let i = 0; i < n; i++) {
|
||||
const start = Math.floor(i * (duration / Math.max((n - 1), 1)))
|
||||
const end = start + window
|
||||
console.log('tranche window', start, end, (end-start)/60)
|
||||
const cs = [newTimeConstraint(TimeMode.SinceOrderStart, start, TimeMode.SinceOrderStart, end)]
|
||||
if( priceConstraint !== null )
|
||||
cs.push(priceConstraint)
|
||||
|
||||
Reference in New Issue
Block a user