diff --git a/src/anchorParsers.ts b/src/anchorParsers.ts index 0b7fd38..8489ffd 100644 --- a/src/anchorParsers.ts +++ b/src/anchorParsers.ts @@ -4,6 +4,7 @@ import { I80F48, IDL, IDS, + PerpEventLayout, PerpMarketConfig, } from "@blockworks-foundation/mango-client"; import { Coder } from "@project-serum/anchor"; @@ -107,10 +108,7 @@ export function anchorParser(parsedTransactions, result, signature, blockTime, s blockDatetime ) ); - } else if ( - eventName === "DepositLog" || - eventName === "WithdrawLog" - ) { + } else if (eventName === "DepositLog" || eventName === "WithdrawLog") { parsedTransactions.deposits_withdraws.push( parseDepositWithDraw( eventNum, @@ -229,7 +227,7 @@ export function anchorParser(parsedTransactions, result, signature, blockTime, s ) ); } else if (eventName === "UpdateFundingLog") { - parsedTransactions.updating_funding.push( + parsedTransactions.funding.push( parseUpdateFunding( eventNum, eventData, @@ -239,13 +237,213 @@ export function anchorParser(parsedTransactions, result, signature, blockTime, s blockDatetime ) ); - } - // else { - // throw new Error("Unknown anchor event: " + eventName); - // } + } else if (eventName === "UpdateRootBankLog") { + parsedTransactions.cache_indexes.push( + parseUpdateRootBank( + eventNum, + eventData, + signature, + blockTime, + slot, + blockDatetime + ) + ) + } else if (eventName === "CachePerpMarketsLog") { + parsedTransactions.funding.push( + ...parseCachePerpMarkets( + eventNum, + eventData, + signature, + blockTime, + slot, + blockDatetime + ) + ) + } else if (eventName === "OpenOrdersBalanceLog") { + parsedTransactions.open_orders_balances.push( + parseOpenOrdersBalance( + eventNum, + eventData, + signature, + blockTime, + slot, + blockDatetime + ) + ) + } else if (eventName === "MngoAccrualLog") { + parsedTransactions.mango_accrual.push( + parseMngoAccrual( + eventNum, + eventData, + signature, + blockTime, + slot, + blockDatetime + ) + ) + } else { + throw new Error("Unknown anchor event: " + eventName); + } } } +function parseMngoAccrual( + instructionNum, + eventData, + signature, + blockTime, + slot, + blockDatetime + ) { + + const config = new Config(IDS); + + const groupConfig = config.groups.find((g) => + g.publicKey.equals(eventData.mangoGroup) + ) as GroupConfig; + + let perpMarketConfig = groupConfig.perpMarkets.find( + (p) => p.marketIndex === eventData.marketIndex.toNumber() + ) as PerpMarketConfig; + + let mangoAccrual = new I80F48(eventData.mngoAccrual).toNumber() + + return { + margin_account: eventData.mangoAccount.toString(), + perp_market: perpMarketConfig.name, + base_symbol: perpMarketConfig.baseSymbol, + mango_accrual: mangoAccrual, + + instruction_num: instructionNum, + mango_group: eventData.mangoGroup.toString(), + block_datetime: blockDatetime, + slot: slot, + signature: signature, + blocktime: blockTime, + } + +} + +function parseOpenOrdersBalance( + instructionNum, + eventData, + signature, + blockTime, + slot, + blockDatetime +) { + + let mangoGroup = eventData.mangoGroup.toString() + let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroup)[ + "tokens" + ]; + + let tokenIndex = eventData.marketIndex.toNumber() + let tokenPk = tokenIndexesMap[mangoGroup][tokenIndex]; + let token = tokens.find((e) => e["mintKey"] === tokenPk); + let symbol = token.symbol; + + let baseFree = new I80F48(eventData.baseFree).toNumber() + let baseTotal = new I80F48(eventData.baseTotal).toNumber() + let quoteFree = new I80F48(eventData.quoteFree).toNumber() + let quoteTotal = new I80F48(eventData.quoteTotal).toNumber() + let referrerRebatesAccrued = new I80F48(eventData.referrerRebatesAccrued).toNumber() + let marginAccount = eventData.mangoAccount.toString() + + return { + margin_account: marginAccount, + symbol: symbol, + baseFree: baseFree, + baseTotal: baseTotal, + quoteFree: quoteFree, + quoteTotal: quoteTotal, + referrerRebatesAccrued: referrerRebatesAccrued, + instruction_num: instructionNum, + + mango_group: mangoGroup, + block_datetime: blockDatetime, + slot: slot, + signature: signature, + blocktime: blockTime, + } +} + +function parseUpdateRootBank( + instructionNum, + eventData, + signature, + blockTime, + slot, + blockDatetime +) { + + let mangoGroupPk = eventData.mangoGroup.toString(); + + let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[ + "tokens" + ]; + + let tokenIndex = eventData.tokenIndex.toNumber(); + let depositIndex = new I80F48(eventData.depositIndex).toNumber() + let borrowIndex = new I80F48(eventData.borrowIndex).toNumber() + + let tokenPk = tokenIndexesMap[mangoGroupPk][tokenIndex]; + let token = tokens.find((e) => e["mintKey"] === tokenPk); + let symbol = token.symbol; + + return { + symbol: symbol, + deposit_index: depositIndex, + borrow_index: borrowIndex, + instruction_num: instructionNum, + mango_group: mangoGroupPk, + block_datetime: blockDatetime, + slot: slot, + signature: signature, + blocktime: blockTime, + } +} + +function parseCachePerpMarkets( + instructionNum, + eventData, + signature, + blockTime, + slot, + blockDatetime +) { + + const config = new Config(IDS); + + const groupConfig = config.groups.find((g) => + g.publicKey.equals(eventData.mangoGroup) + ) as GroupConfig; + + let out: any = [] + for (let i=0; i p.marketIndex === marketIndex + ) as PerpMarketConfig; + + out.push( + { + symbol: perpMarketConfig.baseSymbol, + long_funding: new I80F48(eventData.longFundings[i]).toNumber(), + short_funding: new I80F48(eventData.shortFundings[i]).toNumber(), + instruction_num: instructionNum, + mango_group: eventData.mangoGroup.toString(), + block_datetime: blockDatetime, + slot: slot, + signature: signature, + blocktime: blockTime, + } + ) + } + + return out +} + function parseFillLog( instructionNum, eventData, @@ -262,8 +460,6 @@ function parseFillLog( let marketIndex = eventData.marketIndex.toNumber(); let perpMarket = perpMarkets.find((e) => e["marketIndex"] === marketIndex); - // console.log("parseFillLog data: ", eventData) - const fill = { event_num: instructionNum, maker: eventData.maker.toString(), @@ -288,8 +484,7 @@ function parseFillLog( }; // TODO: verify i80f48 conversions - // console.log("parsed fill: ", fill) - + return fill; } diff --git a/src/index.ts b/src/index.ts index ff26cfc..5c81787 100644 --- a/src/index.ts +++ b/src/index.ts @@ -110,7 +110,7 @@ async function processMangoTransactions( let res; try { res = await client.query( - 'select transaction, slot, signature from ' + + 'select transaction, signature from ' + schema + ".transactions where process_state = 'ready for parsing' and program_pk = $1 limit $2", [address, limit], diff --git a/src/jsonParsers.ts b/src/jsonParsers.ts index 5874d7a..fcfe633 100644 --- a/src/jsonParsers.ts +++ b/src/jsonParsers.ts @@ -518,9 +518,9 @@ function extractSettleFees( maker_fee: eventDetails['maker_fee'], maker_order_id: eventDetails['maker_order_id'], - // TODO: Ask Daffy about the source of these multipliers - price: eventDetails['price'] / 10, - quantity: eventDetails['quantity'] / 10000, + // Storing both price and quantity in UI terms to be consistent with db + price: eventDetails['price'] / perpMarket.quoteLotSize, + quantity: eventDetails['quantity'] * perpMarket.baseLotSize / Math.pow(10, perpMarket.quoteDecimals), seq_num: eventDetails['seq_num'], taker: eventDetails['taker'], diff --git a/src/parseTransactions.ts b/src/parseTransactions.ts index 18a8ace..90cea67 100644 --- a/src/parseTransactions.ts +++ b/src/parseTransactions.ts @@ -37,8 +37,9 @@ export function parseTransactions(transactionsResult, mangoProgramId) { net_balances: [], redeem_mngo: [], funding: [], - // @clarkeni: new log added OpenOrdersBalanceLog - // @clarkeni: new log added MngoAccrual + + open_orders_balances: [], + mango_accrual: [], // Mango: PlacePerpOrder // Mango: CancelPerpOrderByClientI // Mango: CancelPerpOrder diff --git a/src/tests/testParseTransactions.ts b/src/tests/testParseTransactions.ts index d69eaef..5ea5276 100644 --- a/src/tests/testParseTransactions.ts +++ b/src/tests/testParseTransactions.ts @@ -25,7 +25,7 @@ async function processMangoTransactions(rawTransactionsPool, schema, limit) { '3bzj3KkA3FSZHJuCmRgHhSgqeaEzD32sCHkYdRLcZm1vcuB4ra5NbU5EZqBhW6QjeKRV9QRWC4SHxK2hS54s79Zx', // settle_pnl '5TmhvKQJmjUD9dZgCszBF8gNKUohpxwjrYu1RngZVh1hEToGMtjPtXJF89QLHXzANMWWQRfMomsgCg8353CpYgBb', // settle_fees 'mxK5eEiEUeCcQtHwmUKziyYUZJ3NXdjmZigAR6npWgcpQoJtqvikt5A7osD4y6oiLZJhzYFvqAqDznFjHm77K8V', // settle_fees called but nothing settled - '4qV6PTD1nGj5qq89FQK8QKwN231pGgtayD7uX4B6y83b19gcVXB5ByLCvApSJjCRrboiCg7RVT2p2e1CtP3zuXDb', // force_settle_quote_positions + // '4qV6PTD1nGj5qq89FQK8QKwN231pGgtayD7uX4B6y83b19gcVXB5ByLCvApSJjCRrboiCg7RVT2p2e1CtP3zuXDb', // force_settle_quote_positions '5qDPBrFjCcaZthjRCqisHRw1mFEkHFHRFWi5jbKCmpAgpAXNdEkSv8L472D12VB5AukYaGsWhAy5bcvvUGJ1Sgtv', // FillEvent '3YXaEG95w5eG7jBBjz8hW9auXVAv9z2MH8yw51tL8nqSqmKgXtrD1hgE7LCqK2hpFwcrpjeWtBeVqGsbCHLh3kSe', // redeem mango '2HNnZmThkFUsG1pw9bNaJoeeGUZJun3hkcpwBJt3ZU9FKe3CY17wrJgk1BZ8txm13RJ512ThbZVZxaqsxNFn4xVs', // checked_add_net details