101 lines
3.9 KiB
JavaScript
101 lines
3.9 KiB
JavaScript
import {socket} from "@/socket.js";
|
|
import {useStore} from "@/store/store.js";
|
|
import {Exchange} from "@/blockchain/orderlib.js";
|
|
import {uniswapV3PoolAddress} from "@/blockchain/uniswap.js";
|
|
import {ethers, FixedNumber} from "ethers";
|
|
import {uniswapV3PoolAbi} from "@/blockchain/abi.js";
|
|
import {subOHLCs} from "@/blockchain/ohlcs.js";
|
|
|
|
const subscriptionCounts = {} // key is route and value is a subscription counter
|
|
export const WIDE_PRICE_FORMAT = {decimals:38, width:512, signed:false}; // 38 decimals is 127 bits
|
|
|
|
|
|
export function subPrices( routes ) {
|
|
if( !routes.length )
|
|
return
|
|
const subRoutes = []
|
|
let chainId = null
|
|
for( const route of routes ) {
|
|
// console.log('sub route', route, subscriptionCounts)
|
|
const routeKey = [route.chainId, route.pool]
|
|
if( !(routeKey in subscriptionCounts) || subscriptionCounts[routeKey] === 0 ) {
|
|
subscriptionCounts[routeKey] = 1
|
|
subRoutes.push(route)
|
|
}
|
|
else {
|
|
subscriptionCounts[routeKey]++
|
|
}
|
|
if( chainId !== null && route.chainId !== chainId )
|
|
throw Error('cannot mix chainIds in a subscription list')
|
|
chainId = route.chainId
|
|
}
|
|
if( subRoutes.length ) {
|
|
const pools = routes.map((r)=>r.pool);
|
|
// console.log('subscribing to pools', pools)
|
|
socket.emit('subPools', chainId, pools )
|
|
// perform a local query if necessary
|
|
const s = useStore()
|
|
for( const route of subRoutes ) {
|
|
const routeKey = [route.chainId, route.pool]
|
|
if( !(routeKey in s.poolPrices) ) {
|
|
getPriceForRoute(route).then((price)=>s.poolPrices[routeKey]=price)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function unsubPrices( routes ) {
|
|
let chainId = null
|
|
const unsubAddrs = []
|
|
for( const route of routes ) {
|
|
// console.log('unsub route', route, subscriptionCounts)
|
|
const routeKey = [route.chainId, route.pool]
|
|
if( !(routeKey in subscriptionCounts) ) {
|
|
console.error('unsubscribed to a nonexistent route', route)
|
|
}
|
|
else {
|
|
subscriptionCounts[routeKey]--
|
|
if( subscriptionCounts[routeKey] === 0 ) {
|
|
unsubAddrs.push(route.pool)
|
|
if( chainId !== null && route.chainId !== chainId )
|
|
throw Error('cannot mix chainIds in a subscription list')
|
|
// console.log('unsubscribing from pool', route.pool)
|
|
chainId = route.chainId
|
|
}
|
|
else if( subscriptionCounts[routeKey] < 0 ) {
|
|
console.error('unsubscribed to an already unsubbed route', route)
|
|
subscriptionCounts[routeKey] = 0 // fix
|
|
}
|
|
}
|
|
}
|
|
if( unsubAddrs.length )
|
|
socket.emit('unsubPools', chainId, unsubAddrs )
|
|
}
|
|
|
|
|
|
async function getPriceForRoute(route) {
|
|
if( !route.token0 || !route.token1 )
|
|
return null
|
|
if( route.exchange === Exchange.UniswapV3 ) {
|
|
const addr = uniswapV3PoolAddress(route.chainId, route.token0.address, route.token1.address, route.fee)
|
|
const store = useStore();
|
|
const provider = store.provider;
|
|
if( provider === null ) {
|
|
console.error('provider was null during getPriceForRoute')
|
|
return null
|
|
}
|
|
const pool = new ethers.Contract(addr, uniswapV3PoolAbi, provider)
|
|
const got = await pool.slot0()
|
|
const [sqrtPrice,,,,,,] = got
|
|
const spn = BigInt(sqrtPrice)
|
|
let price = FixedNumber.fromValue(spn*spn, route.token1.decimals - route.token0.decimals, WIDE_PRICE_FORMAT)
|
|
price = price.div(FixedNumber.fromValue(2n**(96n*2n),0,WIDE_PRICE_FORMAT))
|
|
price = price.round(18).toString()
|
|
// console.log(`price for ${route.token0.symbol}/${route.token1.symbol}`,price)
|
|
store.poolPrices[[route.chainId,addr]] = price
|
|
return price
|
|
}
|
|
else
|
|
throw Error(`Unsupported exchange ${route.exchange}`)
|
|
}
|