chart-based route finding
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
import {Exchange} from "@/blockchain/orderlib.js";
|
import {Exchange} from "@/blockchain/orderlib.js";
|
||||||
|
import {useOrderStore, useStore} from "@/store/store.js";
|
||||||
|
import {queryHelperContract} from "@/blockchain/contract.js";
|
||||||
|
import {SingletonCoroutine} from "@/misc.js";
|
||||||
|
|
||||||
|
|
||||||
export async function findRoute(helper, chainId, tokenA, tokenB) {
|
export async function findRoute(helper, chainId, tokenA, tokenB) {
|
||||||
console.log('getting raw routes', helper, tokenA.address, tokenB.address)
|
console.log('getting raw routes', helper, tokenA.a, tokenB.a)
|
||||||
const rawRoutes = await helper.getRoutes(tokenA.address, tokenB.address)
|
const rawRoutes = await helper.getRoutes(tokenA.a, tokenB.a)
|
||||||
// todo expose all available pools
|
// todo expose all available pools
|
||||||
console.log('raw routes', rawRoutes)
|
console.log('raw routes', rawRoutes)
|
||||||
let result = null // we actually only find a single pool for now
|
let result = null // we actually only find a single pool for now
|
||||||
@@ -15,11 +18,41 @@ export async function findRoute(helper, chainId, tokenA, tokenB) {
|
|||||||
case 0: // UniswapV2
|
case 0: // UniswapV2
|
||||||
throw Error('Uniswap V2 not yet supported')
|
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 inverted = tokenA.a < tokenB.a;
|
||||||
result = {chainId, exchange: Exchange.UniswapV3, pool, fee, token0, token1}
|
const [token0, token1] = inverted ? [tokenA, tokenB] : [tokenB, tokenA]
|
||||||
|
result = {chainId, exchange: Exchange.UniswapV3, pool, fee, token0, token1, inverted}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result ? [result] : []
|
return result ? [result] : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function componentFindRoute() {
|
||||||
|
const s = useStore()
|
||||||
|
const os = useOrderStore()
|
||||||
|
const tokenA = os.tokenA
|
||||||
|
const tokenB = os.tokenB
|
||||||
|
os.routes = []
|
||||||
|
if (!tokenA || !tokenB)
|
||||||
|
return
|
||||||
|
console.log('finding route', s.chainId.value, tokenA, tokenB)
|
||||||
|
os.routesPending = true
|
||||||
|
try {
|
||||||
|
console.log('getting query helper')
|
||||||
|
const helper = await queryHelperContract(s.helper, s.provider)
|
||||||
|
if (!helper) {
|
||||||
|
console.log('no helper')
|
||||||
|
} else {
|
||||||
|
const result = await findRoute(helper, s.chainId.value, tokenA, tokenB)
|
||||||
|
console.log('found route', result)
|
||||||
|
os.routes = result
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('ignoring routes exception', e)
|
||||||
|
} finally {
|
||||||
|
os.routesPending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const routeFinder = new SingletonCoroutine(componentFindRoute, 10)
|
||||||
|
|||||||
@@ -131,7 +131,10 @@ async function _discoverVaults(owner) {
|
|||||||
console.error(`bad vault version ${version}`)
|
console.error(`bad vault version ${version}`)
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log(`no vault ${num} at ${addr}`, e)
|
if( e.value==='0x' && e.code==='BAD_DATA' )
|
||||||
|
console.log(`no vault ${num} at ${addr}`)
|
||||||
|
else
|
||||||
|
console.error(`routeFinder failed`, e)
|
||||||
}
|
}
|
||||||
if( s.account == owner ) { // double-check the account since it could have changed during our await
|
if( s.account == owner ) { // double-check the account since it could have changed during our await
|
||||||
s.vaults = result
|
s.vaults = result
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
import {useChartOrderStore} from "@/orderbuild.js";
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
import {invokeCallbacks, prototype} from "@/common.js";
|
import {invokeCallbacks, prototype} from "@/common.js";
|
||||||
import datafeed from "@/charts/datafeed.js";
|
import datafeed, {lookupSymbol} from "@/charts/datafeed.js";
|
||||||
|
|
||||||
export let widget = null
|
export let widget = null
|
||||||
export let chart = null
|
export let chart = null
|
||||||
export let crosshairPoint = null
|
export let crosshairPoint = null
|
||||||
|
let symbolChangedCbs = [] // callbacks for TV's chart.onSymbolChanged()
|
||||||
|
let lastSymbolChangedArgs = null
|
||||||
|
|
||||||
|
export function addSymbolChangedCallback(cb) {
|
||||||
|
symbolChangedCbs.push(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeSymbolChangedCallback(cb) {
|
||||||
|
symbolChangedCbs = symbolChangedCbs.filter((i)=>i!==cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeSymbol(symbol) {
|
||||||
|
console.log('tv changeSymbol', symbol)
|
||||||
|
const info = lookupSymbol(symbol.full_name)
|
||||||
|
lastSymbolChangedArgs = info
|
||||||
|
symbolChangedCbs.forEach((cb)=>cb(info))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const subscribeEvents = [
|
const subscribeEvents = [
|
||||||
'toggle_sidebar', 'indicators_dialog', 'toggle_header', 'edit_object_dialog', 'chart_load_requested',
|
'toggle_sidebar', 'indicators_dialog', 'toggle_header', 'edit_object_dialog', 'chart_load_requested',
|
||||||
@@ -51,7 +69,10 @@ function initChart() {
|
|||||||
console.log('init chart')
|
console.log('init chart')
|
||||||
chart = widget.activeChart()
|
chart = widget.activeChart()
|
||||||
chart.crossHairMoved().subscribe(null, (point)=>setTimeout(()=>handleCrosshairMovement(point),0) )
|
chart.crossHairMoved().subscribe(null, (point)=>setTimeout(()=>handleCrosshairMovement(point),0) )
|
||||||
|
chart.onSymbolChanged().subscribe(null, changeSymbol);
|
||||||
|
changeSymbol(chart.symbolExt())
|
||||||
useChartOrderStore().chartReady = true
|
useChartOrderStore().chartReady = true
|
||||||
|
console.log('chart ready')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ function addSymbol(p, base, quote, inverted) {
|
|||||||
const longExchange = ['Uniswap v2', 'Uniswap v3',][p.e]
|
const longExchange = ['Uniswap v2', 'Uniswap v3',][p.e]
|
||||||
const description = `${base.n} / ${quote.n}`
|
const description = `${base.n} / ${quote.n}`
|
||||||
const type = 'swap'
|
const type = 'swap'
|
||||||
_symbols[full_name] = {symbol, full_name, description, exchange, type, inverted,}
|
_symbols[full_name] = {symbol, full_name, description, exchange, type, inverted, base, quote}
|
||||||
indexes[full_name] = {
|
indexes[full_name] = {
|
||||||
// key
|
// key
|
||||||
id: full_name,
|
id: full_name,
|
||||||
@@ -84,7 +84,6 @@ function addSymbol(p, base, quote, inverted) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
async function getAllSymbols() {
|
async function getAllSymbols() {
|
||||||
|
|
||||||
if (_symbols===null) {
|
if (_symbols===null) {
|
||||||
_symbols = {}
|
_symbols = {}
|
||||||
for (const t of metadata.t)
|
for (const t of metadata.t)
|
||||||
@@ -112,6 +111,10 @@ async function getAllSymbols() {
|
|||||||
return _symbols
|
return _symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function lookupSymbol(fullName) {
|
||||||
|
return _symbols[fullName]
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onReady: (callback) => {
|
onReady: (callback) => {
|
||||||
console.log('[onReady]: Method call');
|
console.log('[onReady]: Method call');
|
||||||
|
|||||||
10
src/components/ChartPairSelector.vue
Normal file
10
src/components/ChartPairSelector.vue
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
11
src/components/NeedsChart.vue
Normal file
11
src/components/NeedsChart.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<slot v-if="co.chartReady"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
|
const co = useChartOrderStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
import TokenChoice from "@/components/TokenChoice.vue"
|
import TokenChoice from "@/components/TokenChoice.vue"
|
||||||
import {useOrderStore, useStore} from "@/store/store";
|
import {useOrderStore, useStore} from "@/store/store";
|
||||||
import RoutePrice from "@/components/RoutePrice.vue";
|
import RoutePrice from "@/components/RoutePrice.vue";
|
||||||
import {findRoute} from "@/blockchain/route.js";
|
import {findRoute, routeFinder} from "@/blockchain/route.js";
|
||||||
import {SingletonCoroutine, routeInverted} from "@/misc.js";
|
import {SingletonCoroutine, routeInverted} from "@/misc.js";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import {queryHelperContract} from "@/blockchain/contract.js";
|
import {queryHelperContract} from "@/blockchain/contract.js";
|
||||||
@@ -46,7 +46,7 @@ const tokenA = computed({
|
|||||||
return os.tokenA
|
return os.tokenA
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
if( !os.tokenA || os.tokenA.address !== value.address ) {
|
if( !os.tokenA || os.tokenA.a !== value.a ) {
|
||||||
os.tokenA = value
|
os.tokenA = value
|
||||||
routeFinder.invoke()
|
routeFinder.invoke()
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ const tokenB = computed({
|
|||||||
return os.tokenB
|
return os.tokenB
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
if( !os.tokenB || os.tokenB.address !== value.address ) {
|
if( !os.tokenB || os.tokenB.a !== value.address ) {
|
||||||
os.tokenB = value
|
os.tokenB = value
|
||||||
routeFinder.invoke()
|
routeFinder.invoke()
|
||||||
}
|
}
|
||||||
@@ -75,36 +75,6 @@ const routes = computed({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function componentFindRoute() {
|
|
||||||
const tokenA = os.tokenA
|
|
||||||
const tokenB = os.tokenB
|
|
||||||
os.routes = []
|
|
||||||
if (!tokenA || !tokenB)
|
|
||||||
return
|
|
||||||
console.log('finding route', s.chainId.value, tokenA, tokenB)
|
|
||||||
os.routesPending = true
|
|
||||||
try {
|
|
||||||
console.log('getting query helper')
|
|
||||||
const helper = await queryHelperContract(s.helper, s.provider)
|
|
||||||
if (!helper) {
|
|
||||||
console.log('no helper')
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const result = await findRoute(helper, s.chainId.value, tokenA, tokenB)
|
|
||||||
console.log('found route', result)
|
|
||||||
os.routes = result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.log('ignoring routes exception', e)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
os.routesPending = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const routeFinder = new SingletonCoroutine(componentFindRoute,10)
|
|
||||||
routeFinder.invoke()
|
routeFinder.invoke()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,25 @@
|
|||||||
import {useChartOrderStore} from "@/orderbuild.js";
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
import Toolbar from "@/components/chart/Toolbar.vue";
|
import Toolbar from "@/components/chart/Toolbar.vue";
|
||||||
import BuilderFactory from "@/components/chart/BuilderFactory.vue";
|
import BuilderFactory from "@/components/chart/BuilderFactory.vue";
|
||||||
|
import {addSymbolChangedCallback, removeSymbolChangedCallback} from "@/charts/chart.js";
|
||||||
|
import {onBeforeUnmount} from "vue";
|
||||||
|
import {useOrderStore} from "@/store/store.js";
|
||||||
|
|
||||||
|
import {routeFinder} from "@/blockchain/route.js";
|
||||||
|
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
|
const os = useOrderStore()
|
||||||
|
|
||||||
|
function changeSymbol(symbol) {
|
||||||
|
console.log('changeSymbol', symbol)
|
||||||
|
os.tokenA = symbol.base
|
||||||
|
os.tokenB = symbol.quote
|
||||||
|
routeFinder.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const oldSymbolChanged = addSymbolChangedCallback(changeSymbol)
|
||||||
|
onBeforeUnmount(() => removeSymbolChangedCallback(changeSymbol) )
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ export function timestamp(date=null) {
|
|||||||
|
|
||||||
|
|
||||||
export function pairKey(tokenA, tokenB) {
|
export function pairKey(tokenA, tokenB) {
|
||||||
const token0 = tokenA.address < tokenB.address ? tokenA.address : tokenB.address
|
const token0 = tokenA.a < tokenB.a ? tokenA.a : tokenB.a
|
||||||
const token1 = tokenA.address > tokenB.address ? tokenA.address : tokenB.address
|
const token1 = tokenA.a > tokenB.a ? tokenA.a : tokenB.a
|
||||||
return [token0, token1];
|
return [token0, token1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function applyLine(tranche, intercept, slope, isMinimum = null) {
|
|||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
const route = os.route
|
const route = os.route
|
||||||
const inverted = routeInverted(route)
|
const inverted = routeInverted(route)
|
||||||
const scale = 10 ** (os.tokenA.decimals - os.tokenB.decimals)
|
const scale = 10 ** (os.tokenA.d - os.tokenB.d)
|
||||||
let m = inverted ? -scale / slope : slope / scale
|
let m = inverted ? -scale / slope : slope / scale
|
||||||
let b = inverted ? scale / intercept : intercept / scale
|
let b = inverted ? scale / intercept : intercept / scale
|
||||||
const cur = b + timestamp() * m
|
const cur = b + timestamp() * m
|
||||||
|
|||||||
0
src/routeFinder.js
Normal file
0
src/routeFinder.js
Normal file
@@ -1,5 +1,17 @@
|
|||||||
const versionPromise = fetch('/version.json').then(async (response)=>await response.json())
|
function _json(name) {
|
||||||
const metadataPromise = fetch('/metadata.json').then(async (response)=>await response.json())
|
return async function(response) {
|
||||||
|
try {
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(`could not read ${name}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionPromise = fetch('/version.json').then(_json('version.json'))
|
||||||
|
const metadataPromise = fetch('/metadata.json').then(_json('metadata.json'))
|
||||||
|
|
||||||
export const version = await versionPromise
|
export const version = await versionPromise
|
||||||
console.log('version', version)
|
console.log('version', version)
|
||||||
|
|||||||
Reference in New Issue
Block a user