price constraints working
This commit is contained in:
45
src/components/Faucet.vue
Normal file
45
src/components/Faucet.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<phone-card v-if="s.mockenv">
|
||||
<v-card-title><v-icon icon="mdi-faucet"/> Mock Coin Faucet</v-card-title>
|
||||
<v-card-text>Mockchain provides infinite amounts of MOCK (Mockcoin) and USD (Universally Stable Denomination) for your vault. Click the button below to get a million of each: </v-card-text>
|
||||
<v-card-item>
|
||||
<v-table plain>
|
||||
<tbody>
|
||||
<tr v-for="token of tokens">
|
||||
<td><v-btn prepend-icon='mdi-plus' :text="'Gib '+token.symbol" @click="gib(token)" class="my-3" variant="outlined"/></td>
|
||||
<td>{{token.name}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-table>
|
||||
</v-card-item>
|
||||
</phone-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store";
|
||||
import PhoneCard from "@/components/PhoneCard.vue";
|
||||
import {ethers} from "ethers";
|
||||
import {computed, ref} from "vue";
|
||||
import {pendTransaction} from "@/blockchain/wallet.js";
|
||||
import {mockErc20Abi} from "@/blockchain/abi.js";
|
||||
|
||||
const s = useStore()
|
||||
|
||||
function gib(token) {
|
||||
const tokenAddr = token.address
|
||||
const vault = s.vault
|
||||
const amount = 1_000_000n * 10n ** BigInt(token.decimals);
|
||||
async function send(signer) {
|
||||
return await new ethers.Contract(tokenAddr, mockErc20Abi, signer).mint(vault, amount);
|
||||
}
|
||||
pendTransaction(send)
|
||||
}
|
||||
|
||||
const tokens = computed(()=>!s.mockCoins? [] : s.mockCoins.map((addr)=>s.tokens[addr]))
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "src/styles/vars" as *;
|
||||
|
||||
</style>
|
||||
@@ -1,12 +1,15 @@
|
||||
<template>
|
||||
<!-- tablets and desktops get a card outline -->
|
||||
<v-card class="d-none d-sm-block phone-card" :elevation="4">
|
||||
<slot/>
|
||||
</v-card>
|
||||
<!-- phones use the entire screen -->
|
||||
<v-container class="d-sm-none">
|
||||
<slot/>
|
||||
</v-container>
|
||||
<!-- todo use javascript media breakpoint instead of display classes so we dont double-render the slot -->
|
||||
<div>
|
||||
<!-- tablets and desktops get a card outline -->
|
||||
<v-card class="d-none d-sm-block phone-card" :elevation="4">
|
||||
<slot/>
|
||||
</v-card>
|
||||
<!-- phones use the entire screen -->
|
||||
<v-container class="d-sm-none">
|
||||
<slot/>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
43
src/components/RoutePrice.vue
Normal file
43
src/components/RoutePrice.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<span v-if="route">{{price}}</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store";
|
||||
import {subPrices, unsubPrices} from "@/blockchain/prices.js";
|
||||
import {computed, onBeforeUnmount} from "vue";
|
||||
|
||||
const s = useStore()
|
||||
|
||||
const props = defineProps({
|
||||
route: {type: Object, required:true},
|
||||
inverted: {type: Boolean, required:true},
|
||||
precision: {type: Number, default:5, required:false},
|
||||
})
|
||||
|
||||
const price = computed(()=>{
|
||||
const route = props.route;
|
||||
if( !route || !(route.pool in s.poolPrices) )
|
||||
return ''
|
||||
let p = s.poolPrices[route.pool]
|
||||
if( props.inverted )
|
||||
p = 1/p
|
||||
return p.toPrecision(props.precision)
|
||||
})
|
||||
|
||||
if( props.route )
|
||||
subPrices([props.route])
|
||||
else
|
||||
console.log('route is empty: no price')
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if( props.route )
|
||||
unsubPrices([props.route])
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "src/styles/vars" as *;
|
||||
</style>
|
||||
@@ -21,16 +21,17 @@
|
||||
{{ s.chain.name }}
|
||||
<v-img src="https://upload.wikimedia.org/wikipedia/commons/e/e7/Uniswap_Logo.svg" width="1.5em"/>
|
||||
<span class="uniswap-color ml-0 mr-1">v3</span>
|
||||
{{pairSymbol}} {{r.fee/10000}}%
|
||||
<span>{{pairSymbol}} {{r.fee/10000}}%</span>
|
||||
<route-price :route="r" :inverted="routeInverted(r)" class="text-green clickable" @click="inverted=!inverted"/>
|
||||
</v-chip>
|
||||
|
||||
<div v-if="routesPending">
|
||||
<v-progress-circular indeterminate/> Searching for {{pairSymbol}} pools...
|
||||
</div>
|
||||
|
||||
<v-alert v-if="routes.length===0 && !routeFinder.pending()" text="No pool found!"/>
|
||||
<v-alert v-if="!route && !routesPending" text="No pool found!"/>
|
||||
|
||||
<div v-if="routes.length">
|
||||
<div v-if="route && !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>
|
||||
@@ -59,7 +60,6 @@
|
||||
<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"
|
||||
variant="outlined" aria-valuemin="0" min="0"
|
||||
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
||||
@@ -68,8 +68,12 @@
|
||||
{{pairSymbol}}
|
||||
</v-btn>
|
||||
</template>
|
||||
<template #details style="flex-direction: column-reverse">
|
||||
<div>
|
||||
Current price <route-price :inverted="routeInverted(route)" :route="route" class="text-green"/>
|
||||
</div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
-->
|
||||
</div>
|
||||
|
||||
</v-card-text>
|
||||
@@ -89,12 +93,12 @@ import TokenChoice from "@/components/TokenChoice.vue"
|
||||
import PhoneCard from "@/components/PhoneCard.vue";
|
||||
// noinspection ES6UnusedImports
|
||||
import {SingletonCoroutine, vAutoSelect} from "@/misc.js";
|
||||
import {newOrder, newTimeConstraint, TimeMode} from "@/blockchain/orderlib.js";
|
||||
import {newLimitConstraint, newOrder, newTimeConstraint, sqrtX96, TimeMode} from "@/blockchain/orderlib.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {pendOrder} from "@/blockchain/wallet.js";
|
||||
import NeedsProvider from "@/components/NeedsProvider.vue";
|
||||
import {subPrices, unsubPrices} from "@/blockchain/prices.js";
|
||||
import {findRoute} from "@/blockchain/route.js";
|
||||
import RoutePrice from "@/components/RoutePrice.vue";
|
||||
|
||||
const s = useStore()
|
||||
const buy = ref(false)
|
||||
@@ -138,18 +142,20 @@ const routes = computed({
|
||||
return _routes.value
|
||||
},
|
||||
set(value) {
|
||||
console.log('setting new routes', value)
|
||||
subPrices(value)
|
||||
unsubPrices(_routes.value)
|
||||
console.log('setting new routes', _routes.value, value)
|
||||
_routes.value = value
|
||||
}
|
||||
})
|
||||
const route = computed(()=>_routes.value.length===0 ? null : _routes.value[0])
|
||||
const routesPending = ref(false)
|
||||
const amount = ref(100) // todo 0
|
||||
const amountIsTokenA = ref(false)
|
||||
const amountIsTotal = ref(true)
|
||||
const tranches = ref(3)
|
||||
const inverted = ref(false)
|
||||
function routeInverted(route) {
|
||||
return route && (route.token0 === tokenA.value) === inverted.value
|
||||
}
|
||||
const minPrice = ref(null)
|
||||
const maxPrice = ref(null)
|
||||
const limitPrice = ref(null)
|
||||
@@ -161,11 +167,6 @@ const limitIsMinimum = computed(() => !(buy.value ^ inverted.value))
|
||||
const validOrder = computed(()=>amount.value > 0 && routes.value.length > 0 )
|
||||
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
unsubPrices(_routes.value)
|
||||
})
|
||||
|
||||
|
||||
async function componentFindRoute() {
|
||||
console.log('finding route', _tokenA.value, _tokenB.value)
|
||||
routes.value = []
|
||||
@@ -271,11 +272,22 @@ function placeOrder() {
|
||||
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 ) {
|
||||
const inverted = routeInverted(route)
|
||||
const isAbove = limitIsMinimum.value ^ inverted
|
||||
const isRatio = false // todo ratios
|
||||
const decimals = 10 ** (tokenA.value.decimals - tokenB.value.decimals)
|
||||
const limit = inverted ? decimals/limitPrice.value : limitPrice.value/decimals
|
||||
priceConstraint = !limitPrice.value ? null : newLimitConstraint(isAbove, isRatio, limit)
|
||||
}
|
||||
for (let i = 0; i < n; i++) {
|
||||
const start = Math.floor(i * (duration / (n-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)
|
||||
ts.push([amtPerTranche, cs])
|
||||
}
|
||||
const order = newOrder(tokenIn, tokenOut, route.exchange, route.fee, amt, amountIsInput, ts)
|
||||
|
||||
Reference in New Issue
Block a user