From 7c4ee31615adb97de5c94dbc264f19d71ee18915 Mon Sep 17 00:00:00 2001 From: Maximilian Schneider Date: Tue, 13 Aug 2024 18:45:26 +0100 Subject: [PATCH] remove async where not needed --- ts/client/scripts/update-risk-params.ts | 12 +- ts/client/src/risk.ts | 385 ++++++++++++------------ 2 files changed, 199 insertions(+), 198 deletions(-) diff --git a/ts/client/scripts/update-risk-params.ts b/ts/client/scripts/update-risk-params.ts index da458191e..2f664351c 100644 --- a/ts/client/scripts/update-risk-params.ts +++ b/ts/client/scripts/update-risk-params.ts @@ -106,6 +106,7 @@ async function setupVsr( return vsrClient; } +/** unused async function getTotalLiqorEquity( client: MangoClient, group: Group, @@ -127,9 +128,8 @@ async function getTotalLiqorEquity( ) ).json() ).map((data) => new PublicKey(data['liqor'])); - const ttlLiqorEquity = ( - await getEquityForMangoAccounts(client, group, liqors, mangoAccounts) - ).reduce((partialSum, ae) => partialSum + ae.Equity.val, 0); + const ttlLiqorEquity = getEquityForMangoAccounts(client, group, liqors, mangoAccounts) + .reduce((partialSum, ae) => partialSum + ae.Equity.val, 0); return ttlLiqorEquity; } @@ -152,6 +152,8 @@ function getPriceImpactForBank( const priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)]; return priceImpact; } + */ + async function updateTokenParams(): Promise { const [client, wallet] = await Promise.all([buildClient(), setupWallet()]); @@ -208,7 +210,8 @@ async function updateTokenParams(): Promise { const builder = Builder(NullTokenEditParams); let change = false; - // try { + // unused + /* const tier = Object.values(LISTING_PRESETS).find((x) => x.initLiabWeight.toFixed(1) === '1.8' ? x.initLiabWeight.toFixed(1) === @@ -217,6 +220,7 @@ async function updateTokenParams(): Promise { : x.initLiabWeight.toFixed(1) === bank?.initLiabWeight.toNumber().toFixed(1), ); + */ // eslint-disable-next-line no-constant-condition if (true) { diff --git a/ts/client/src/risk.ts b/ts/client/src/risk.ts index 34e832c59..f71289c9d 100644 --- a/ts/client/src/risk.ts +++ b/ts/client/src/risk.ts @@ -120,11 +120,11 @@ export async function getOnChainPriceForMints( ); } -export async function getPriceImpactForLiqor( +export function getPriceImpactForLiqor( group: Group, pis: PriceImpact[], mangoAccounts: MangoAccount[], -): Promise { +): LiqorPriceImpact[] { const mangoAccounts_ = mangoAccounts.filter((a) => a.getHealth(group, HealthType.maint).lt(ZERO_I80F48()), ); @@ -140,91 +140,28 @@ export async function getPriceImpactForLiqor( const usdcBank = group.getFirstBankByTokenIndex(0 as TokenIndex); const usdcMint = usdcBank.mint; - return await Promise.all( - Array.from(group.banksMapByMint.values()) - .sort((a, b) => a[0].name.localeCompare(b[0].name)) - // .filter((banks) => banks[0].name == 'MSOL') - .map(async (banks) => { - const bank = banks[0]; - - // Sum of all liabs, these liabs would be acquired by liqor, - // who would immediately want to reduce them to 0 - // Assuming liabs need to be bought using USDC - const liabs = - // Max liab of a particular token that would be liquidated to bring health above 0 - mangoAccountsWithHealth.reduce((sum, a) => { - // How much would health increase for every unit liab moved to liqor - // liabprice * (liabweight - (1+liabfees)*(1+assetfees)*assetweight) - // Choose the most valuable asset the user has - const assetBank = Array.from(group.banksMapByTokenIndex.values()) - .flat() - .reduce((prev, curr) => - prev.initAssetWeight - .mul(a.account.getEffectiveTokenBalance(group, prev)) - .mul(prev._price!) - .gt( - curr.initAssetWeight.mul( - a.account - .getEffectiveTokenBalance(group, curr) - .mul(curr._price!), - ), - ) - ? prev - : curr, - ); - const feeFactor = ONE_I80F48() - .add(bank.liquidationFee) - .add(bank.platformLiquidationFee) - .mul( - ONE_I80F48() - .add(assetBank.liquidationFee) - .add(assetBank.platformLiquidationFee), - ); - const tokenLiabHealthContrib = bank.price.mul( - bank.initLiabWeight.sub(feeFactor.mul(assetBank.initAssetWeight)), - ); - // Abs liab/borrow - const maxTokenLiab = a.account - .getEffectiveTokenBalance(group, bank) - .min(ZERO_I80F48()) - .abs(); - - if (tokenLiabHealthContrib.eq(ZERO_I80F48())) { - return sum.add(maxTokenLiab); - } - - // Health under 0 - const maxLiab = a.health - .min(ZERO_I80F48()) - .abs() - .div(tokenLiabHealthContrib) - .min(maxTokenLiab); - - return sum.add(maxLiab); - }, ZERO_I80F48()); - const liabsInUsdc = - // convert to usdc, this is an approximation - liabs - .mul(bank.price) - .floor() - // jup oddity - .min(I80F48.fromNumber(99999999999)); - - // Sum of all assets which would be acquired in exchange for also acquiring - // liabs by the liqor, who would immediately want to reduce to 0 - // Assuming assets need to be sold to USDC - const assets = mangoAccountsWithHealth.reduce((sum, a) => { + return Array.from(group.banksMapByMint.values()) + .sort((a, b) => a[0].name.localeCompare(b[0].name)) + .map((banks) => { + const bank = banks[0]; + + // Sum of all liabs, these liabs would be acquired by liqor, + // who would immediately want to reduce them to 0 + // Assuming liabs need to be bought using USDC + const liabs = + // Max liab of a particular token that would be liquidated to bring health above 0 + mangoAccountsWithHealth.reduce((sum, a) => { // How much would health increase for every unit liab moved to liqor - // assetprice * (liabweight/(1+liabliqfee) - assetweight) - // Choose the smallest liability the user has - const liabBank = Array.from(group.banksMapByTokenIndex.values()) + // liabprice * (liabweight - (1+liabfees)*(1+assetfees)*assetweight) + // Choose the most valuable asset the user has + const assetBank = Array.from(group.banksMapByTokenIndex.values()) .flat() .reduce((prev, curr) => - prev.initLiabWeight + prev.initAssetWeight .mul(a.account.getEffectiveTokenBalance(group, prev)) .mul(prev._price!) - .lt( - curr.initLiabWeight.mul( + .gt( + curr.initAssetWeight.mul( a.account .getEffectiveTokenBalance(group, curr) .mul(curr._price!), @@ -233,103 +170,162 @@ export async function getPriceImpactForLiqor( ? prev : curr, ); - const tokenAssetHealthContrib = bank.price.mul( - liabBank.initLiabWeight - .div(ONE_I80F48().add(liabBank.liquidationFee)) - .sub(bank.initAssetWeight), + const feeFactor = ONE_I80F48() + .add(bank.liquidationFee) + .add(bank.platformLiquidationFee) + .mul( + ONE_I80F48() + .add(assetBank.liquidationFee) + .add(assetBank.platformLiquidationFee), + ); + const tokenLiabHealthContrib = bank.price.mul( + bank.initLiabWeight.sub(feeFactor.mul(assetBank.initAssetWeight)), ); - - // Abs collateral/asset - const maxTokenHealthAsset = a.account + // Abs liab/borrow + const maxTokenLiab = a.account .getEffectiveTokenBalance(group, bank) - .max(ZERO_I80F48()); + .min(ZERO_I80F48()) + .abs(); - if (tokenAssetHealthContrib.eq(ZERO_I80F48())) { - return sum.add(maxTokenHealthAsset); + if (tokenLiabHealthContrib.eq(ZERO_I80F48())) { + return sum.add(maxTokenLiab); } - const maxAsset = a.health + // Health under 0 + const maxLiab = a.health .min(ZERO_I80F48()) .abs() - .div(tokenAssetHealthContrib) - .min(maxTokenHealthAsset); + .div(tokenLiabHealthContrib) + .min(maxTokenLiab); - return sum.add(maxAsset); + return sum.add(maxLiab); }, ZERO_I80F48()); - - const pi1 = - !liabsInUsdc.eq(ZERO_I80F48()) && - usdcMint.toBase58() !== bank.mint.toBase58() - ? computePriceImpactOnJup( - pis, - toUiDecimalsForQuote(liabsInUsdc), - bank.name, - ) - : 0; - const pi2 = - !assets.eq(ZERO_I80F48()) && - usdcMint.toBase58() !== bank.mint.toBase58() - ? computePriceImpactOnJup( - pis, - toUiDecimals(assets.mul(bank.price), bank.mintDecimals), - bank.name, + const liabsInUsdc = + // convert to usdc, this is an approximation + liabs + .mul(bank.price) + .floor() + // jup oddity + .min(I80F48.fromNumber(99999999999)); + + // Sum of all assets which would be acquired in exchange for also acquiring + // liabs by the liqor, who would immediately want to reduce to 0 + // Assuming assets need to be sold to USDC + const assets = mangoAccountsWithHealth.reduce((sum, a) => { + // How much would health increase for every unit liab moved to liqor + // assetprice * (liabweight/(1+liabliqfee) - assetweight) + // Choose the smallest liability the user has + const liabBank = Array.from(group.banksMapByTokenIndex.values()) + .flat() + .reduce((prev, curr) => + prev.initLiabWeight + .mul(a.account.getEffectiveTokenBalance(group, prev)) + .mul(prev._price!) + .lt( + curr.initLiabWeight.mul( + a.account + .getEffectiveTokenBalance(group, curr) + .mul(curr._price!), + ), ) - : 0; + ? prev + : curr, + ); + const tokenAssetHealthContrib = bank.price.mul( + liabBank.initLiabWeight + .div(ONE_I80F48().add(liabBank.liquidationFee)) + .sub(bank.initAssetWeight), + ); + + // Abs collateral/asset + const maxTokenHealthAsset = a.account + .getEffectiveTokenBalance(group, bank) + .max(ZERO_I80F48()); + + if (tokenAssetHealthContrib.eq(ZERO_I80F48())) { + return sum.add(maxTokenHealthAsset); + } + + const maxAsset = a.health + .min(ZERO_I80F48()) + .abs() + .div(tokenAssetHealthContrib) + .min(maxTokenHealthAsset); + + return sum.add(maxAsset); + }, ZERO_I80F48()); + + const pi1 = + !liabsInUsdc.eq(ZERO_I80F48()) && + usdcMint.toBase58() !== bank.mint.toBase58() + ? computePriceImpactOnJup( + pis, + toUiDecimalsForQuote(liabsInUsdc), + bank.name, + ) + : 0; + const pi2 = + !assets.eq(ZERO_I80F48()) && + usdcMint.toBase58() !== bank.mint.toBase58() + ? computePriceImpactOnJup( + pis, + toUiDecimals(assets.mul(bank.price), bank.mintDecimals), + bank.name, + ) + : 0; - return { - Coin: { val: bank.name, highlight: false }, - 'Oracle Price': { - val: bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!, - highlight: false, - }, - 'Jup Price': { - val: bank['onChainPrice'], - highlight: - Math.abs( - (bank['onChainPrice'] - - (bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!)) / - (bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!), - ) > 0.05, - }, - 'Future Price': { val: bank._uiPrice!, highlight: false }, - 'V4 Liq Fee': { - val: Math.round(bank.liquidationFee.toNumber() * 10000), - highlight: false, - }, - Liabs: { - val: Math.round(toUiDecimalsForQuote(liabsInUsdc)), - highlight: Math.round(toUiDecimalsForQuote(liabsInUsdc)) > 5000, - }, - 'Liabs Slippage': { - val: Math.round(pi1), - highlight: - Math.round(pi1) > - Math.round(bank.liquidationFee.toNumber() * 10000), - }, - Assets: { - val: Math.round( - toUiDecimals(assets, bank.mintDecimals) * bank.uiPrice, - ), - highlight: - Math.round( - toUiDecimals(assets, bank.mintDecimals) * bank.uiPrice, - ) > 5000, - }, - 'Assets Slippage': { - val: Math.round(pi2), - highlight: - Math.round(pi2) > - Math.round(bank.liquidationFee.toNumber() * 10000), - }, - }; - }), - ); + return { + Coin: { val: bank.name, highlight: false }, + 'Oracle Price': { + val: bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!, + highlight: false, + }, + 'Jup Price': { + val: bank['onChainPrice'], + highlight: + Math.abs( + (bank['onChainPrice'] - + (bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!)) / + (bank['oldUiPrice'] ? bank['oldUiPrice'] : bank._uiPrice!), + ) > 0.05, + }, + 'Future Price': { val: bank._uiPrice!, highlight: false }, + 'V4 Liq Fee': { + val: Math.round(bank.liquidationFee.toNumber() * 10000), + highlight: false, + }, + Liabs: { + val: Math.round(toUiDecimalsForQuote(liabsInUsdc)), + highlight: Math.round(toUiDecimalsForQuote(liabsInUsdc)) > 5000, + }, + 'Liabs Slippage': { + val: Math.round(pi1), + highlight: + Math.round(pi1) > + Math.round(bank.liquidationFee.toNumber() * 10000), + }, + Assets: { + val: Math.round( + toUiDecimals(assets, bank.mintDecimals) * bank.uiPrice, + ), + highlight: + Math.round(toUiDecimals(assets, bank.mintDecimals) * bank.uiPrice) > + 5000, + }, + 'Assets Slippage': { + val: Math.round(pi2), + highlight: + Math.round(pi2) > + Math.round(bank.liquidationFee.toNumber() * 10000), + }, + }; + }); } -export async function getPerpPositionsToBeLiquidated( +export function getPerpPositionsToBeLiquidated( group: Group, mangoAccounts: MangoAccount[], -): Promise { +): PerpPositionsToBeLiquidated[] { const mangoAccountsWithHealth = mangoAccounts.map((a: MangoAccount) => { return { account: a, @@ -395,12 +391,12 @@ export async function getPerpPositionsToBeLiquidated( }); } -export async function getEquityForMangoAccounts( +export function getEquityForMangoAccounts( client: MangoClient, group: Group, mangoAccountPks: PublicKey[], allMangoAccounts: MangoAccount[], -): Promise { +): AccountEquity[] { const mangoAccounts = allMangoAccounts.filter((a) => mangoAccountPks.find((pk) => pk.equals(a.publicKey)), ); @@ -542,8 +538,8 @@ export async function buildGroupGrid( // Compute how much of an asset would need to be liquidated // when group (i.e. asset prices) reach a specific state - return await Promise.all( - groups.map((g) => getPriceImpactForLiqor(g, pis, mangoAccountsSubset)), + return groups.map((g) => + getPriceImpactForLiqor(g, pis, mangoAccountsSubset), ); } } @@ -660,13 +656,13 @@ export async function getRiskStats( const mangoAccounts = await client.getAllMangoAccounts(group, true); // Get on chain prices - const mints = [ - ...new Set( - Array.from(group.banksMapByTokenIndex.values()) - .flat() - .map((bank) => bank.mint.toString()), - ), - ]; + // const mints = [ + // ...new Set( + // Array.from(group.banksMapByTokenIndex.values()) + // .flat() + // .map((bank) => bank.mint.toString()), + // ), + // ]; // Note: // Disable for now @@ -744,25 +740,26 @@ export async function getRiskStats( p._price = p._price?.mul(I80F48.fromNumber(rally)); }); - const [ - assetDrop, - assetRally, - usdcDepeg, - usdtDepeg, - perpDrop, - perpRally, - liqorEquity, - marketMakerEquity, - ] = await Promise.all([ - getPriceImpactForLiqor(groupDrop, pis, mangoAccounts), - getPriceImpactForLiqor(groupRally, pis, mangoAccounts), - getPriceImpactForLiqor(groupUsdcDepeg, pis, mangoAccounts), - getPriceImpactForLiqor(groupUsdtDepeg, pis, mangoAccounts), - getPerpPositionsToBeLiquidated(groupDrop, mangoAccounts), - getPerpPositionsToBeLiquidated(groupRally, mangoAccounts), - getEquityForMangoAccounts(client, group, liqors, mangoAccounts), - getEquityForMangoAccounts(client, group, mms, mangoAccounts), - ]); + const assetDrop = getPriceImpactForLiqor(groupDrop, pis, mangoAccounts); + const assetRally = getPriceImpactForLiqor(groupRally, pis, mangoAccounts); + const usdcDepeg = getPriceImpactForLiqor(groupUsdcDepeg, pis, mangoAccounts); + const usdtDepeg = getPriceImpactForLiqor(groupUsdtDepeg, pis, mangoAccounts); + + const perpDrop = getPerpPositionsToBeLiquidated(groupDrop, mangoAccounts); + const perpRally = getPerpPositionsToBeLiquidated(groupRally, mangoAccounts); + + const liqorEquity = getEquityForMangoAccounts( + client, + group, + liqors, + mangoAccounts, + ); + const marketMakerEquity = getEquityForMangoAccounts( + client, + group, + mms, + mangoAccounts, + ); return { assetDrop: {