2023-06-21 06:30:45 -07:00
|
|
|
import { AnchorProvider, Program } from '@coral-xyz/anchor'
|
2023-05-22 16:05:43 -07:00
|
|
|
import { PythHttpClient } from '@pythnetwork/client'
|
|
|
|
import { notify } from 'utils/notifications'
|
|
|
|
import { MAINNET_PYTH_PROGRAM } from './constants'
|
2023-06-26 05:48:37 -07:00
|
|
|
import {
|
|
|
|
Bank,
|
|
|
|
Group,
|
|
|
|
I80F48,
|
|
|
|
OPENBOOK_PROGRAM_ID,
|
|
|
|
toNative,
|
|
|
|
toUiDecimals,
|
|
|
|
toUiDecimalsForQuote,
|
|
|
|
} from '@blockworks-foundation/mango-v4'
|
2023-05-22 16:05:43 -07:00
|
|
|
import { Market } from '@project-serum/serum'
|
|
|
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js'
|
|
|
|
import EmptyWallet from 'utils/wallet'
|
|
|
|
|
|
|
|
export const getOracle = async ({
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol,
|
|
|
|
quoteSymbol,
|
2023-05-22 16:05:43 -07:00
|
|
|
connection,
|
2023-06-06 15:54:44 -07:00
|
|
|
pythOnly = false,
|
2023-05-22 16:05:43 -07:00
|
|
|
}: {
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol: string
|
|
|
|
quoteSymbol: string
|
2023-05-22 16:05:43 -07:00
|
|
|
connection: Connection
|
2023-06-06 15:54:44 -07:00
|
|
|
pythOnly?: boolean
|
2023-05-22 16:05:43 -07:00
|
|
|
}) => {
|
|
|
|
try {
|
|
|
|
let oraclePk = ''
|
2023-05-22 16:17:53 -07:00
|
|
|
const pythOracle = await getPythOracle({
|
|
|
|
baseSymbol,
|
|
|
|
quoteSymbol,
|
|
|
|
connection,
|
|
|
|
})
|
2023-05-22 16:05:43 -07:00
|
|
|
if (pythOracle) {
|
|
|
|
oraclePk = pythOracle
|
2023-06-06 15:54:44 -07:00
|
|
|
} else if (!pythOnly) {
|
2023-05-22 16:05:43 -07:00
|
|
|
const switchBoardOracle = await getSwitchBoardOracle({
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol,
|
|
|
|
quoteSymbol,
|
2023-05-22 16:05:43 -07:00
|
|
|
connection,
|
|
|
|
})
|
|
|
|
oraclePk = switchBoardOracle
|
|
|
|
}
|
|
|
|
|
|
|
|
return oraclePk
|
|
|
|
} catch (e) {
|
|
|
|
notify({
|
|
|
|
title: 'Oracle not found',
|
|
|
|
description: `${e}`,
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getPythOracle = async ({
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol,
|
|
|
|
quoteSymbol,
|
2023-05-22 16:05:43 -07:00
|
|
|
connection,
|
|
|
|
}: {
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol: string
|
|
|
|
quoteSymbol: string
|
2023-05-22 16:05:43 -07:00
|
|
|
connection: Connection
|
|
|
|
}) => {
|
|
|
|
try {
|
|
|
|
const pythClient = new PythHttpClient(connection, MAINNET_PYTH_PROGRAM)
|
|
|
|
const pythAccounts = await pythClient.getData()
|
|
|
|
const product = pythAccounts.products.find(
|
2023-05-22 16:17:53 -07:00
|
|
|
(x) =>
|
|
|
|
x.base === baseSymbol.toUpperCase() &&
|
|
|
|
x.quote_currency === quoteSymbol.toUpperCase()
|
2023-05-22 16:05:43 -07:00
|
|
|
)
|
|
|
|
return product?.price_account || ''
|
|
|
|
} catch (e) {
|
|
|
|
notify({
|
|
|
|
title: 'Pyth oracle fetch error',
|
|
|
|
description: `${e}`,
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getSwitchBoardOracle = async ({
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol,
|
|
|
|
quoteSymbol,
|
2023-05-22 16:05:43 -07:00
|
|
|
connection,
|
|
|
|
}: {
|
2023-05-22 16:17:53 -07:00
|
|
|
baseSymbol: string
|
|
|
|
quoteSymbol: string
|
2023-05-22 16:05:43 -07:00
|
|
|
connection: Connection
|
|
|
|
}) => {
|
|
|
|
try {
|
|
|
|
const SWITCHBOARD_PROGRAM_ID = 'SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f'
|
|
|
|
|
|
|
|
const options = AnchorProvider.defaultOptions()
|
|
|
|
const provider = new AnchorProvider(
|
|
|
|
connection,
|
|
|
|
new EmptyWallet(Keypair.generate()),
|
|
|
|
options
|
|
|
|
)
|
|
|
|
const idl = await Program.fetchIdl(
|
|
|
|
new PublicKey(SWITCHBOARD_PROGRAM_ID),
|
|
|
|
provider
|
|
|
|
)
|
|
|
|
const switchboardProgram = new Program(
|
|
|
|
idl!,
|
|
|
|
new PublicKey(SWITCHBOARD_PROGRAM_ID),
|
|
|
|
provider
|
|
|
|
)
|
|
|
|
|
|
|
|
const allFeeds =
|
|
|
|
await switchboardProgram.account.aggregatorAccountData.all()
|
|
|
|
|
|
|
|
const feedNames = allFeeds.map((x) =>
|
|
|
|
String.fromCharCode(...[...(x.account.name as number[])].filter((x) => x))
|
|
|
|
)
|
2023-05-22 16:17:53 -07:00
|
|
|
|
2023-05-22 16:05:43 -07:00
|
|
|
const possibleFeedIndexes = feedNames.reduce(function (r, v, i) {
|
|
|
|
return r.concat(
|
2023-05-22 16:17:53 -07:00
|
|
|
v.toLowerCase().includes(baseSymbol.toLowerCase()) &&
|
|
|
|
v.toLowerCase().includes(quoteSymbol.toLowerCase())
|
2023-05-22 16:05:43 -07:00
|
|
|
? i
|
|
|
|
: []
|
|
|
|
)
|
|
|
|
}, [] as number[])
|
|
|
|
|
|
|
|
const possibleFeeds = allFeeds.filter(
|
|
|
|
(x, i) => possibleFeedIndexes.includes(i) && x.account.isLocked
|
|
|
|
)
|
|
|
|
return possibleFeeds.length ? possibleFeeds[0].publicKey.toBase58() : ''
|
|
|
|
} catch (e) {
|
|
|
|
notify({
|
|
|
|
title: 'Switchboard oracle fetch error',
|
|
|
|
description: `${e}`,
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getBestMarket = async ({
|
2023-05-22 16:17:53 -07:00
|
|
|
baseMint,
|
|
|
|
quoteMint,
|
2023-05-22 16:05:43 -07:00
|
|
|
cluster,
|
|
|
|
connection,
|
|
|
|
}: {
|
2023-05-22 16:17:53 -07:00
|
|
|
baseMint: string
|
|
|
|
quoteMint: string
|
2023-05-22 16:05:43 -07:00
|
|
|
cluster: 'devnet' | 'mainnet-beta'
|
|
|
|
connection: Connection
|
|
|
|
}) => {
|
|
|
|
try {
|
|
|
|
const dexProgramPk = OPENBOOK_PROGRAM_ID[cluster]
|
|
|
|
|
|
|
|
const markets = await Market.findAccountsByMints(
|
|
|
|
connection,
|
2023-05-22 16:17:53 -07:00
|
|
|
new PublicKey(baseMint),
|
|
|
|
new PublicKey(quoteMint),
|
2023-05-22 16:05:43 -07:00
|
|
|
dexProgramPk
|
|
|
|
)
|
2023-05-23 13:00:02 -07:00
|
|
|
|
2023-05-22 16:05:43 -07:00
|
|
|
if (!markets.length) {
|
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
if (markets.length === 1) {
|
|
|
|
return markets[0].publicKey
|
|
|
|
}
|
|
|
|
const marketsDataJsons = await Promise.all([
|
|
|
|
...markets.map((x) =>
|
|
|
|
fetch(`/openSerumApi/market/${x.publicKey.toBase58()}`)
|
|
|
|
),
|
|
|
|
])
|
|
|
|
const marketsData = await Promise.all([
|
|
|
|
...marketsDataJsons.map((x) => x.json()),
|
|
|
|
])
|
|
|
|
const bestMarket = marketsData.sort((a, b) => b.volume24h - a.volume24h)
|
2023-05-24 07:42:13 -07:00
|
|
|
return bestMarket.length
|
|
|
|
? new PublicKey(bestMarket[0].id)
|
|
|
|
: markets[0].publicKey
|
2023-05-22 16:05:43 -07:00
|
|
|
} catch (e) {
|
|
|
|
notify({
|
|
|
|
title: 'Openbook market not found',
|
|
|
|
description: `${e}`,
|
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-05-23 07:10:22 -07:00
|
|
|
|
2023-05-24 04:50:23 -07:00
|
|
|
// definitions:
|
|
|
|
// baseLots = 10 ^ baseLotExponent
|
|
|
|
// quoteLots = 10 ^ quoteLotExponent
|
|
|
|
// minOrderSize = 10^(baseLotExponent - baseDecimals)
|
|
|
|
// minOrderValue = basePrice * minOrderSize
|
|
|
|
// priceIncrement = 10^(quoteLotExponent + baseDecimals - baseLotExponent - quoteDecimals)
|
2023-05-25 09:09:12 -07:00
|
|
|
// priceIncrementRelative = priceIncrement * quotePrice / basePrice
|
2023-05-24 04:50:23 -07:00
|
|
|
|
2023-05-25 07:16:32 -07:00
|
|
|
// derive: baseLotExponent <= min[ basePrice * minOrderSize > 0.05]
|
|
|
|
// baseLotExponent = 10
|
|
|
|
// While (baseLotExponent < 10):
|
2023-05-24 04:50:23 -07:00
|
|
|
// minOrderSize = 10^(baseLotExponent - baseDecimals)
|
|
|
|
// minOrderValue = basePrice * minOrderSize
|
2023-05-25 07:16:32 -07:00
|
|
|
// if minOrderValue > 0.05:
|
2023-05-24 04:50:23 -07:00
|
|
|
// break;
|
|
|
|
|
2023-05-25 13:06:22 -07:00
|
|
|
// Derive: quoteLotExponent <= min[ priceIncrement * quotePrice / basePrice > 0.000025 ]
|
2023-05-25 07:16:32 -07:00
|
|
|
// quoteLotExponent = 0
|
|
|
|
// While (quoteLotExponent < 10):
|
2023-05-24 04:50:23 -07:00
|
|
|
// priceIncrement = 10^(quoteLotExponent + baseDecimals - baseLotExponent - quoteDecimals)
|
2023-05-25 09:09:12 -07:00
|
|
|
// priceIncrementRelative = priceIncrement * quotePrice / basePrice
|
2023-05-25 13:06:22 -07:00
|
|
|
// if priceIncrementRelative > 0.000025:
|
2023-05-24 04:50:23 -07:00
|
|
|
// break;
|
|
|
|
|
|
|
|
export function calculateTradingParameters(
|
2023-05-23 13:00:02 -07:00
|
|
|
basePrice: number,
|
2023-05-24 04:50:23 -07:00
|
|
|
quotePrice: number,
|
|
|
|
baseDecimals: number,
|
|
|
|
quoteDecimals: number
|
|
|
|
) {
|
2023-05-25 04:39:33 -07:00
|
|
|
const MAX_MIN_ORDER_VALUE = 0.05
|
2023-05-25 09:09:12 -07:00
|
|
|
const MIN_PRICE_INCREMENT_RELATIVE = 0.000025
|
2023-05-25 13:06:22 -07:00
|
|
|
const EXPONENT_THRESHOLD = 10
|
2023-05-24 04:50:23 -07:00
|
|
|
|
|
|
|
let minOrderSize = 0
|
|
|
|
let priceIncrement = 0
|
2023-05-25 04:39:33 -07:00
|
|
|
let baseLotExponent = 0
|
|
|
|
let quoteLotExponent = 0
|
2023-05-24 16:22:13 -07:00
|
|
|
let minOrderValue = 0
|
|
|
|
let priceIncrementRelative = 0
|
2023-05-24 04:50:23 -07:00
|
|
|
|
|
|
|
// Calculate minimum order size
|
|
|
|
do {
|
|
|
|
minOrderSize = Math.pow(10, baseLotExponent - baseDecimals)
|
2023-05-24 16:22:13 -07:00
|
|
|
minOrderValue = basePrice * minOrderSize
|
2023-05-23 13:00:02 -07:00
|
|
|
|
2023-05-25 04:39:33 -07:00
|
|
|
if (minOrderValue > MAX_MIN_ORDER_VALUE) {
|
2023-05-24 04:50:23 -07:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2023-05-25 04:39:33 -07:00
|
|
|
baseLotExponent++
|
2023-05-25 13:06:22 -07:00
|
|
|
} while (baseLotExponent < EXPONENT_THRESHOLD)
|
2023-05-24 04:50:23 -07:00
|
|
|
|
|
|
|
// Calculate price increment
|
|
|
|
do {
|
|
|
|
priceIncrement = Math.pow(
|
|
|
|
10,
|
|
|
|
quoteLotExponent + baseDecimals - baseLotExponent - quoteDecimals
|
|
|
|
)
|
2023-05-25 09:09:12 -07:00
|
|
|
priceIncrementRelative = (priceIncrement * quotePrice) / basePrice
|
2023-05-25 04:39:33 -07:00
|
|
|
if (priceIncrementRelative > MIN_PRICE_INCREMENT_RELATIVE) {
|
2023-05-24 04:50:23 -07:00
|
|
|
break
|
|
|
|
}
|
2023-05-23 07:10:22 -07:00
|
|
|
|
2023-05-25 04:39:33 -07:00
|
|
|
quoteLotExponent++
|
2023-05-25 13:06:22 -07:00
|
|
|
} while (quoteLotExponent < EXPONENT_THRESHOLD)
|
2023-05-25 04:39:33 -07:00
|
|
|
|
2023-05-25 13:06:22 -07:00
|
|
|
//exception override values in that case example eth/btc market
|
2023-05-25 10:06:37 -07:00
|
|
|
if (
|
|
|
|
quoteLotExponent === 0 &&
|
|
|
|
priceIncrementRelative > 0.001 &&
|
|
|
|
minOrderSize < 1
|
|
|
|
) {
|
|
|
|
baseLotExponent = baseLotExponent + 1
|
|
|
|
minOrderSize = Math.pow(10, baseLotExponent - baseDecimals)
|
|
|
|
minOrderValue = basePrice * minOrderSize
|
|
|
|
priceIncrement = Math.pow(
|
|
|
|
10,
|
|
|
|
quoteLotExponent + baseDecimals - baseLotExponent - quoteDecimals
|
|
|
|
)
|
|
|
|
priceIncrementRelative = (priceIncrement * quotePrice) / basePrice
|
|
|
|
}
|
|
|
|
|
2023-05-23 07:10:22 -07:00
|
|
|
return {
|
2023-05-25 13:06:22 -07:00
|
|
|
baseLots: Math.pow(10, baseLotExponent),
|
|
|
|
quoteLots: Math.pow(10, quoteLotExponent),
|
2023-05-24 16:22:13 -07:00
|
|
|
minOrderValue: minOrderValue,
|
|
|
|
baseLotExponent: baseLotExponent,
|
|
|
|
quoteLotExponent: quoteLotExponent,
|
2023-05-25 13:06:22 -07:00
|
|
|
minOrderSize: minOrderSize,
|
|
|
|
priceIncrement: priceIncrement,
|
2023-05-24 16:22:13 -07:00
|
|
|
priceIncrementRelative: priceIncrementRelative,
|
2023-05-23 07:10:22 -07:00
|
|
|
}
|
|
|
|
}
|
2023-05-23 13:00:02 -07:00
|
|
|
|
|
|
|
export const getQuoteSymbol = (quoteTokenSymbol: string) => {
|
|
|
|
if (
|
|
|
|
quoteTokenSymbol.toLowerCase() === 'usdc' ||
|
|
|
|
quoteTokenSymbol.toLocaleLowerCase() === 'usdt'
|
|
|
|
) {
|
|
|
|
return 'usd'
|
|
|
|
}
|
|
|
|
return quoteTokenSymbol
|
|
|
|
}
|
2023-06-06 15:54:44 -07:00
|
|
|
|
|
|
|
const listingBase = {
|
|
|
|
maxStalenessSlots: 120 as number | null,
|
|
|
|
oracleConfFilter: 0.1,
|
|
|
|
adjustmentFactor: 0.004,
|
|
|
|
util0: 0.5,
|
|
|
|
rate0: 0.052,
|
|
|
|
util1: 0.8,
|
|
|
|
rate1: 0.1446,
|
|
|
|
maxRate: 1.4456,
|
|
|
|
loanFeeRate: 0.005,
|
|
|
|
loanOriginationFeeRate: 0.001,
|
|
|
|
maintAssetWeight: 0.9,
|
|
|
|
initAssetWeight: 0.8,
|
|
|
|
maintLiabWeight: 1.1,
|
|
|
|
initLiabWeight: 1.2,
|
|
|
|
liquidationFee: 0.05,
|
|
|
|
minVaultToDepositsRatio: 0.2,
|
|
|
|
netBorrowLimitWindowSizeTs: 24 * 60 * 60,
|
|
|
|
netBorrowLimitPerWindowQuote: toNative(50000, 6).toNumber(),
|
|
|
|
insuranceFound: true,
|
|
|
|
borrowWeightScale: toNative(250000, 6).toNumber(),
|
|
|
|
depositWeightScale: toNative(250000, 6).toNumber(),
|
2023-06-26 05:48:37 -07:00
|
|
|
preset_key: 'PREMIUM',
|
|
|
|
preset_name: 'Blue chip',
|
|
|
|
target_amount: 100000,
|
2023-06-06 15:54:44 -07:00
|
|
|
}
|
|
|
|
|
2023-06-26 05:48:37 -07:00
|
|
|
export type ListingPreset = typeof listingBase
|
|
|
|
|
2023-06-08 02:14:46 -07:00
|
|
|
export type LISTING_PRESETS_KEYS =
|
|
|
|
| 'PREMIUM'
|
|
|
|
| 'MID'
|
|
|
|
| 'MEME'
|
|
|
|
| 'SHIT'
|
|
|
|
| 'UNTRUSTED'
|
|
|
|
|
2023-06-06 15:54:44 -07:00
|
|
|
export const LISTING_PRESETS: {
|
2023-06-26 05:48:37 -07:00
|
|
|
[key in LISTING_PRESETS_KEYS]: ListingPreset | Record<string, never>
|
2023-06-06 15:54:44 -07:00
|
|
|
} = {
|
|
|
|
//Price impact $100,000 < 1%
|
|
|
|
PREMIUM: {
|
|
|
|
...listingBase,
|
|
|
|
},
|
|
|
|
//Price impact $20,000 < 1%
|
|
|
|
MID: {
|
|
|
|
...listingBase,
|
|
|
|
maintAssetWeight: 0.75,
|
|
|
|
initAssetWeight: 0.5,
|
|
|
|
maintLiabWeight: 1.2,
|
|
|
|
initLiabWeight: 1.4,
|
|
|
|
liquidationFee: 0.1,
|
|
|
|
netBorrowLimitPerWindowQuote: toNative(20000, 6).toNumber(),
|
|
|
|
borrowWeightScale: toNative(50000, 6).toNumber(),
|
|
|
|
depositWeightScale: toNative(50000, 6).toNumber(),
|
|
|
|
insuranceFound: false,
|
2023-06-26 05:48:37 -07:00
|
|
|
preset_key: 'MID',
|
|
|
|
preset_name: 'Midwit',
|
|
|
|
target_amount: 20000,
|
2023-06-06 15:54:44 -07:00
|
|
|
},
|
|
|
|
//Price impact $5,000 < 1%
|
|
|
|
MEME: {
|
|
|
|
...listingBase,
|
|
|
|
maxStalenessSlots: 800,
|
|
|
|
loanOriginationFeeRate: 0.002,
|
|
|
|
maintAssetWeight: 0,
|
|
|
|
initAssetWeight: 0,
|
|
|
|
maintLiabWeight: 1.25,
|
|
|
|
initLiabWeight: 1.5,
|
|
|
|
liquidationFee: 0.125,
|
|
|
|
netBorrowLimitPerWindowQuote: toNative(5000, 6).toNumber(),
|
|
|
|
borrowWeightScale: toNative(20000, 6).toNumber(),
|
|
|
|
depositWeightScale: toNative(20000, 6).toNumber(),
|
|
|
|
insuranceFound: false,
|
2023-06-26 05:48:37 -07:00
|
|
|
preset_key: 'MEME',
|
|
|
|
preset_name: 'Meme Coin',
|
|
|
|
target_amount: 5000,
|
2023-06-06 15:54:44 -07:00
|
|
|
},
|
|
|
|
//Price impact $1,000 < 1%
|
|
|
|
SHIT: {
|
|
|
|
...listingBase,
|
|
|
|
maxStalenessSlots: 800,
|
|
|
|
loanOriginationFeeRate: 0.002,
|
|
|
|
maintAssetWeight: 0,
|
|
|
|
initAssetWeight: 0,
|
|
|
|
maintLiabWeight: 1.4,
|
|
|
|
initLiabWeight: 1.8,
|
|
|
|
liquidationFee: 0.2,
|
|
|
|
netBorrowLimitPerWindowQuote: toNative(1000, 6).toNumber(),
|
|
|
|
borrowWeightScale: toNative(5000, 6).toNumber(),
|
|
|
|
depositWeightScale: toNative(5000, 6).toNumber(),
|
|
|
|
insuranceFound: false,
|
2023-06-26 05:48:37 -07:00
|
|
|
preset_key: 'SHIT',
|
|
|
|
preset_name: 'Shit Coin',
|
|
|
|
target_amount: 1000,
|
2023-06-06 15:54:44 -07:00
|
|
|
},
|
2023-06-08 02:14:46 -07:00
|
|
|
UNTRUSTED: {},
|
2023-06-06 15:54:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export const coinTiersToNames: {
|
2023-06-08 02:14:46 -07:00
|
|
|
[key in LISTING_PRESETS_KEYS]: string
|
2023-06-06 15:54:44 -07:00
|
|
|
} = {
|
|
|
|
PREMIUM: 'Blue Chip',
|
|
|
|
MID: 'Mid-wit',
|
|
|
|
MEME: 'Meme',
|
|
|
|
SHIT: 'Shit Coin',
|
2023-06-08 02:14:46 -07:00
|
|
|
UNTRUSTED: 'Untrusted',
|
2023-06-06 15:54:44 -07:00
|
|
|
}
|
2023-06-26 05:48:37 -07:00
|
|
|
|
|
|
|
export const formatSuggestedValues = (
|
|
|
|
suggestedParams:
|
|
|
|
| Record<string, never>
|
|
|
|
| Omit<
|
|
|
|
typeof listingBase,
|
|
|
|
'name' | 'netBorrowLimitWindowSizeTs' | 'insuranceFound'
|
|
|
|
>
|
|
|
|
) => {
|
|
|
|
return {
|
|
|
|
maxStalenessSlots: suggestedParams.maxStalenessSlots,
|
|
|
|
oracleConfFilter: (100 * suggestedParams.oracleConfFilter).toFixed(2),
|
|
|
|
adjustmentFactor: (suggestedParams.adjustmentFactor * 100).toFixed(2),
|
|
|
|
rate0: (100 * suggestedParams.rate0).toFixed(2),
|
|
|
|
util0: (100 * suggestedParams.util0).toFixed(),
|
|
|
|
rate1: (100 * suggestedParams.rate1).toFixed(2),
|
|
|
|
util1: (100 * suggestedParams.util1).toFixed(),
|
|
|
|
maxRate: (100 * suggestedParams.maxRate).toFixed(2),
|
|
|
|
loanFeeRate: (10000 * suggestedParams.loanFeeRate).toFixed(2),
|
|
|
|
loanOriginationFeeRate: (
|
|
|
|
10000 * suggestedParams.loanOriginationFeeRate
|
|
|
|
).toFixed(2),
|
|
|
|
maintAssetWeight: suggestedParams.maintAssetWeight.toFixed(2),
|
|
|
|
initAssetWeight: suggestedParams.initAssetWeight.toFixed(2),
|
|
|
|
maintLiabWeight: suggestedParams.maintLiabWeight.toFixed(2),
|
|
|
|
initLiabWeight: suggestedParams.initLiabWeight.toFixed(2),
|
|
|
|
liquidationFee: (suggestedParams.liquidationFee * 100).toFixed(2),
|
|
|
|
minVaultToDepositsRatio: suggestedParams.minVaultToDepositsRatio * 100,
|
|
|
|
netBorrowLimitPerWindowQuote: toUiDecimals(
|
|
|
|
suggestedParams.netBorrowLimitPerWindowQuote,
|
|
|
|
6
|
|
|
|
),
|
|
|
|
borrowWeightScale: toUiDecimals(suggestedParams.borrowWeightScale, 6),
|
|
|
|
depositWeightScale: toUiDecimals(suggestedParams.depositWeightScale, 6),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getFormattedBankValues = (group: Group, bank: Bank) => {
|
|
|
|
return {
|
|
|
|
...bank,
|
|
|
|
publicKey: bank.publicKey.toBase58(),
|
|
|
|
vault: bank.vault.toBase58(),
|
|
|
|
oracle: bank.oracle.toBase58(),
|
|
|
|
stablePrice: group.toUiPrice(
|
|
|
|
I80F48.fromNumber(bank.stablePriceModel.stablePrice),
|
|
|
|
bank.mintDecimals
|
|
|
|
),
|
|
|
|
maxStalenessSlots: bank.oracleConfig.maxStalenessSlots.toNumber(),
|
|
|
|
lastStablePriceUpdated: new Date(
|
|
|
|
1000 * bank.stablePriceModel.lastUpdateTimestamp.toNumber()
|
|
|
|
).toUTCString(),
|
|
|
|
stablePriceGrowthLimitsDelay: (
|
|
|
|
100 * bank.stablePriceModel.delayGrowthLimit
|
|
|
|
).toFixed(2),
|
|
|
|
stablePriceGrowthLimitsStable: (
|
|
|
|
100 * bank.stablePriceModel.stableGrowthLimit
|
|
|
|
).toFixed(2),
|
|
|
|
loanFeeRate: (10000 * bank.loanFeeRate.toNumber()).toFixed(2),
|
|
|
|
loanOriginationFeeRate: (
|
|
|
|
10000 * bank.loanOriginationFeeRate.toNumber()
|
|
|
|
).toFixed(2),
|
|
|
|
collectedFeesNative: toUiDecimals(
|
|
|
|
bank.collectedFeesNative.toNumber(),
|
|
|
|
bank.mintDecimals
|
|
|
|
).toFixed(2),
|
|
|
|
collectedFeesNativePrice: (
|
|
|
|
toUiDecimals(bank.collectedFeesNative.toNumber(), bank.mintDecimals) *
|
|
|
|
bank.uiPrice
|
|
|
|
).toFixed(2),
|
|
|
|
dust: bank.dust.toNumber(),
|
|
|
|
deposits: toUiDecimals(
|
|
|
|
bank.indexedDeposits.mul(bank.depositIndex).toNumber(),
|
|
|
|
bank.mintDecimals
|
|
|
|
),
|
|
|
|
depositsPrice: (
|
|
|
|
toUiDecimals(
|
|
|
|
bank.indexedDeposits.mul(bank.depositIndex).toNumber(),
|
|
|
|
bank.mintDecimals
|
|
|
|
) * bank.uiPrice
|
|
|
|
).toFixed(2),
|
|
|
|
borrows: toUiDecimals(
|
|
|
|
bank.indexedBorrows.mul(bank.borrowIndex).toNumber(),
|
|
|
|
bank.mintDecimals
|
|
|
|
),
|
|
|
|
borrowsPrice: (
|
|
|
|
toUiDecimals(
|
|
|
|
bank.indexedBorrows.mul(bank.borrowIndex).toNumber(),
|
|
|
|
bank.mintDecimals
|
|
|
|
) * bank.uiPrice
|
|
|
|
).toFixed(2),
|
|
|
|
avgUtilization: bank.avgUtilization.toNumber() * 100,
|
|
|
|
maintAssetWeight: bank.maintAssetWeight.toFixed(2),
|
|
|
|
maintLiabWeight: bank.maintLiabWeight.toFixed(2),
|
|
|
|
initAssetWeight: bank.initAssetWeight.toFixed(2),
|
|
|
|
initLiabWeight: bank.initLiabWeight.toFixed(2),
|
2023-07-09 02:47:52 -07:00
|
|
|
scaledInitAssetWeight: bank.scaledInitAssetWeight(bank.price).toFixed(2),
|
|
|
|
scaledInitLiabWeight: bank.scaledInitLiabWeight(bank.price).toFixed(2),
|
2023-06-26 05:48:37 -07:00
|
|
|
depositWeightScale: toUiDecimalsForQuote(bank.depositWeightScaleStartQuote),
|
|
|
|
borrowWeightScale: toUiDecimalsForQuote(bank.borrowWeightScaleStartQuote),
|
|
|
|
rate0: (100 * bank.rate0.toNumber()).toFixed(2),
|
|
|
|
util0: (100 * bank.util0.toNumber()).toFixed(),
|
|
|
|
rate1: (100 * bank.rate1.toNumber()).toFixed(2),
|
|
|
|
util1: (100 * bank.util1.toNumber()).toFixed(),
|
|
|
|
maxRate: (100 * bank.maxRate.toNumber()).toFixed(2),
|
|
|
|
adjustmentFactor: (bank.adjustmentFactor.toNumber() * 100).toFixed(2),
|
|
|
|
depositRate: bank.getDepositRateUi(),
|
|
|
|
borrowRate: bank.getBorrowRateUi(),
|
|
|
|
lastIndexUpdate: new Date(
|
|
|
|
1000 * bank.indexLastUpdated.toNumber()
|
|
|
|
).toUTCString(),
|
|
|
|
lastRatesUpdate: new Date(
|
|
|
|
1000 * bank.bankRateLastUpdated.toNumber()
|
|
|
|
).toUTCString(),
|
|
|
|
oracleConfFilter: (100 * bank.oracleConfig.confFilter.toNumber()).toFixed(
|
|
|
|
2
|
|
|
|
),
|
|
|
|
minVaultToDepositsRatio: bank.minVaultToDepositsRatio * 100,
|
|
|
|
netBorrowsInWindow: toUiDecimalsForQuote(
|
|
|
|
I80F48.fromI64(bank.netBorrowsInWindow).mul(bank.price)
|
|
|
|
).toFixed(2),
|
|
|
|
netBorrowLimitPerWindowQuote: toUiDecimals(
|
|
|
|
bank.netBorrowLimitPerWindowQuote,
|
|
|
|
6
|
|
|
|
),
|
|
|
|
liquidationFee: (bank.liquidationFee.toNumber() * 100).toFixed(2),
|
|
|
|
}
|
|
|
|
}
|