Merge branch 'mc/update-risk' into deploy
This commit is contained in:
commit
888a270cf2
|
@ -1,9 +1,6 @@
|
||||||
import {
|
import {
|
||||||
LISTING_PRESETS,
|
|
||||||
LISTING_PRESETS_PYTH,
|
|
||||||
MidPriceImpact,
|
MidPriceImpact,
|
||||||
getMidPriceImpacts,
|
getMidPriceImpacts,
|
||||||
getProposedTier,
|
|
||||||
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools';
|
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools';
|
||||||
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
|
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
|
||||||
import { BN } from '@project-serum/anchor';
|
import { BN } from '@project-serum/anchor';
|
||||||
|
@ -21,12 +18,14 @@ import {
|
||||||
TransactionInstruction,
|
TransactionInstruction,
|
||||||
} from '@solana/web3.js';
|
} from '@solana/web3.js';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { OracleProvider } from '../src/accounts/oracle';
|
import { Bank } from '../src/accounts/bank';
|
||||||
|
import { Group } from '../src/accounts/group';
|
||||||
import { Builder } from '../src/builder';
|
import { Builder } from '../src/builder';
|
||||||
import { MangoClient } from '../src/client';
|
import { MangoClient } from '../src/client';
|
||||||
import { NullTokenEditParams } from '../src/clientIxParamBuilder';
|
import { NullTokenEditParams } from '../src/clientIxParamBuilder';
|
||||||
import { MANGO_V4_MAIN_GROUP as MANGO_V4_PRIMARY_GROUP } from '../src/constants';
|
import { MANGO_V4_MAIN_GROUP as MANGO_V4_PRIMARY_GROUP } from '../src/constants';
|
||||||
import { toUiDecimalsForQuote } from '../src/utils';
|
import { getEquityForMangoAccounts } from '../src/risk';
|
||||||
|
import { buildFetch } from '../src/utils';
|
||||||
import {
|
import {
|
||||||
MANGO_DAO_WALLET_GOVERNANCE,
|
MANGO_DAO_WALLET_GOVERNANCE,
|
||||||
MANGO_GOVERNANCE_PROGRAM,
|
MANGO_GOVERNANCE_PROGRAM,
|
||||||
|
@ -77,6 +76,52 @@ async function setupVsr(
|
||||||
return vsrClient;
|
return vsrClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getTotalLiqorEquity(
|
||||||
|
client: MangoClient,
|
||||||
|
group: Group,
|
||||||
|
mangoAccounts: import('/Users/mc/repos/mango-v4/ts/client/src/accounts/mangoAccount').MangoAccount[],
|
||||||
|
): Promise<number> {
|
||||||
|
const liqors = (
|
||||||
|
await (
|
||||||
|
await (
|
||||||
|
await buildFetch()
|
||||||
|
)(
|
||||||
|
`https://api.mngo.cloud/data/v4/stats/liqors-over_period?over_period=1MONTH`,
|
||||||
|
{
|
||||||
|
mode: 'cors',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).json()
|
||||||
|
).map((data) => new PublicKey(data['liqor']));
|
||||||
|
const ttlLiqorEquity = (
|
||||||
|
await getEquityForMangoAccounts(client, group, liqors, mangoAccounts)
|
||||||
|
).reduce((partialSum, ae) => partialSum + ae.Equity.val, 0);
|
||||||
|
return ttlLiqorEquity;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPriceImpactForBank(
|
||||||
|
midPriceImpacts: MidPriceImpact[],
|
||||||
|
bank: Bank,
|
||||||
|
): MidPriceImpact {
|
||||||
|
const tokenToPriceImpact = midPriceImpacts
|
||||||
|
.filter((x) => x.avg_price_impact_percent < 1)
|
||||||
|
.reduce((acc: { [key: string]: MidPriceImpact }, val: MidPriceImpact) => {
|
||||||
|
if (
|
||||||
|
!acc[val.symbol] ||
|
||||||
|
val.target_amount > acc[val.symbol].target_amount
|
||||||
|
) {
|
||||||
|
acc[val.symbol] = val;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
const priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)];
|
||||||
|
return priceImpact;
|
||||||
|
}
|
||||||
|
|
||||||
async function updateTokenParams(): Promise<void> {
|
async function updateTokenParams(): Promise<void> {
|
||||||
const [client, wallet] = await Promise.all([buildClient(), setupWallet()]);
|
const [client, wallet] = await Promise.all([buildClient(), setupWallet()]);
|
||||||
const vsrClient = await setupVsr(client.connection, wallet);
|
const vsrClient = await setupVsr(client.connection, wallet);
|
||||||
|
@ -84,87 +129,65 @@ async function updateTokenParams(): Promise<void> {
|
||||||
const group = await client.getGroup(MANGO_V4_PRIMARY_GROUP);
|
const group = await client.getGroup(MANGO_V4_PRIMARY_GROUP);
|
||||||
|
|
||||||
const instructions: TransactionInstruction[] = [];
|
const instructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
|
const mangoAccounts = await client.getAllMangoAccounts(group, true);
|
||||||
|
const ttlLiqorEquityUi = await getTotalLiqorEquity(
|
||||||
|
client,
|
||||||
|
group,
|
||||||
|
mangoAccounts,
|
||||||
|
);
|
||||||
|
|
||||||
const midPriceImpacts = getMidPriceImpacts(group.pis);
|
const midPriceImpacts = getMidPriceImpacts(group.pis);
|
||||||
|
|
||||||
Array.from(group.banksMapByTokenIndex.values())
|
Array.from(group.banksMapByTokenIndex.values())
|
||||||
.map((banks) => banks[0])
|
.map((banks) => banks[0])
|
||||||
.filter(
|
.filter(
|
||||||
(bank) =>
|
(bank) =>
|
||||||
bank.mint.toBase58() == 'So11111111111111111111111111111111111111112' ||
|
// // low low liquidity
|
||||||
bank.name.toLocaleLowerCase().indexOf('usdc') > -1 ||
|
// bank.name.includes('DUAL') ||
|
||||||
bank.name.toLocaleLowerCase().indexOf('stsol') > -1,
|
// bank.name.includes('MNGO') ||
|
||||||
|
// // low liquidity
|
||||||
|
// bank.name.includes('ALL') ||
|
||||||
|
// bank.name.includes('CROWN') ||
|
||||||
|
// bank.name.includes('GUAC') ||
|
||||||
|
// bank.name.includes('HNT') ||
|
||||||
|
// bank.name.includes('KIN') ||
|
||||||
|
// bank.name.includes('OPOS') ||
|
||||||
|
// bank.name.includes('RLB') ||
|
||||||
|
// bank.name.includes('USDH') ||
|
||||||
|
// better liquidity
|
||||||
|
bank.name.includes('BONK') ||
|
||||||
|
bank.name.includes('bSOL') ||
|
||||||
|
bank.name.includes('CHAI') ||
|
||||||
|
bank.name.includes('DAI') ||
|
||||||
|
bank.name.includes('ETH (Portal)') ||
|
||||||
|
bank.name.includes('JitoSOL') ||
|
||||||
|
bank.name.includes('LDO') ||
|
||||||
|
bank.name.includes('MSOL') ||
|
||||||
|
bank.name.includes('ORCA') ||
|
||||||
|
bank.name.includes('RAY') ||
|
||||||
|
bank.name.includes('SOL') ||
|
||||||
|
bank.name.includes('stSOL') ||
|
||||||
|
bank.name.includes('TBTC') ||
|
||||||
|
bank.name.includes('USDC') ||
|
||||||
|
bank.name.includes('wBTC (Portal)') ||
|
||||||
|
bank.name.includes('USDT'),
|
||||||
)
|
)
|
||||||
.forEach(async (bank) => {
|
.forEach(async (bank) => {
|
||||||
// Limit borrows to 1/3rd of deposit, rounded to 1000, only update if more than 10% different
|
const priceImpact = getPriceImpactForBank(midPriceImpacts, bank);
|
||||||
const depositsInUsd = bank.nativeDeposits().mul(bank.price);
|
|
||||||
let newNetBorrowLimitPerWindowQuote: number | null =
|
|
||||||
depositsInUsd.toNumber() / 3;
|
|
||||||
newNetBorrowLimitPerWindowQuote =
|
|
||||||
Math.round(newNetBorrowLimitPerWindowQuote / 1_000_000_000) *
|
|
||||||
1_000_000_000;
|
|
||||||
newNetBorrowLimitPerWindowQuote =
|
|
||||||
Math.abs(
|
|
||||||
(newNetBorrowLimitPerWindowQuote -
|
|
||||||
bank.netBorrowLimitPerWindowQuote.toNumber()) /
|
|
||||||
bank.netBorrowLimitPerWindowQuote.toNumber(),
|
|
||||||
) > 0.1
|
|
||||||
? newNetBorrowLimitPerWindowQuote
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Kick in weight scaling as late as possible until liquidation fee remains reasonable
|
const scaleStartQuoteUi = Math.min(
|
||||||
// Only update if more than 10% different
|
50 * ttlLiqorEquityUi,
|
||||||
let newWeightScaleQuote: number | null = null;
|
4 * priceImpact.target_amount,
|
||||||
if (
|
);
|
||||||
bank.tokenIndex != 0 && // USDC
|
|
||||||
bank.mint.toBase58() != 'So11111111111111111111111111111111111111112' // SOL
|
|
||||||
) {
|
|
||||||
const PRESETS =
|
|
||||||
bank?.oracleProvider === OracleProvider.Pyth
|
|
||||||
? LISTING_PRESETS_PYTH
|
|
||||||
: LISTING_PRESETS;
|
|
||||||
|
|
||||||
const tokenToPriceImpact = midPriceImpacts
|
const newNetDepositsUi = Math.max(
|
||||||
.filter((x) => x.avg_price_impact_percent < 1)
|
10_000,
|
||||||
.reduce(
|
Math.min(bank.uiDeposits(), 300_000) / 3 +
|
||||||
(acc: { [key: string]: MidPriceImpact }, val: MidPriceImpact) => {
|
Math.max(0, bank.uiDeposits() - 300_000) / 5,
|
||||||
if (
|
);
|
||||||
!acc[val.symbol] ||
|
|
||||||
val.target_amount > acc[val.symbol].target_amount
|
|
||||||
) {
|
|
||||||
acc[val.symbol] = val;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
const priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)];
|
|
||||||
const suggestedTier = getProposedTier(
|
|
||||||
PRESETS,
|
|
||||||
priceImpact?.target_amount,
|
|
||||||
bank.oracleProvider === OracleProvider.Pyth,
|
|
||||||
);
|
|
||||||
newWeightScaleQuote =
|
|
||||||
PRESETS[suggestedTier].borrowWeightScaleStartQuote;
|
|
||||||
|
|
||||||
newWeightScaleQuote =
|
const params = Builder(NullTokenEditParams).build();
|
||||||
bank.depositWeightScaleStartQuote !== newWeightScaleQuote ||
|
|
||||||
bank.borrowWeightScaleStartQuote !== newWeightScaleQuote
|
|
||||||
? newWeightScaleQuote
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
newNetBorrowLimitPerWindowQuote == null &&
|
|
||||||
newWeightScaleQuote == null
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = Builder(NullTokenEditParams)
|
|
||||||
.netBorrowLimitPerWindowQuote(newNetBorrowLimitPerWindowQuote)
|
|
||||||
.borrowWeightScaleStartQuote(newWeightScaleQuote)
|
|
||||||
.depositWeightScaleStartQuote(newWeightScaleQuote)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
const ix = await client.program.methods
|
const ix = await client.program.methods
|
||||||
.tokenEdit(
|
.tokenEdit(
|
||||||
|
@ -224,21 +247,6 @@ async function updateTokenParams(): Promise<void> {
|
||||||
throw simulated.value.logs;
|
throw simulated.value.logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Bank ${bank.name}`);
|
|
||||||
console.log(
|
|
||||||
`- netBorrowLimitPerWindowQuote UI old ${toUiDecimalsForQuote(
|
|
||||||
bank.netBorrowLimitPerWindowQuote.toNumber(),
|
|
||||||
).toLocaleString()} new ${toUiDecimalsForQuote(
|
|
||||||
newNetBorrowLimitPerWindowQuote!,
|
|
||||||
).toLocaleString()}`,
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`- WeightScaleQuote UI old ${toUiDecimalsForQuote(
|
|
||||||
bank.depositWeightScaleStartQuote,
|
|
||||||
).toLocaleString()} new ${toUiDecimalsForQuote(
|
|
||||||
newWeightScaleQuote!,
|
|
||||||
).toLocaleString()}`,
|
|
||||||
);
|
|
||||||
instructions.push(ix);
|
instructions.push(ix);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue