price constraints working
This commit is contained in:
@@ -9,8 +9,7 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="app" class="app"></div>
|
<div id="app"></div>
|
||||||
<script src="/version.js"></script>
|
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ export const erc20Abi = [
|
|||||||
'event Approval(address indexed,address indexed,uint256)',
|
'event Approval(address indexed,address indexed,uint256)',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const mockErc20Abi = [...erc20Abi,
|
||||||
|
'function mint(address,uint256)',
|
||||||
|
]
|
||||||
|
|
||||||
const Route = '(uint8,uint24)'
|
const Route = '(uint8,uint24)'
|
||||||
const Constraint = '(uint8,bytes)'
|
const Constraint = '(uint8,bytes)'
|
||||||
const Tranche = `(uint64,${Constraint}[])`
|
const Tranche = `(uint64,${Constraint}[])`
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import {uint32max, uint64max} from "@/misc.js";
|
import {uint32max, uint64max} from "@/misc.js";
|
||||||
import {ethers} from "ethers";
|
import {ethers} from "ethers";
|
||||||
|
|
||||||
@@ -49,18 +48,14 @@ export const Exchange = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enum ConstraintMode {
|
// enum ConstraintMode {
|
||||||
// Time, // 0
|
// Time, // 0
|
||||||
// Limit, // 1
|
// Line, // 1
|
||||||
// Trailing, // 2
|
// Barrier // 2
|
||||||
// Barrier, // 3
|
|
||||||
// Line // 4
|
|
||||||
// }
|
// }
|
||||||
export const ConstraintMode = {
|
export const ConstraintMode = {
|
||||||
Time: 0,
|
Time: 0,
|
||||||
Limit: 1,
|
Line: 1,
|
||||||
Trailing: 2,
|
Barrier: 2,
|
||||||
Barrier: 3,
|
|
||||||
Line: 4,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct Constraint {
|
// struct Constraint {
|
||||||
@@ -98,12 +93,6 @@ export function newTimeConstraint(startMode, start, endMode, end) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct PriceConstraint {
|
|
||||||
// bool isAbove;
|
|
||||||
// bool isRatio;
|
|
||||||
// uint160 valueSqrtX96;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// struct LineConstraint {
|
// struct LineConstraint {
|
||||||
// bool isAbove;
|
// bool isAbove;
|
||||||
// bool isRatio;
|
// bool isRatio;
|
||||||
@@ -112,3 +101,19 @@ export function newTimeConstraint(startMode, start, endMode, end) {
|
|||||||
// int160 slopeSqrtX96; // price change per second
|
// int160 slopeSqrtX96; // price change per second
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
export function newLimitConstraint( isAbove, isRatio, price ) {
|
||||||
|
return newLineConstraint(isAbove, isRatio, 0, price, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function newLineConstraint( isAbove, isRatio, time, price, slope ) {
|
||||||
|
return encodeConstraint(
|
||||||
|
ConstraintMode.Line,
|
||||||
|
['bool', 'bool', 'uint32', 'uint160', 'int160'],
|
||||||
|
[isAbove, isRatio, time, sqrtX96(price), sqrtX96(slope)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sqrtX96(value) {
|
||||||
|
return BigInt(Math.round(Math.sqrt(value * 2 ** (96*2))))
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,35 +2,40 @@ import {socket} from "@/socket.js";
|
|||||||
import {useStore} from "@/store/store.js";
|
import {useStore} from "@/store/store.js";
|
||||||
import {Exchange} from "@/blockchain/orderlib.js";
|
import {Exchange} from "@/blockchain/orderlib.js";
|
||||||
import {uniswapV3PoolAddress} from "@/blockchain/uniswap.js";
|
import {uniswapV3PoolAddress} from "@/blockchain/uniswap.js";
|
||||||
import {ethers, FixedNumber} from "ethers";
|
import {ethers} from "ethers";
|
||||||
import {erc20Abi, uniswapV3PoolAbi} from "@/blockchain/abi.js";
|
import {uniswapV3PoolAbi} from "@/blockchain/abi.js";
|
||||||
|
|
||||||
const subs = {} // key is route and value is a subscription counter
|
const subscriptionCounts = {} // key is route and value is a subscription counter
|
||||||
|
|
||||||
|
|
||||||
export function subPrices( routes ) {
|
export function subPrices( routes ) {
|
||||||
|
if( !routes.length )
|
||||||
|
return
|
||||||
const subRoutes = []
|
const subRoutes = []
|
||||||
let chainId = null
|
let chainId = null
|
||||||
for( const route of routes ) {
|
for( const route of routes ) {
|
||||||
if( !(route in subRoutes) || subRoutes[route] === 0 ) {
|
console.log('sub route', route, subscriptionCounts)
|
||||||
subRoutes[route] = 1
|
if( !(route in subscriptionCounts) || subscriptionCounts[route] === 0 ) {
|
||||||
|
subscriptionCounts[route] = 1
|
||||||
console.log('subscribing to pool', route.pool)
|
console.log('subscribing to pool', route.pool)
|
||||||
subRoutes.push(route)
|
subRoutes.push(route)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
subRoutes[route]++
|
subscriptionCounts[route]++
|
||||||
if( chainId !== null && route.chainId !== chainId )
|
|
||||||
throw Error('cannot mix chainIds in a subscription list')
|
|
||||||
chainId = route.chainId
|
|
||||||
}
|
}
|
||||||
|
if( chainId !== null && route.chainId !== chainId )
|
||||||
|
throw Error('cannot mix chainIds in a subscription list')
|
||||||
|
chainId = route.chainId
|
||||||
}
|
}
|
||||||
if( subRoutes.length ) {
|
if( subRoutes.length ) {
|
||||||
socket.emit('subPools', chainId, routes.map((r)=>r.address) )
|
socket.emit('subPools', chainId, routes.map((r)=>r.pool) )
|
||||||
// perform a local query if necessary
|
// perform a local query if necessary
|
||||||
for( const route of subRoutes ) {
|
for( const route of subRoutes ) {
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
if( !(route.address in s.poolPrices) ) {
|
console.log('route in prices?', route.pool in s.poolPrices, route.pool, s.poolPrices)
|
||||||
getPriceForRoute(route).then((price)=>s.poolPrices[route.address]=price)
|
if( !(route.pool in s.poolPrices) ) {
|
||||||
|
console.log('querying initial route price', route.pool)
|
||||||
|
getPriceForRoute(route).then((price)=>s.poolPrices[route.pool]=price)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,21 +45,22 @@ export function unsubPrices( routes ) {
|
|||||||
let chainId = null
|
let chainId = null
|
||||||
const unsubAddrs = []
|
const unsubAddrs = []
|
||||||
for( const route of routes ) {
|
for( const route of routes ) {
|
||||||
if( !(route in subs) ) {
|
console.log('unsub route', route, subscriptionCounts)
|
||||||
|
if( !(route in subscriptionCounts) ) {
|
||||||
console.error('unsubscribed to a nonexistent route', route)
|
console.error('unsubscribed to a nonexistent route', route)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
subs[route]--
|
subscriptionCounts[route]--
|
||||||
if( subs[route] === 0 ) {
|
if( subscriptionCounts[route] === 0 ) {
|
||||||
unsubAddrs.push(route.pool)
|
unsubAddrs.push(route.pool)
|
||||||
if( chainId !== null && route.chainId !== chainId )
|
if( chainId !== null && route.chainId !== chainId )
|
||||||
throw Error('cannot mix chainIds in a subscription list')
|
throw Error('cannot mix chainIds in a subscription list')
|
||||||
console.log('unsubscribing from pool', route.pool)
|
console.log('unsubscribing from pool', route.pool)
|
||||||
chainId = route.chainId
|
chainId = route.chainId
|
||||||
}
|
}
|
||||||
else if( subs[route] < 0 ) {
|
else if( subscriptionCounts[route] < 0 ) {
|
||||||
console.error('unsubscribed to an already unsubbed route', route)
|
console.error('unsubscribed to an already unsubbed route', route)
|
||||||
subs[route] = 0 // fix
|
subscriptionCounts[route] = 0 // fix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +73,8 @@ async function getPriceForRoute(route) {
|
|||||||
console.log('route is',route)
|
console.log('route is',route)
|
||||||
if( route.exchange === Exchange.UniswapV3 ) {
|
if( route.exchange === Exchange.UniswapV3 ) {
|
||||||
const addr = uniswapV3PoolAddress(route.chainId, route.token0.address, route.token1.address, route.fee)
|
const addr = uniswapV3PoolAddress(route.chainId, route.token0.address, route.token1.address, route.fee)
|
||||||
const provider = useStore().provider;
|
const store = useStore();
|
||||||
|
const provider = store.provider;
|
||||||
if( provider === null ) {
|
if( provider === null ) {
|
||||||
console.error('provider was null during getPriceForRoute')
|
console.error('provider was null during getPriceForRoute')
|
||||||
return null
|
return null
|
||||||
@@ -78,6 +85,8 @@ async function getPriceForRoute(route) {
|
|||||||
const spn = Number(sqrtPrice)
|
const spn = Number(sqrtPrice)
|
||||||
const price = spn*spn/2**(96*2) * 10**(route.token0.decimals-route.token1.decimals)
|
const price = spn*spn/2**(96*2) * 10**(route.token0.decimals-route.token1.decimals)
|
||||||
console.log(`price for ${route.token0.symbol}/${route.token1.symbol}`,price)
|
console.log(`price for ${route.token0.symbol}/${route.token1.symbol}`,price)
|
||||||
|
store.poolPrices[addr] = price
|
||||||
|
return price
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error(`Unsupported exchange ${route.exchange}`)
|
throw Error(`Unsupported exchange ${route.exchange}`)
|
||||||
|
|||||||
@@ -10,14 +10,15 @@ export async function findRoute(tokenA, tokenB) {
|
|||||||
const chainId = useStore().chainId
|
const chainId = useStore().chainId
|
||||||
const rawRoutes = await helper.getRoutes(tokenA.address, tokenB.address)
|
const rawRoutes = await helper.getRoutes(tokenA.address, tokenB.address)
|
||||||
// todo expose all available pools
|
// todo expose all available pools
|
||||||
let result = {} // we actually only find a single pool for now
|
console.log('raw routes', rawRoutes)
|
||||||
|
let result = null // we actually only find a single pool for now
|
||||||
for (let [exchange, fee, pool] of rawRoutes) {
|
for (let [exchange, fee, pool] of rawRoutes) {
|
||||||
exchange = Number(exchange)
|
exchange = Number(exchange)
|
||||||
fee = Number(fee)
|
fee = Number(fee)
|
||||||
if (result.fee === undefined || result.fee > fee) {
|
if (!result || result.fee > fee) {
|
||||||
switch (exchange) {
|
switch (exchange) {
|
||||||
case 0: // UniswapV2
|
case 0: // UniswapV2
|
||||||
break
|
throw Error('Uniswap V2 not yet supported')
|
||||||
case 1: // UniswapV3
|
case 1: // UniswapV3
|
||||||
const [token0, token1] = tokenA.address < tokenB.address ? [tokenA, tokenB] : [tokenB, tokenA]
|
const [token0, token1] = tokenA.address < tokenB.address ? [tokenA, tokenB] : [tokenB, tokenA]
|
||||||
result = {chainId, exchange: Exchange.UniswapV3, pool, fee, token0, token1}
|
result = {chainId, exchange: Exchange.UniswapV3, pool, fee, token0, token1}
|
||||||
@@ -25,5 +26,5 @@ export async function findRoute(tokenA, tokenB) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [result]
|
return result ? [result] : []
|
||||||
}
|
}
|
||||||
|
|||||||
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>
|
<template>
|
||||||
<!-- tablets and desktops get a card outline -->
|
<!-- todo use javascript media breakpoint instead of display classes so we dont double-render the slot -->
|
||||||
<v-card class="d-none d-sm-block phone-card" :elevation="4">
|
<div>
|
||||||
<slot/>
|
<!-- tablets and desktops get a card outline -->
|
||||||
</v-card>
|
<v-card class="d-none d-sm-block phone-card" :elevation="4">
|
||||||
<!-- phones use the entire screen -->
|
<slot/>
|
||||||
<v-container class="d-sm-none">
|
</v-card>
|
||||||
<slot/>
|
<!-- phones use the entire screen -->
|
||||||
</v-container>
|
<v-container class="d-sm-none">
|
||||||
|
<slot/>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<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 }}
|
{{ s.chain.name }}
|
||||||
<v-img src="https://upload.wikimedia.org/wikipedia/commons/e/e7/Uniswap_Logo.svg" width="1.5em"/>
|
<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>
|
<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>
|
</v-chip>
|
||||||
|
|
||||||
<div v-if="routesPending">
|
<div v-if="routesPending">
|
||||||
<v-progress-circular indeterminate/> Searching for {{pairSymbol}} pools...
|
<v-progress-circular indeterminate/> Searching for {{pairSymbol}} pools...
|
||||||
</div>
|
</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-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
|
||||||
v-model="amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
v-model="amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
||||||
<template v-slot:append-inner>
|
<template v-slot:append-inner>
|
||||||
@@ -59,7 +60,6 @@
|
|||||||
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
|
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
<!--
|
|
||||||
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
||||||
variant="outlined" aria-valuemin="0" min="0"
|
variant="outlined" aria-valuemin="0" min="0"
|
||||||
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
||||||
@@ -68,8 +68,12 @@
|
|||||||
{{pairSymbol}}
|
{{pairSymbol}}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</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>
|
</v-text-field>
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@@ -89,12 +93,12 @@ import TokenChoice from "@/components/TokenChoice.vue"
|
|||||||
import PhoneCard from "@/components/PhoneCard.vue";
|
import PhoneCard from "@/components/PhoneCard.vue";
|
||||||
// noinspection ES6UnusedImports
|
// noinspection ES6UnusedImports
|
||||||
import {SingletonCoroutine, vAutoSelect} from "@/misc.js";
|
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 {FixedNumber} from "ethers";
|
||||||
import {pendOrder} from "@/blockchain/wallet.js";
|
import {pendOrder} from "@/blockchain/wallet.js";
|
||||||
import NeedsProvider from "@/components/NeedsProvider.vue";
|
import NeedsProvider from "@/components/NeedsProvider.vue";
|
||||||
import {subPrices, unsubPrices} from "@/blockchain/prices.js";
|
|
||||||
import {findRoute} from "@/blockchain/route.js";
|
import {findRoute} from "@/blockchain/route.js";
|
||||||
|
import RoutePrice from "@/components/RoutePrice.vue";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
const buy = ref(false)
|
const buy = ref(false)
|
||||||
@@ -138,18 +142,20 @@ const routes = computed({
|
|||||||
return _routes.value
|
return _routes.value
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
console.log('setting new routes', value)
|
console.log('setting new routes', _routes.value, value)
|
||||||
subPrices(value)
|
|
||||||
unsubPrices(_routes.value)
|
|
||||||
_routes.value = value
|
_routes.value = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const route = computed(()=>_routes.value.length===0 ? null : _routes.value[0])
|
||||||
const routesPending = ref(false)
|
const routesPending = ref(false)
|
||||||
const amount = ref(100) // todo 0
|
const amount = ref(100) // todo 0
|
||||||
const amountIsTokenA = ref(false)
|
const amountIsTokenA = ref(false)
|
||||||
const amountIsTotal = ref(true)
|
const amountIsTotal = ref(true)
|
||||||
const tranches = ref(3)
|
const tranches = ref(3)
|
||||||
const inverted = ref(false)
|
const inverted = ref(false)
|
||||||
|
function routeInverted(route) {
|
||||||
|
return route && (route.token0 === tokenA.value) === inverted.value
|
||||||
|
}
|
||||||
const minPrice = ref(null)
|
const minPrice = ref(null)
|
||||||
const maxPrice = ref(null)
|
const maxPrice = ref(null)
|
||||||
const limitPrice = 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 )
|
const validOrder = computed(()=>amount.value > 0 && routes.value.length > 0 )
|
||||||
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
unsubPrices(_routes.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
async function componentFindRoute() {
|
async function componentFindRoute() {
|
||||||
console.log('finding route', _tokenA.value, _tokenB.value)
|
console.log('finding route', _tokenA.value, _tokenB.value)
|
||||||
routes.value = []
|
routes.value = []
|
||||||
@@ -271,11 +272,22 @@ function placeOrder() {
|
|||||||
const amtPerTranche = oneHundredPercent / BigInt(n) + ceil
|
const amtPerTranche = oneHundredPercent / BigInt(n) + ceil
|
||||||
duration -= 15 // subtract 15 seconds so the last tranche completes before the deadline
|
duration -= 15 // subtract 15 seconds so the last tranche completes before the deadline
|
||||||
console.log('duration', duration)
|
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++) {
|
for (let i = 0; i < n; i++) {
|
||||||
const start = Math.floor(i * (duration / (n-1)))
|
const start = Math.floor(i * (duration / (n-1)))
|
||||||
const end = start + window
|
const end = start + window
|
||||||
console.log('tranche window', start, end, (end-start)/60)
|
console.log('tranche window', start, end, (end-start)/60)
|
||||||
const cs = [newTimeConstraint(TimeMode.SinceOrderStart, start, TimeMode.SinceOrderStart, end)]
|
const cs = [newTimeConstraint(TimeMode.SinceOrderStart, start, TimeMode.SinceOrderStart, end)]
|
||||||
|
if( priceConstraint !== null )
|
||||||
|
cs.push(priceConstraint)
|
||||||
ts.push([amtPerTranche, cs])
|
ts.push([amtPerTranche, cs])
|
||||||
}
|
}
|
||||||
const order = newOrder(tokenIn, tokenOut, route.exchange, route.fee, amt, amountIsInput, ts)
|
const order = newOrder(tokenIn, tokenOut, route.exchange, route.fee, amt, amountIsInput, ts)
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ socket.on('p', async (pool, price) => {
|
|||||||
const s = useStore()
|
const s = useStore()
|
||||||
const prices = {}
|
const prices = {}
|
||||||
prices[pool] = price
|
prices[pool] = price
|
||||||
s.$patch({poolPrices: prices})
|
console.log('pool price', pool, price)
|
||||||
|
const poolPrices = s.poolPrices
|
||||||
|
poolPrices[pool] = price
|
||||||
|
s.poolPrices = poolPrices
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('vb', async (vault, balances) => {
|
socket.on('vb', async (vault, balances) => {
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ export const useStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
factory: (s)=>!s.chain?null:s.chain.factory,
|
factory: (s)=>!s.chain?null:s.chain.factory,
|
||||||
helper: (s)=>!s.chain?null:s.chain.helper,
|
helper: (s)=>!s.chain?null:s.chain.helper,
|
||||||
|
mockenv: (s)=>!s.chain?null:s.chain.mockenv,
|
||||||
|
mockCoins: (s)=>!s.chain?[]:!s.chain.mockCoins?[]:s.chain.mockCoins,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
removeTransactionSender(sender) {
|
removeTransactionSender(sender) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@use "/src/styles/vars" as v;
|
@use "/src/styles/vars" as v;
|
||||||
|
|
||||||
.app {
|
#app {
|
||||||
.clickable {
|
.clickable {
|
||||||
:hover {
|
:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- todo needs account -->
|
<!-- todo needs account -->
|
||||||
<needs-signer>
|
<needs-signer>
|
||||||
<Vault :owner="s.account" :num="0"/>
|
<vault :owner="s.account" :num="0"/>
|
||||||
|
<faucet class="mt-3"/>
|
||||||
</needs-signer>
|
</needs-signer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
import {useStore} from "@/store/store";
|
import {useStore} from "@/store/store";
|
||||||
import Vault from "@/components/Vault.vue";
|
import Vault from "@/components/Vault.vue";
|
||||||
import NeedsSigner from "@/components/NeedsSigner.vue";
|
import NeedsSigner from "@/components/NeedsSigner.vue";
|
||||||
|
import Faucet from "@/components/Faucet.vue";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user