import {orderFilled, orderStatuses, vaultOpenOrders, vaultRecentlyClosedOrders} from "./cache.js" import {sql} from "./db.js"; export function sendVaultOrders( socket, chainId, vault ) { Promise.all([ vaultOpenOrders.get(chainId, vault, '[]'), vaultRecentlyClosedOrders.get(chainId, vault, '[]'), archivedOrders(chainId, vault), ]).then(async (got)=>{ const [openIndexes, closedIndexes, recents] = got const statuses = {} // noinspection JSCheckFunctionSignatures const indexes = [...JSON.parse(openIndexes), ...JSON.parse(closedIndexes)] const proms = [] if( openIndexes !== null ) { for (const orderIndex of indexes) { // there is a race condition here since we need multiple queries to get the complete order status, // so we check for nulls and exclude such an order, since it was deleted and no longer active. proms.push(orderStatus(chainId, vault, orderIndex).then((status)=>{ if (status !== null) statuses[orderIndex] = status })) } } for( let [orderIndex, status] of recents ) { if( !(orderIndex in statuses) ) { // only write the database version if there's no open order in the memcache const orderKey = `${vault}|${orderIndex}` proms.push(fillOrderStatus(chainId, orderKey, status)) statuses[orderIndex] = status } } await Promise.all(proms) const result = [] for(const index of Object.keys(statuses)) result.push([parseInt(index), statuses[index]]) socket.emit('os', chainId, vault, result) }) } export function unsubVaultOrders( socket, chainId, vault ) { console.log('todo: unsubVaultOrders') // todo } export async function orderStatus( chainId, vault, orderIndex ) { const orderKey = `${vault}|${orderIndex}` let status = await orderStatuses.get(chainId, orderKey) if( status === null ) { console.warn(`Could not find order status for ${chainId}|${vault}|${orderIndex}`) } else { status = JSON.parse(status) await fillOrderStatus(chainId, orderKey, status) } return status } async function fillOrderStatus(chainId, orderKey, status ) { const fills = await orderFilled.get(chainId, orderKey) if (fills !== null) applyFillsServer(status, JSON.parse(fills)) } export async function archivedOrders(chainId, vault, limit=100 ) { const query = await sql( `select oi.order_index, sd.value from seriesdict sd, orderindex oi where oi.chain = ${chainId} and oi.vault = '${vault}' and sd.series = 'o' and sd.key = concat('${vault}', '|', to_char(oi.order_index, 'FM9999999999999999999')) order by oi.order_index desc limit ${limit}` ) const result = [] for( const {order_index, value} of query.rows) result.push([order_index,JSON.parse(value)]) return result } export function applyFillsServer(orderStatus, orderFills) { // class ElaboratedTrancheStatus: // filledIn: int // filledOut: int // activationTime: int // startTime: int // endTime: int // fills: list[Fill] // // class Fill: // tx: str // time: int // filledIn: int // filledOut: int // fee: int // console.log('apply fills OrderStatus', orderStatus) // console.log('apply fills orderFills', orderFills) const trancheStatus = orderStatus[9] let orderIn = 0n let orderOut = 0n for (const i in orderFills) { let filledIn = 0n let filledOut = 0n const [activationTime, fills] = orderFills[i]; for (const fill of fills) { filledIn += BigInt(fill[2]) filledOut += BigInt(fill[3]) } const old = trancheStatus[i] const startTime = old[3] const endTime = old[4] trancheStatus[i] = [filledIn.toString(), filledOut.toString(), activationTime, startTime, endTime, fills] orderIn += filledIn orderOut += filledOut } orderStatus[7] = orderIn.toString() orderStatus[8] = orderOut.toString() // console.log('apply fills final', orderStatus, orderStatus[1][8]) }