2021-10-17 21:50:48 -07:00
|
|
|
import {
|
|
|
|
Config,
|
|
|
|
GroupConfig,
|
|
|
|
I80F48,
|
|
|
|
IDL,
|
|
|
|
IDS,
|
2021-10-17 23:21:27 -07:00
|
|
|
PerpEventLayout,
|
2021-10-17 21:50:48 -07:00
|
|
|
PerpMarketConfig,
|
|
|
|
} from "@blockworks-foundation/mango-client";
|
|
|
|
import { Coder } from "@project-serum/anchor";
|
2021-10-18 22:45:06 -07:00
|
|
|
import { getLatestObjPerCombination } from './utils';
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
// Unfortunately ids.json does not correspond to the token indexes in the log - so keep a map here for reference
|
|
|
|
// mango group -> token index -> mint key
|
|
|
|
// TODO: is there a better way?
|
|
|
|
var tokenIndexesMap = {
|
|
|
|
'98pjRuQjK3qA6gXts96PqZT4Ze5QmnCmt3QYjhbUSPue': {
|
|
|
|
0: 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac',
|
|
|
|
1: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
|
|
|
2: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
|
|
|
3: 'So11111111111111111111111111111111111111112',
|
|
|
|
4: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
|
|
5: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt',
|
|
|
|
6: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
|
|
|
|
7: '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
|
|
|
|
15: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
|
},
|
|
|
|
'4yJ2Vx3kZnmHTNCrHzdoj5nCwriF2kVhfKNvqC6gU8tr': {
|
|
|
|
0: 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac',
|
|
|
|
1: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E',
|
|
|
|
2: '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk',
|
|
|
|
3: 'So11111111111111111111111111111111111111112',
|
|
|
|
4: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt',
|
|
|
|
5: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
|
|
15: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// mango group -> token index -> mint key
|
|
|
|
var oracleIndexesMap = {
|
|
|
|
'98pjRuQjK3qA6gXts96PqZT4Ze5QmnCmt3QYjhbUSPue': {
|
|
|
|
0: '49cnp1ejyvQi3CJw3kKXNCDGnNbWDuZd3UG3Y2zGvQkX',
|
|
|
|
1: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
|
|
|
|
2: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
|
|
|
|
3: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
|
|
|
|
4: '3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL',
|
|
|
|
5: '3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym',
|
|
|
|
6: 'AnLf8tVYCM816gmBjiy8n53eXKKEDydT5piYjjQDPgTB',
|
|
|
|
7: '9xYBiDWYsh2fHzpsz3aaCnNHCKWBNtfEDLtU6kS4aFD9',
|
|
|
|
},
|
|
|
|
'4yJ2Vx3kZnmHTNCrHzdoj5nCwriF2kVhfKNvqC6gU8tr': {
|
|
|
|
0: '49cnp1ejyvQi3CJw3kKXNCDGnNbWDuZd3UG3Y2zGvQkX',
|
|
|
|
1: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
|
|
|
|
2: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
|
|
|
|
3: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
|
|
|
|
4: '3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym',
|
|
|
|
5: '3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-10-18 22:45:06 -07:00
|
|
|
// Lot sizes also not available on ids.json
|
|
|
|
// mango group -> perp name -> lot sizes
|
|
|
|
var perpLotSizes = {
|
|
|
|
'98pjRuQjK3qA6gXts96PqZT4Ze5QmnCmt3QYjhbUSPue': {
|
|
|
|
'BTC-PERP': {
|
|
|
|
'baseLotSize': 100,
|
|
|
|
'quoteLotSize': 10
|
|
|
|
},
|
|
|
|
'SOL-PERP': {
|
|
|
|
'baseLotSize': 10000000,
|
|
|
|
'quoteLotSize': 100
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
var ids = IDS;
|
|
|
|
|
|
|
|
export function anchorParser(parsedTransactions, result, signature, blockTime, slot, blockDatetime) {
|
|
|
|
|
|
|
|
let serializedLogMessages: any = [];
|
|
|
|
const coder = new Coder(IDL);
|
|
|
|
|
|
|
|
for (let i = 0; i < result.meta.logMessages.length; i++) {
|
|
|
|
const logMessage = result.meta.logMessages[i];
|
|
|
|
const jsonStartStr = "Program log: mango-log";
|
|
|
|
|
|
|
|
if (logMessage.startsWith(jsonStartStr)) {
|
|
|
|
const serializedMangoLog = result.meta.logMessages[i + 1].slice(
|
|
|
|
"Program log: ".length
|
|
|
|
);
|
|
|
|
serializedLogMessages.push(serializedMangoLog);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can have multiple inserts per signature so add instructionNum column to allow a primary key
|
|
|
|
let eventNum = 1;
|
|
|
|
|
2021-10-18 22:45:06 -07:00
|
|
|
let allNetBalances: any = [];
|
2021-10-17 21:50:48 -07:00
|
|
|
for (const log of serializedLogMessages) {
|
|
|
|
const decodedEvent = coder.events.decode(log);
|
|
|
|
const eventName = decodedEvent?.name;
|
|
|
|
const eventData = decodedEvent?.data as any;
|
|
|
|
|
|
|
|
if (eventName === "CachePricesLog") {
|
|
|
|
parsedTransactions.cache_prices.push(
|
|
|
|
...parseCachePrices(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "CacheRootBanksLog") {
|
|
|
|
parsedTransactions.cache_indexes.push(
|
|
|
|
...parseCacheRootBanks(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
2021-10-17 23:21:27 -07:00
|
|
|
} else if (eventName === "DepositLog" || eventName === "WithdrawLog") {
|
2021-10-17 21:50:48 -07:00
|
|
|
parsedTransactions.deposits_withdraws.push(
|
|
|
|
parseDepositWithDraw(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
eventName,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "TokenBalanceLog") {
|
2021-10-18 22:45:06 -07:00
|
|
|
// Net balances is a special case - we only want to keep the latest change to net balance for each
|
|
|
|
// (mangoAccount, symbol) pair in each transaction
|
|
|
|
allNetBalances.push(
|
2021-10-17 21:50:48 -07:00
|
|
|
parseTokenBalance(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "RedeemMngoLog") {
|
|
|
|
parsedTransactions.redeem_mngo.push(
|
|
|
|
parseRedeemMngo(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "FillLog") {
|
|
|
|
parsedTransactions.fill_events.push(
|
|
|
|
parseFillLog(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "LiquidateTokenAndTokenLog") {
|
|
|
|
parsedTransactions.liquidate_token_and_token.push(
|
|
|
|
parseLiquidateTokenAndToken(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "LiquidateTokenAndPerpLog") {
|
|
|
|
parsedTransactions.liquidate_token_and_perp.push(
|
|
|
|
parseLiquidateTokenAndPerp(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "LiquidatePerpMarketLog") {
|
|
|
|
parsedTransactions.liquidate_perp_market.push(
|
|
|
|
parseLiquidatePerpMarket(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "TokenBankruptcyLog") {
|
|
|
|
parsedTransactions.token_bankruptcy.push(
|
|
|
|
parseTokenBankruptcy(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "PerpBankruptcyLog") {
|
|
|
|
const [perpBankruptcyRow, updateFundingRow] = parsePerpBankruptcy(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
);
|
|
|
|
parsedTransactions.perp_bankruptcy.push(perpBankruptcyRow);
|
2021-11-01 14:34:33 -07:00
|
|
|
parsedTransactions.funding.push(updateFundingRow);
|
2021-10-17 21:50:48 -07:00
|
|
|
} else if (eventName === "SettlePnlLog") {
|
|
|
|
parsedTransactions.settle_pnl.push(
|
|
|
|
...parseSettlePnl(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "SettleFeesLog") {
|
2021-10-18 22:45:06 -07:00
|
|
|
parsedTransactions.settle_fees.push(
|
2021-10-17 21:50:48 -07:00
|
|
|
parseSettleFees(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else if (eventName === "UpdateFundingLog") {
|
2021-10-17 23:21:27 -07:00
|
|
|
parsedTransactions.funding.push(
|
2021-10-17 21:50:48 -07:00
|
|
|
parseUpdateFunding(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
);
|
2021-10-17 23:21:27 -07:00
|
|
|
} else if (eventName === "UpdateRootBankLog") {
|
|
|
|
parsedTransactions.cache_indexes.push(
|
|
|
|
parseUpdateRootBank(
|
|
|
|
eventNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else if (eventName === "CachePerpMarketsLog") {
|
2021-11-01 14:34:33 -07:00
|
|
|
// pass - logging from CachePerpMarkets is redundant - can just log from updateFunding
|
|
|
|
|
|
|
|
// parsedTransactions.funding.push(
|
|
|
|
// ...parseCachePerpMarkets(
|
|
|
|
// eventNum,
|
|
|
|
// eventData,
|
|
|
|
// signature,
|
|
|
|
// blockTime,
|
|
|
|
// slot,
|
|
|
|
// blockDatetime
|
|
|
|
// )
|
|
|
|
// )
|
2021-10-17 23:21:27 -07:00
|
|
|
} 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);
|
|
|
|
}
|
2021-10-18 22:45:06 -07:00
|
|
|
|
|
|
|
eventNum++;
|
2021-10-17 21:50:48 -07:00
|
|
|
}
|
2021-10-18 22:45:06 -07:00
|
|
|
|
|
|
|
// Extract the latest (mangoAccount, symbol) pair from net balances changes in the transaction
|
|
|
|
parsedTransactions.net_balances.push(...getLatestObjPerCombination(allNetBalances, ['mango_account','symbol']))
|
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
}
|
|
|
|
|
2021-10-17 23:21:27 -07:00
|
|
|
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;
|
|
|
|
|
2021-10-18 14:15:48 -07:00
|
|
|
let mangoDecimals = groupConfig.tokens.find((e) => e["symbol"] === 'MNGO')!.decimals
|
2021-10-18 22:45:06 -07:00
|
|
|
let mangoAccrualUi = eventData.mngoAccrual.toNumber() / Math.pow(10, mangoDecimals)
|
2021-10-17 23:21:27 -07:00
|
|
|
|
|
|
|
return {
|
|
|
|
margin_account: eventData.mangoAccount.toString(),
|
|
|
|
perp_market: perpMarketConfig.name,
|
|
|
|
base_symbol: perpMarketConfig.baseSymbol,
|
2021-10-18 14:15:48 -07:00
|
|
|
mango_accrual: mangoAccrualUi,
|
2021-10-17 23:21:27 -07:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-10-18 14:15:48 -07:00
|
|
|
let baseDecimals = token.decimals
|
|
|
|
// Assuming that quote currency is always USDC
|
|
|
|
let quoteDecimals = tokens.find((e) => e.symbol === 'USDC').decimals;
|
|
|
|
|
2021-10-18 22:45:06 -07:00
|
|
|
let baseFree = eventData.baseFree.toNumber() / Math.pow(10, baseDecimals)
|
|
|
|
let baseTotal = eventData.baseTotal.toNumber() / Math.pow(10, baseDecimals)
|
|
|
|
let quoteFree = eventData.quoteFree.toNumber() / Math.pow(10, quoteDecimals)
|
|
|
|
let quoteTotal = eventData.quoteTotal.toNumber() / Math.pow(10, quoteDecimals)
|
|
|
|
let referrerRebatesAccrued = eventData.referrerRebatesAccrued.toNumber() / Math.pow(10, quoteDecimals)
|
2021-10-17 23:21:27 -07:00
|
|
|
let marginAccount = eventData.mangoAccount.toString()
|
|
|
|
|
|
|
|
return {
|
|
|
|
margin_account: marginAccount,
|
|
|
|
symbol: symbol,
|
2021-10-18 22:45:06 -07:00
|
|
|
base_free: baseFree,
|
|
|
|
base_total: baseTotal,
|
|
|
|
quote_free: quoteFree,
|
|
|
|
quote_total: quoteTotal,
|
|
|
|
referrer_rebates_accrued: referrerRebatesAccrued,
|
2021-10-17 23:21:27 -07:00
|
|
|
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<eventData.marketIndexes.length; i++) {
|
|
|
|
let marketIndex = eventData.marketIndexes[i].toNumber()
|
|
|
|
let perpMarketConfig = groupConfig.perpMarkets.find(
|
|
|
|
(p) => 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
|
|
|
|
}
|
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
function parseFillLog(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
// instructionNum is used here to form a primary key on the db table (with signature)
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
let marketIndex = eventData.marketIndex.toNumber();
|
|
|
|
let perpMarket = perpMarkets.find((e) => e["marketIndex"] === marketIndex);
|
2021-10-18 22:45:06 -07:00
|
|
|
|
|
|
|
let lotSizes = perpLotSizes[mangoGroupPk][perpMarket.name]
|
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
const fill = {
|
|
|
|
event_num: instructionNum,
|
|
|
|
maker: eventData.maker.toString(),
|
|
|
|
maker_fee: new I80F48(eventData.makerFee).toNumber(),
|
2021-10-18 22:45:06 -07:00
|
|
|
maker_order_id: eventData.makerOrderId.toString(),
|
|
|
|
price: eventData.price.toNumber() / lotSizes.quoteLotSize,
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
// Storing both price and quantity in UI terms to be consistent with db
|
2021-10-18 22:45:06 -07:00
|
|
|
quantity: eventData.quantity.toNumber() * lotSizes.baseLotSize / Math.pow(10, perpMarket.baseDecimals),
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
seq_num: eventData.seqNum.toNumber(),
|
|
|
|
taker: eventData.taker.toString(),
|
|
|
|
taker_fee: new I80F48(eventData.takerFee).toNumber(),
|
2021-10-18 22:45:06 -07:00
|
|
|
taker_order_id: eventData.takerOrderId.toString(),
|
|
|
|
taker_side: eventData.takerSide === 0 ? 'bid' : 'ask',
|
|
|
|
|
|
|
|
perp_market: perpMarket.name,
|
|
|
|
base_symbol: perpMarket.baseSymbol,
|
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
2021-10-18 22:45:06 -07:00
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
return fill;
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseSettleFees(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let mangoAccount = eventData.mangoAccount.toString();
|
|
|
|
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
|
|
|
|
let marketIndex = eventData.marketIndex.toNumber();
|
|
|
|
let perpMarket = perpMarkets.find((e) => e["marketIndex"] === marketIndex);
|
|
|
|
let perpMarketName = perpMarket.name;
|
|
|
|
|
|
|
|
// TODO: confirm correct conversion from i80f48
|
|
|
|
let settlement =
|
|
|
|
new I80F48(eventData.settlement).toNumber() /
|
|
|
|
Math.pow(10, perpMarket.quoteDecimals);
|
|
|
|
|
|
|
|
return {
|
|
|
|
margin_account: mangoAccount,
|
|
|
|
settlement: settlement,
|
|
|
|
perp_market_name: perpMarketName,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseSettlePnl(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
|
|
|
|
let mangoAccountA = eventData.mangoAccountA.toString();
|
|
|
|
let mangoAccountB = eventData.mangoAccountB.toString();
|
|
|
|
let marketIndex = eventData.marketIndex.toNumber();
|
|
|
|
let perpMarket = perpMarkets.find((e) => e["marketIndex"] === marketIndex);
|
|
|
|
let perpMarketName = perpMarket.name;
|
|
|
|
let settlement = new I80F48(eventData.settlement).toNumber();
|
|
|
|
|
|
|
|
// A's quote position is reduced by settlement and B's quote position is increased by settlement
|
|
|
|
let settlementA = (-1 * settlement) / Math.pow(10, perpMarket.quoteDecimals);
|
|
|
|
let settlementB = settlement / Math.pow(10, perpMarket.quoteDecimals);
|
|
|
|
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
margin_account: mangoAccountA,
|
|
|
|
settlement: settlementA,
|
|
|
|
perp_market_name: perpMarketName,
|
|
|
|
counterparty: mangoAccountB,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
margin_account: mangoAccountB,
|
|
|
|
settlement: settlementB,
|
|
|
|
perp_market_name: perpMarketName,
|
|
|
|
counterparty: mangoAccountA,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
function parsePerpBankruptcy(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
const config = new Config(IDS);
|
|
|
|
|
|
|
|
const groupConfig = config.groups.find((g) =>
|
|
|
|
g.publicKey.equals(eventData.mangoGroup)
|
|
|
|
) as GroupConfig;
|
|
|
|
const perpMarketConfig = groupConfig.perpMarkets.find(
|
|
|
|
(p) => p.marketIndex === eventData.liabIndex.toNumber()
|
|
|
|
) as PerpMarketConfig;
|
|
|
|
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let liqee = eventData.liqee.toString();
|
|
|
|
let liqor = eventData.liqor.toString();
|
|
|
|
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroupPk)
|
|
|
|
["tokens"].find((e) => e.symbol === quoteSymbol).decimals;
|
|
|
|
|
|
|
|
let liabIndex = eventData.liabIndex.toNumber();
|
|
|
|
let perpMarket = perpMarkets.find((e) => e["marketIndex"] === liabIndex);
|
|
|
|
let perpMarketName = perpMarket.name;
|
|
|
|
|
|
|
|
let insuranceFundTransfer =
|
|
|
|
eventData.insuranceTransfer.toNumber() / Math.pow(10, quoteDecimals);
|
|
|
|
|
|
|
|
// loss is on quote position
|
|
|
|
let loss =
|
|
|
|
new I80F48(eventData.socializedLoss).toNumber() /
|
|
|
|
Math.pow(10, quoteDecimals);
|
|
|
|
|
|
|
|
// TODO: are these needed? db columns don't exist
|
|
|
|
const cacheLongFunding = new I80F48(eventData.cacheLongFunding).toNumber();
|
|
|
|
const cacheShortFunding = new I80F48(eventData.cacheShortFunding).toNumber();
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
liqor: liqor,
|
|
|
|
liqee: liqee,
|
|
|
|
perp_market_name: perpMarketName,
|
|
|
|
insurance_fund_transfer: insuranceFundTransfer,
|
|
|
|
loss: loss,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
symbol: perpMarketConfig.baseSymbol,
|
|
|
|
long_funding: cacheLongFunding,
|
|
|
|
short_funding: cacheShortFunding,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseTokenBankruptcy(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let liqee = eventData.liqee.toString();
|
|
|
|
let liqor = eventData.liqor.toString();
|
|
|
|
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"tokens"
|
|
|
|
];
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroupPk)
|
|
|
|
["tokens"].find((e) => e.symbol === quoteSymbol).decimals;
|
|
|
|
|
|
|
|
// Either bankruptcy or socialized loss (or both) will be logged
|
|
|
|
// So initialize variables as null - nulls can be outputted to json if variables are not set
|
|
|
|
let symbol;
|
|
|
|
let insuranceFundTransfer: number | null = null;
|
|
|
|
let loss: number | null = null;
|
|
|
|
let percentageLoss: number | null = null;
|
|
|
|
let depositIndex: number | null = null;
|
|
|
|
|
|
|
|
// TODO: validate this when an example comes along
|
|
|
|
|
|
|
|
let tokenIndex = eventData.liabIndex.toNumber();
|
|
|
|
let tokenPk = tokenIndexesMap[mangoGroupPk][tokenIndex];
|
|
|
|
let token = tokens.find((e) => e["mintKey"] === tokenPk);
|
|
|
|
symbol = token.symbol;
|
|
|
|
|
|
|
|
insuranceFundTransfer =
|
|
|
|
eventData.insuranceTransfer.toNumber() / Math.pow(10, quoteDecimals);
|
|
|
|
loss = eventData.socializedLoss.toNumber() / Math.pow(10, token.decimals);
|
|
|
|
percentageLoss = eventData.percentageLoss.toNumber();
|
|
|
|
symbol = token.symbol;
|
|
|
|
|
|
|
|
// TODO: is this needed? didn't see it in the logs
|
|
|
|
// depositIndex = socializedLossDetails["deposit_index"]
|
|
|
|
|
|
|
|
return {
|
|
|
|
liqor: liqor,
|
|
|
|
liqee: liqee,
|
|
|
|
symbol: symbol,
|
|
|
|
insurance_fund_transfer: insuranceFundTransfer,
|
|
|
|
loss: loss,
|
|
|
|
percentage_loss: percentageLoss,
|
|
|
|
deposit_index: depositIndex,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseLiquidatePerpMarket(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let liqee = eventData.liqee.toString();
|
|
|
|
let liqor = eventData.liqor.toString();
|
|
|
|
let marketIndex = eventData.marketIndex.toNumber();
|
|
|
|
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
|
|
|
|
let perpMarket = perpMarkets.find((e) => e["marketIndex"] === marketIndex);
|
|
|
|
let perpMarketName = perpMarket.name;
|
|
|
|
let liabDecimals = perpMarket.baseDecimals;
|
|
|
|
let assetDecimals = perpMarket.quoteDecimals;
|
|
|
|
|
|
|
|
let liabSymbol = perpMarket.baseSymbol;
|
|
|
|
let assetSymbol = quoteSymbol;
|
|
|
|
let baseTransfer =
|
|
|
|
eventData.baseTransfer.toNumber() / Math.pow(10, liabDecimals);
|
|
|
|
// TODO: quoteTransfer is -base_transfer * pmi.base_lot_size - but I don't really know what this means
|
|
|
|
let quoteTransfer =
|
|
|
|
new I80F48(eventData.quoteTransfer).toNumber() /
|
|
|
|
Math.pow(10, assetDecimals);
|
|
|
|
let bankruptcy = eventData.bankruptcy;
|
|
|
|
|
|
|
|
return {
|
|
|
|
liqor: liqor,
|
|
|
|
liqee: liqee,
|
|
|
|
perp_market: perpMarketName,
|
|
|
|
liab_symbol: liabSymbol,
|
|
|
|
liab_amount: baseTransfer,
|
|
|
|
asset_symbol: assetSymbol,
|
|
|
|
asset_amount: quoteTransfer,
|
|
|
|
bankruptcy: bankruptcy,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseLiquidateTokenAndPerp(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let liqee = eventData.liqee.toString();
|
|
|
|
let liqor = eventData.liqor.toString();
|
|
|
|
let assetIndex = eventData.assetIndex.toNumber();
|
|
|
|
let liabIndex = eventData.liabIndex.toNumber();
|
|
|
|
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"tokens"
|
|
|
|
];
|
|
|
|
let perpMarkets = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"perpMarkets"
|
|
|
|
];
|
|
|
|
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroupPk)
|
|
|
|
["tokens"].find((e) => e.symbol === quoteSymbol).decimals;
|
|
|
|
|
|
|
|
let perpMarket;
|
|
|
|
let assetSymbol;
|
|
|
|
let liabSymbol;
|
|
|
|
|
2021-10-19 09:12:57 -07:00
|
|
|
let assetType = eventData.assetType === 0 ? 'Token': 'Perp';
|
|
|
|
let liabType = eventData.liabType === 0 ? 'Token': 'Perp';
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
let assetDecimals;
|
|
|
|
let liabDecimals;
|
|
|
|
let assetTokenPk = tokenIndexesMap[mangoGroupPk][assetIndex];
|
|
|
|
let assetToken = tokens.find((e) => e["mintKey"] === assetTokenPk);
|
|
|
|
let liabTokenPk = tokenIndexesMap[mangoGroupPk][liabIndex];
|
|
|
|
let liabToken = tokens.find((e) => e["mintKey"] === liabTokenPk);
|
|
|
|
|
|
|
|
if (assetType === "Token") {
|
|
|
|
// asset is token and liab is perp
|
|
|
|
assetSymbol = assetToken.symbol;
|
|
|
|
assetDecimals = assetToken.decimals;
|
|
|
|
|
|
|
|
let liabPerpMarket = perpMarkets.find(
|
|
|
|
(e) => e["marketIndex"] === liabIndex
|
|
|
|
);
|
|
|
|
// Liquidation can only occur on quote position on perp side
|
|
|
|
// So I'll set the asset symbol to the quote symbol (as that is what is transferred)
|
|
|
|
liabSymbol = quoteSymbol;
|
|
|
|
liabDecimals = liabPerpMarket.quoteDecimals;
|
|
|
|
perpMarket = liabPerpMarket.name;
|
|
|
|
} else {
|
|
|
|
// asset is perp and liab is token
|
|
|
|
let assetPerpMarket = perpMarkets.find(
|
|
|
|
(e) => e["marketIndex"] === assetIndex
|
|
|
|
);
|
|
|
|
// Liquidation can only occur on quote position on perp side
|
|
|
|
// So I'll set the asset symbol to the quote symbol (as that is what is transferred)
|
|
|
|
assetSymbol = quoteSymbol;
|
|
|
|
assetDecimals = assetPerpMarket.quoteDecimals;
|
|
|
|
perpMarket = assetPerpMarket.name;
|
|
|
|
|
|
|
|
liabSymbol = liabToken.symbol;
|
|
|
|
liabDecimals = liabToken.decimals;
|
|
|
|
}
|
|
|
|
|
|
|
|
let assetPrice =
|
|
|
|
new I80F48(eventData.assetPrice).toNumber() *
|
2021-10-19 09:12:57 -07:00
|
|
|
Math.pow(10, assetDecimals - quoteDecimals);
|
2021-10-17 21:50:48 -07:00
|
|
|
let liabPrice =
|
|
|
|
new I80F48(eventData.liabPrice).toNumber() *
|
2021-10-19 09:12:57 -07:00
|
|
|
Math.pow(10, liabDecimals - quoteDecimals);
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
let assetTransfer =
|
|
|
|
new I80F48(eventData.assetTransfer).toNumber() /
|
2021-10-19 09:12:57 -07:00
|
|
|
Math.pow(10, assetDecimals);
|
2021-10-17 21:50:48 -07:00
|
|
|
let liabTransfer =
|
|
|
|
new I80F48(eventData.liabTransfer).toNumber() /
|
2021-10-19 09:12:57 -07:00
|
|
|
Math.pow(10, liabDecimals);
|
2021-10-17 21:50:48 -07:00
|
|
|
|
|
|
|
return {
|
|
|
|
liqor: liqor,
|
|
|
|
liqee: liqee,
|
|
|
|
perp_market: perpMarket,
|
|
|
|
liab_symbol: liabSymbol,
|
|
|
|
liab_amount: liabTransfer,
|
|
|
|
liab_price: liabPrice,
|
|
|
|
liab_type: liabType,
|
|
|
|
asset_symbol: assetSymbol,
|
|
|
|
asset_amount: assetTransfer,
|
|
|
|
asset_price: assetPrice,
|
|
|
|
asset_type: assetType,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseLiquidateTokenAndToken(
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroup = eventData.mangoGroup.toString();
|
|
|
|
let liqee = eventData.liqee.toString();
|
|
|
|
let liqor = eventData.liqor.toString();
|
|
|
|
let assetIndex = eventData.assetIndex.toNumber();
|
|
|
|
let liabIndex = eventData.liabIndex.toNumber();
|
|
|
|
|
|
|
|
let assetToken = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroup)
|
|
|
|
["tokens"].find(
|
|
|
|
(e) => e.mintKey === tokenIndexesMap[mangoGroup][assetIndex]
|
|
|
|
);
|
|
|
|
let liabToken = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroup)
|
|
|
|
["tokens"].find(
|
|
|
|
(e) => e.mintKey === tokenIndexesMap[mangoGroup][liabIndex]
|
|
|
|
);
|
|
|
|
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroup)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroup)
|
|
|
|
["tokens"].find((e) => e.symbol === quoteSymbol).decimals;
|
|
|
|
|
|
|
|
let assetPrice =
|
|
|
|
new I80F48(eventData.assetPrice).toNumber() *
|
|
|
|
Math.pow(10, assetToken.decimals - quoteDecimals);
|
|
|
|
let liabPrice =
|
|
|
|
new I80F48(eventData.liabPrice).toNumber() *
|
|
|
|
Math.pow(10, liabToken.decimals - quoteDecimals);
|
|
|
|
|
|
|
|
// TODO: confirm that this is correct
|
|
|
|
let assetTransfer =
|
|
|
|
new I80F48(eventData.assetTransfer).toNumber() /
|
|
|
|
Math.pow(10, assetToken.decimals);
|
|
|
|
let liabTransfer =
|
|
|
|
new I80F48(eventData.liabTransfer).toNumber() /
|
|
|
|
Math.pow(10, liabToken.decimals);
|
|
|
|
|
|
|
|
let bankruptcy = eventData.bankruptcy;
|
|
|
|
|
|
|
|
return {
|
|
|
|
liqor: liqor,
|
|
|
|
liqee: liqee,
|
|
|
|
liab_symbol: liabToken.symbol,
|
|
|
|
liab_amount: liabTransfer,
|
|
|
|
liab_price: liabPrice,
|
|
|
|
asset_symbol: assetToken.symbol,
|
|
|
|
asset_amount: assetTransfer,
|
|
|
|
asset_price: assetPrice,
|
|
|
|
bankruptcy: bankruptcy,
|
|
|
|
mango_group: mangoGroup,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseRedeemMngo(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroup = eventData.mangoGroup.toString();
|
|
|
|
let marginAccount = eventData.mangoAccount.toString();
|
|
|
|
|
|
|
|
let decimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroup)
|
|
|
|
["tokens"].find((e) => e.symbol === "MNGO").decimals;
|
|
|
|
|
|
|
|
let quantity = eventData.redeemedMngo.toNumber() / Math.pow(10, decimals);
|
|
|
|
|
|
|
|
return {
|
|
|
|
margin_account: marginAccount,
|
|
|
|
quantity: quantity,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroup,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseDepositWithDraw(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
eventName,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroup = eventData.mangoGroup.toString();
|
|
|
|
let marginAccount = eventData.mangoAccount.toString();
|
|
|
|
let owner = eventData.owner.toString();
|
|
|
|
let tokenIndex = eventData.tokenIndex.toNumber();
|
|
|
|
let nativeQuantity = eventData.quantity.toNumber();
|
|
|
|
|
|
|
|
let side;
|
|
|
|
if (eventName === "DepositLog") {
|
|
|
|
side = "Deposit";
|
|
|
|
} else if (eventName === "WithdrawLog") {
|
|
|
|
side = "Withdraw";
|
|
|
|
}
|
|
|
|
|
|
|
|
let tokenPk = tokenIndexesMap[mangoGroup][tokenIndex];
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroup)[
|
|
|
|
"tokens"
|
|
|
|
];
|
|
|
|
let token = tokens.find((e) => e["mintKey"] === tokenPk);
|
|
|
|
let mintDecimals = token.decimals;
|
|
|
|
let symbol = token.symbol;
|
|
|
|
|
|
|
|
let quantity = nativeQuantity / Math.pow(10, mintDecimals);
|
|
|
|
|
|
|
|
return {
|
|
|
|
margin_account: marginAccount,
|
|
|
|
owner: owner,
|
|
|
|
symbol: symbol,
|
|
|
|
side: side,
|
|
|
|
quantity: quantity,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroup,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseTokenBalance(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
const mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"tokens"
|
|
|
|
];
|
2021-10-19 09:12:57 -07:00
|
|
|
let quoteSymbol = ids['groups'].find((e) => e['publicKey'] === mangoGroupPk)[
|
|
|
|
'quoteSymbol'
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids['groups']
|
|
|
|
.find((e) => e['publicKey'] === mangoGroupPk)
|
|
|
|
['tokens'].find((e) => e.symbol === quoteSymbol).decimals;
|
2021-10-18 22:45:06 -07:00
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
let mangoAccountPk = eventData.mangoAccount.toString();
|
|
|
|
let tokenIndex = eventData.tokenIndex.toNumber();
|
|
|
|
|
|
|
|
let tokenPk = tokenIndexesMap[mangoGroupPk][tokenIndex];
|
|
|
|
let token = tokens.find((e) => e["mintKey"] === tokenPk);
|
|
|
|
let symbol = token.symbol;
|
2021-10-19 09:12:57 -07:00
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
let deposit = new I80F48(eventData.deposit)
|
2021-10-19 09:12:57 -07:00
|
|
|
.div(I80F48.fromNumber(Math.pow(10, token.decimals - quoteDecimals)))
|
2021-10-17 21:50:48 -07:00
|
|
|
.toNumber();
|
|
|
|
let borrow = new I80F48(eventData.borrow)
|
2021-10-19 09:12:57 -07:00
|
|
|
.div(I80F48.fromNumber(Math.pow(10, token.decimals - quoteDecimals)))
|
2021-10-17 21:50:48 -07:00
|
|
|
.toNumber();
|
|
|
|
|
|
|
|
return {
|
|
|
|
mango_account: mangoAccountPk,
|
|
|
|
symbol: symbol,
|
|
|
|
deposit: deposit,
|
|
|
|
borrow: borrow,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseCacheRootBanks(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"tokens"
|
|
|
|
];
|
|
|
|
|
|
|
|
let cacheIndexes: any = [];
|
|
|
|
|
|
|
|
let tokenIndexes = eventData.tokenIndexes.map((i) => i.toNumber());
|
|
|
|
let depositIndexes = eventData.depositIndexes.map((i) =>
|
|
|
|
new I80F48(i).toNumber()
|
|
|
|
);
|
|
|
|
let borrowIndexes = eventData.borrowIndexes.map((i) =>
|
|
|
|
new I80F48(i).toNumber()
|
|
|
|
);
|
|
|
|
|
|
|
|
for (let i = 0; i < tokenIndexes.length; i++) {
|
|
|
|
let tokenIndex = tokenIndexes[i];
|
|
|
|
|
|
|
|
let tokenPk = tokenIndexesMap[mangoGroupPk][tokenIndex];
|
|
|
|
let token = tokens.find((e) => e["mintKey"] === tokenPk);
|
|
|
|
let symbol = token.symbol;
|
|
|
|
|
|
|
|
let depositIndex = depositIndexes[i];
|
|
|
|
let borrowIndex = borrowIndexes[i];
|
|
|
|
|
|
|
|
cacheIndexes.push({
|
|
|
|
symbol: symbol,
|
|
|
|
deposit_index: depositIndex,
|
|
|
|
borrow_index: borrowIndex,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return cacheIndexes;
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseCachePrices(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
let mangoGroupPk = eventData.mangoGroup.toString();
|
|
|
|
|
|
|
|
let tokens = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"tokens"
|
|
|
|
];
|
|
|
|
let oracles = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"oracles"
|
|
|
|
];
|
|
|
|
let quoteSymbol = ids["groups"].find((e) => e["publicKey"] === mangoGroupPk)[
|
|
|
|
"quoteSymbol"
|
|
|
|
];
|
|
|
|
let quoteDecimals = ids["groups"]
|
|
|
|
.find((e) => e["publicKey"] === mangoGroupPk)
|
|
|
|
["tokens"].find((e) => e.symbol === quoteSymbol).decimals;
|
|
|
|
|
|
|
|
let cachePrices: any = [];
|
|
|
|
let oracleIndexes = eventData.oracleIndexes.map((i) => i.toNumber());
|
|
|
|
let oraclePrices = eventData.oraclePrices.map((p) => new I80F48(p));
|
|
|
|
|
|
|
|
for (let [i, oracleIndex] of oracleIndexes.entries()) {
|
|
|
|
let oraclePk = oracleIndexesMap[mangoGroupPk][oracleIndex];
|
|
|
|
let oracle = oracles.find((e) => e["publicKey"] === oraclePk);
|
|
|
|
let symbol = oracle.symbol;
|
|
|
|
|
|
|
|
let token = tokens.find((e) => e.symbol === symbol);
|
|
|
|
let baseDecimals = token.decimals;
|
|
|
|
|
|
|
|
let rawPrice = oraclePrices[i];
|
|
|
|
let price = rawPrice
|
|
|
|
.mul(I80F48.fromNumber(Math.pow(10, baseDecimals - quoteDecimals)))
|
|
|
|
.toNumber();
|
|
|
|
|
|
|
|
cachePrices.push({
|
|
|
|
symbol: symbol,
|
|
|
|
price: price,
|
|
|
|
oracle_pk: oraclePk,
|
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: mangoGroupPk,
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return cachePrices;
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseUpdateFunding(
|
|
|
|
instructionNum,
|
|
|
|
eventData,
|
|
|
|
signature,
|
|
|
|
blockTime,
|
|
|
|
slot,
|
|
|
|
blockDatetime
|
|
|
|
) {
|
|
|
|
const config = new Config(IDS);
|
|
|
|
|
|
|
|
const groupConfig = config.groups.find((g) =>
|
|
|
|
g.publicKey.equals(eventData.mangoGroup)
|
|
|
|
) as GroupConfig;
|
|
|
|
const perpMarketConfig = groupConfig.perpMarkets.find(
|
|
|
|
(p) => p.marketIndex === eventData.marketIndex.toNumber()
|
|
|
|
) as PerpMarketConfig;
|
2021-11-01 14:34:33 -07:00
|
|
|
|
2021-10-17 21:50:48 -07:00
|
|
|
return {
|
|
|
|
symbol: perpMarketConfig.baseSymbol,
|
|
|
|
long_funding: new I80F48(eventData.longFunding).toNumber(),
|
2021-11-01 14:34:33 -07:00
|
|
|
short_funding: new I80F48(eventData.shortFunding).toNumber(),
|
2021-10-17 21:50:48 -07:00
|
|
|
instruction_num: instructionNum,
|
|
|
|
mango_group: eventData.mangoGroup.toString(),
|
|
|
|
block_datetime: blockDatetime,
|
|
|
|
slot: slot,
|
|
|
|
signature: signature,
|
|
|
|
blocktime: blockTime,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|