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}`) }