Add staleness param to OracleConfig

Since Bank can't expand the existing OracleConfig, add a new one to Bank
and (temporarily!) copy over the old value to the new one in
TokenUpdateIndexAndRate.

Add some reserved space to OracleConfig to make this easier in the
future.

Breaks the PerpMarket and PerpPosition layouts
This commit is contained in:
Christian Kamm 2022-11-09 13:25:53 +01:00
parent f5e47c47bd
commit 58f7ff2e0e
20 changed files with 396 additions and 383 deletions

View File

@ -48,7 +48,7 @@ pub fn perp_create_market(
settle_token_index: TokenIndex,
perp_market_index: PerpMarketIndex,
name: String,
oracle_config: OracleConfig,
oracle_config: OracleConfigParams,
base_decimals: u8,
quote_lot_size: i64,
base_lot_size: i64,
@ -91,7 +91,7 @@ pub fn perp_create_market(
trusted_market: if trusted_market { 1 } else { 0 },
name: fill_from_str(&name)?,
oracle: ctx.accounts.oracle.key(),
oracle_config,
oracle_config: oracle_config.to_oracle_config(),
orderbook: ctx.accounts.orderbook.key(),
event_queue: ctx.accounts.event_queue.key(),
quote_lot_size,
@ -118,12 +118,11 @@ pub fn perp_create_market(
registration_time: now_ts,
padding1: Default::default(),
padding2: Default::default(),
padding3: Default::default(),
fee_penalty,
settle_fee_flat,
settle_fee_amount_threshold,
settle_fee_fraction_low_health,
reserved: [0; 92],
reserved: [0; 2244],
};
let mut orderbook = ctx.accounts.orderbook.load_init()?;

View File

@ -23,7 +23,7 @@ pub struct PerpEditMarket<'info> {
pub fn perp_edit_market(
ctx: Context<PerpEditMarket>,
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfig>,
oracle_config_opt: Option<OracleConfigParams>,
base_decimals_opt: Option<u8>,
maint_asset_weight_opt: Option<f32>,
init_asset_weight_opt: Option<f32>,
@ -55,7 +55,7 @@ pub fn perp_edit_market(
perp_market.oracle = oracle;
}
if let Some(oracle_config) = oracle_config_opt {
perp_market.oracle_config = oracle_config;
perp_market.oracle_config = oracle_config.to_oracle_config();
};
// unchanged -

View File

@ -33,7 +33,7 @@ pub struct TokenEdit<'info> {
pub fn token_edit(
ctx: Context<TokenEdit>,
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfig>,
oracle_config_opt: Option<OracleConfigParams>,
group_insurance_fund_opt: Option<bool>,
interest_rate_params_opt: Option<InterestRateParams>,
loan_fee_rate_opt: Option<f32>,
@ -63,8 +63,9 @@ pub fn token_edit(
bank.oracle = oracle;
mint_info.oracle = oracle;
}
if let Some(oracle_config) = oracle_config_opt {
bank.oracle_config = oracle_config;
if let Some(oracle_config) = oracle_config_opt.as_ref() {
bank.oracle_config = oracle_config.to_oracle_config();
bank.oracle_conf_filter = bank.oracle_config.conf_filter;
};
if let Some(group_insurance_fund) = group_insurance_fund_opt {

View File

@ -80,7 +80,7 @@ pub fn token_register(
ctx: Context<TokenRegister>,
token_index: TokenIndex,
name: String,
oracle_config: OracleConfig,
oracle_config: OracleConfigParams,
interest_rate_params: InterestRateParams,
loan_fee_rate: f32,
loan_origination_fee_rate: f32,
@ -105,7 +105,6 @@ pub fn token_register(
mint: ctx.accounts.mint.key(),
vault: ctx.accounts.vault.key(),
oracle: ctx.accounts.oracle.key(),
oracle_config,
deposit_index: INDEX_START,
borrow_index: INDEX_START,
cached_indexed_total_deposits: I80F48::ZERO,
@ -137,7 +136,9 @@ pub fn token_register(
bump: *ctx.bumps.get("bank").ok_or(MangoError::SomeError)?,
mint_decimals: ctx.accounts.mint.decimals,
bank_num: 0,
reserved: [0; 2560],
oracle_conf_filter: oracle_config.to_oracle_config().conf_filter,
oracle_config: oracle_config.to_oracle_config(),
reserved: [0; 2464],
};
require_gt!(bank.max_rate, MINIMUM_MAX_RATE);

View File

@ -78,9 +78,6 @@ pub fn token_register_trustless(
mint: ctx.accounts.mint.key(),
vault: ctx.accounts.vault.key(),
oracle: ctx.accounts.oracle.key(),
oracle_config: OracleConfig {
conf_filter: I80F48::from_num(0.10),
},
deposit_index: INDEX_START,
borrow_index: INDEX_START,
cached_indexed_total_deposits: I80F48::ZERO,
@ -112,7 +109,13 @@ pub fn token_register_trustless(
bump: *ctx.bumps.get("bank").ok_or(MangoError::SomeError)?,
mint_decimals: ctx.accounts.mint.decimals,
bank_num: 0,
reserved: [0; 2560],
oracle_conf_filter: I80F48::from_num(0.10),
oracle_config: OracleConfig {
conf_filter: I80F48::from_num(0.10),
max_staleness_slots: -1,
reserved: [0; 72],
},
reserved: [0; 2464],
};
require_gt!(bank.max_rate, MINIMUM_MAX_RATE);

View File

@ -142,6 +142,11 @@ pub fn token_update_index_and_rate(ctx: Context<TokenUpdateIndexAndRate>) -> Res
bank.borrow_index = borrow_index;
bank.avg_utilization = new_avg_utilization;
// This copies the old conf_filter parameter location to the new one
// inside OracleConfig.
// TODO: remove once fully migrated to OracleConfig
bank.oracle_config.conf_filter = bank.oracle_conf_filter;
}
}

View File

@ -20,15 +20,14 @@ pub mod serum3_cpi;
pub mod state;
pub mod types;
use state::{OracleConfig, PerpMarketIndex, PlaceOrderType, Serum3MarketIndex, Side, TokenIndex};
use state::{
OracleConfigParams, PerpMarketIndex, PlaceOrderType, Serum3MarketIndex, Side, TokenIndex,
};
declare_id!("m43thNJ58XCjL798ZSq6JGAG1BnWskhdq5or6kcnfsD");
#[program]
pub mod mango_v4 {
use crate::state::OracleConfig;
use super::*;
pub fn group_create(
@ -69,7 +68,7 @@ pub mod mango_v4 {
ctx: Context<TokenRegister>,
token_index: TokenIndex,
name: String,
oracle_config: OracleConfig,
oracle_config: OracleConfigParams,
interest_rate_params: InterestRateParams,
loan_fee_rate: f32,
loan_origination_fee_rate: f32,
@ -107,7 +106,7 @@ pub mod mango_v4 {
pub fn token_edit(
ctx: Context<TokenEdit>,
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfig>,
oracle_config_opt: Option<OracleConfigParams>,
group_insurance_fund_opt: Option<bool>,
interest_rate_params_opt: Option<InterestRateParams>,
loan_fee_rate_opt: Option<f32>,
@ -393,7 +392,7 @@ pub mod mango_v4 {
ctx: Context<PerpCreateMarket>,
perp_market_index: PerpMarketIndex,
name: String,
oracle_config: OracleConfig,
oracle_config: OracleConfigParams,
base_decimals: u8,
quote_lot_size: i64,
base_lot_size: i64,
@ -447,7 +446,7 @@ pub mod mango_v4 {
pub fn perp_edit_market(
ctx: Context<PerpEditMarket>,
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfig>,
oracle_config_opt: Option<OracleConfigParams>,
base_decimals_opt: Option<u8>,
maint_asset_weight_opt: Option<f32>,
init_asset_weight_opt: Option<f32>,

View File

@ -31,7 +31,8 @@ pub struct Bank {
pub vault: Pubkey,
pub oracle: Pubkey,
pub oracle_config: OracleConfig,
// TODO: Merge with oracle_config once Bank re-layouts are possible
pub oracle_conf_filter: I80F48,
/// the index used to scale the value of an IndexedPosition
/// TODO: should always be >= 0, add checks?
@ -101,12 +102,14 @@ pub struct Bank {
pub bank_num: u32,
pub oracle_config: OracleConfig,
#[derivative(Debug = "ignore")]
pub reserved: [u8; 2560],
pub reserved: [u8; 2464],
}
const_assert_eq!(
size_of::<Bank>(),
32 + 16 + 32 * 3 + 16 + 16 * 6 + 8 * 2 + 16 * 16 + 8 * 2 + 2 + 1 + 1 + 4 + 2560
32 + 16 + 32 * 3 + 16 + 16 * 6 + 8 * 2 + 16 * 16 + 8 * 2 + 2 + 1 + 1 + 4 + 96 + 2464
);
const_assert_eq!(size_of::<Bank>() % 8, 0);
@ -136,7 +139,7 @@ impl Bank {
group: existing_bank.group,
mint: existing_bank.mint,
oracle: existing_bank.oracle,
oracle_config: existing_bank.oracle_config,
oracle_conf_filter: existing_bank.oracle_conf_filter,
deposit_index: existing_bank.deposit_index,
borrow_index: existing_bank.borrow_index,
cached_indexed_total_deposits: existing_bank.cached_indexed_total_deposits,
@ -159,7 +162,8 @@ impl Bank {
liquidation_fee: existing_bank.liquidation_fee,
token_index: existing_bank.token_index,
mint_decimals: existing_bank.mint_decimals,
reserved: [0; 2560],
oracle_config: existing_bank.oracle_config.clone(),
reserved: [0; 2464],
}
}
@ -581,11 +585,7 @@ impl Bank {
pub fn oracle_price(&self, oracle_acc: &impl KeyedAccountReader) -> Result<I80F48> {
require_keys_eq!(self.oracle, *oracle_acc.key());
oracle::oracle_price(
oracle_acc,
self.oracle_config.conf_filter,
self.mint_decimals,
)
oracle::oracle_price(oracle_acc, &self.oracle_config, self.mint_decimals)
}
}

View File

@ -31,6 +31,7 @@ pub struct TokenPosition {
#[derivative(Debug = "ignore")]
pub padding: [u8; 5],
// TODO: When re-layouting: move this to the end
#[derivative(Debug = "ignore")]
pub reserved: [u8; 8],
@ -191,9 +192,6 @@ pub struct PerpPosition {
pub taker_base_lots: i64,
pub taker_quote_lots: i64,
#[derivative(Debug = "ignore")]
pub reserved: [u8; 24],
// (Display only)
// Cumulative long funding in base native units
pub cumulative_long_funding: f64,
@ -209,6 +207,9 @@ pub struct PerpPosition {
// (Display only)
// Cumulative realized pnl in quote native units
pub perp_spot_transfers: i64,
#[derivative(Debug = "ignore")]
pub reserved: [u8; 24],
}
const_assert_eq!(size_of::<PerpPosition>(), 8 + 7 * 8 + 3 * 16 + 64);
const_assert_eq!(size_of::<PerpPosition>() % 8, 0);
@ -228,7 +229,6 @@ impl Default for PerpPosition {
asks_base_lots: 0,
taker_base_lots: 0,
taker_quote_lots: 0,
reserved: [0; 24],
long_settled_funding: I80F48::ZERO,
short_settled_funding: I80F48::ZERO,
padding: Default::default(),
@ -237,6 +237,7 @@ impl Default for PerpPosition {
maker_volume: 0,
taker_volume: 0,
perp_spot_transfers: 0,
reserved: [0; 24],
}
}
}

View File

@ -60,10 +60,28 @@ pub mod switchboard_v2_mainnet_oracle {
#[derive(AnchorDeserialize, AnchorSerialize, Debug)]
pub struct OracleConfig {
pub conf_filter: I80F48,
pub max_staleness_slots: i64,
pub reserved: [u8; 72],
}
const_assert_eq!(size_of::<OracleConfig>(), 16);
const_assert_eq!(size_of::<OracleConfig>(), 96);
const_assert_eq!(size_of::<OracleConfig>() % 8, 0);
#[derive(AnchorDeserialize, AnchorSerialize, Debug)]
pub struct OracleConfigParams {
pub conf_filter: f32,
pub max_staleness_slots: Option<u32>,
}
impl OracleConfigParams {
pub fn to_oracle_config(&self) -> OracleConfig {
OracleConfig {
conf_filter: I80F48::from_num(self.conf_filter),
max_staleness_slots: self.max_staleness_slots.map(|v| v as i64).unwrap_or(-1),
reserved: [0; 72],
}
}
}
#[derive(PartialEq)]
pub enum OracleType {
Pyth,
@ -115,7 +133,7 @@ pub fn determine_oracle_type(acc_info: &impl KeyedAccountReader) -> Result<Oracl
/// This currently assumes that quote decimals is 6, like for USDC.
pub fn oracle_price(
acc_info: &impl KeyedAccountReader,
oracle_conf_filter: I80F48,
config: &OracleConfig,
base_decimals: u8,
) -> Result<I80F48> {
let data = &acc_info.data();
@ -128,7 +146,7 @@ pub fn oracle_price(
let price = I80F48::from_num(price_account.price);
// Filter out bad prices
if I80F48::from_num(price_account.conf) > cm!(oracle_conf_filter * price) {
if I80F48::from_num(price_account.conf) > cm!(config.conf_filter * price) {
msg!(
"Pyth conf interval too high; pubkey {} price: {} price_account.conf: {}",
acc_info.key(),
@ -162,7 +180,7 @@ pub fn oracle_price(
.std_deviation
.try_into()
.map_err(from_foreign_error)?;
if I80F48::from_num(std_deviation_decimal) > cm!(oracle_conf_filter * price) {
if I80F48::from_num(std_deviation_decimal) > cm!(config.conf_filter * price) {
msg!(
"Switchboard v2 std deviation too high; pubkey {} price: {} latest_confirmed_round.std_deviation: {}",
acc_info.key(),
@ -183,7 +201,7 @@ pub fn oracle_price(
// Filter out bad prices
let min_response = I80F48::from_num(result.result.min_response);
let max_response = I80F48::from_num(result.result.max_response);
if cm!(max_response - min_response) > cm!(oracle_conf_filter * price) {
if cm!(max_response - min_response) > cm!(config.conf_filter * price) {
msg!(
"Switchboard v1 min-max response gap too wide; pubkey {} price: {} min_response: {} max_response {}",
acc_info.key(),

View File

@ -41,7 +41,6 @@ pub struct PerpMarket {
pub oracle_config: OracleConfig,
pub orderbook: Pubkey,
pub padding3: [u8; 32],
pub event_queue: Pubkey,
@ -110,10 +109,10 @@ pub struct PerpMarket {
/// Fraction of pnl to pay out as fee if +pnl account has low health.
pub settle_fee_fraction_low_health: f32,
pub reserved: [u8; 92],
pub reserved: [u8; 2244],
}
const_assert_eq!(size_of::<PerpMarket>(), 584);
const_assert_eq!(size_of::<PerpMarket>(), 2784);
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
impl PerpMarket {
@ -142,11 +141,7 @@ impl PerpMarket {
pub fn oracle_price(&self, oracle_acc: &impl KeyedAccountReader) -> Result<I80F48> {
require_keys_eq!(self.oracle, *oracle_acc.key());
oracle::oracle_price(
oracle_acc,
self.oracle_config.conf_filter,
self.base_decimals,
)
oracle::oracle_price(oracle_acc, &self.oracle_config, self.base_decimals)
}
/// Use current order book price and index price to update the instantaneous funding
@ -263,6 +258,8 @@ impl PerpMarket {
oracle: Pubkey::new_unique(),
oracle_config: OracleConfig {
conf_filter: I80F48::ZERO,
max_staleness_slots: -1,
reserved: [0; 72],
},
orderbook: Pubkey::new_unique(),
event_queue: Pubkey::new_unique(),
@ -287,10 +284,9 @@ impl PerpMarket {
fees_settled: I80F48::ZERO,
bump: 0,
base_decimals: 0,
reserved: [0; 92],
reserved: [0; 2244],
padding1: Default::default(),
padding2: Default::default(),
padding3: Default::default(),
registration_time: 0,
fee_penalty: 0.0,
trusted_market: 0,

View File

@ -742,8 +742,9 @@ impl ClientInstruction for TokenRegisterInstruction {
self.token_index.to_string()
),
token_index: self.token_index,
oracle_config: OracleConfig {
conf_filter: I80F48::from_num::<f32>(0.10),
oracle_config: OracleConfigParams {
conf_filter: 0.1,
max_staleness_slots: None,
},
interest_rate_params: InterestRateParams {
adjustment_factor: self.adjustment_factor,
@ -2261,8 +2262,9 @@ impl ClientInstruction for PerpCreateMarketInstruction {
let program_id = mango_v4::id();
let instruction = Self::Instruction {
name: "UUU-PERP".to_string(),
oracle_config: OracleConfig {
conf_filter: I80F48::from_num::<f32>(0.10),
oracle_config: OracleConfigParams {
conf_filter: 0.1,
max_staleness_slots: None,
},
settle_token_index: self.settle_token_index,
perp_market_index: self.perp_market_index,

View File

@ -10,6 +10,8 @@ export type TokenIndex = number & As<'token-index'>;
export type OracleConfig = {
confFilter: I80F48Dto;
maxStalenessSlots: BN;
reserved: number[];
};
export interface BankForHealth {

View File

@ -24,7 +24,7 @@ import {
TransactionSignature,
} from '@solana/web3.js';
import bs58 from 'bs58';
import { Bank, MintInfo, TokenIndex } from './accounts/bank';
import { Bank, MintInfo, TokenIndex, OracleConfig } from './accounts/bank';
import { Group } from './accounts/group';
import {
MangoAccount,
@ -52,7 +52,7 @@ import { SERUM3_PROGRAM_ID } from './constants';
import { Id } from './ids';
import { IDL, MangoV4 } from './mango_v4';
import { I80F48 } from './numbers/I80F48';
import { FlashLoanType, InterestRateParams } from './types';
import { FlashLoanType, InterestRateParams, OracleConfigParams } from './types';
import {
createAssociatedTokenAccountIdempotentInstruction,
getAssociatedTokenAddress,
@ -236,15 +236,10 @@ export class MangoClient {
group: Group,
mintPk: PublicKey,
oraclePk: PublicKey,
oracleConfFilter: number,
oracleConfig: OracleConfigParams,
tokenIndex: number,
name: string,
adjustmentFactor: number,
util0: number,
rate0: number,
util1: number,
rate1: number,
maxRate: number,
interestRateParams: InterestRateParams,
loanFeeRate: number,
loanOriginationFeeRate: number,
maintAssetWeight: number,
@ -257,12 +252,8 @@ export class MangoClient {
.tokenRegister(
tokenIndex,
name,
{
confFilter: {
val: I80F48.fromNumber(oracleConfFilter).getData(),
},
} as any, // future: nested custom types dont typecheck, fix if possible?
{ adjustmentFactor, util0, rate0, util1, rate1, maxRate },
oracleConfig,
interestRateParams,
loanFeeRate,
loanOriginationFeeRate,
maintAssetWeight,
@ -307,7 +298,7 @@ export class MangoClient {
group: Group,
mintPk: PublicKey,
oracle: PublicKey | null,
oracleConfFilter: number | null,
oracleConfig: OracleConfigParams | null,
groupInsuranceFund: boolean | null,
interestRateParams: InterestRateParams | null,
loanFeeRate: number | null,
@ -321,21 +312,10 @@ export class MangoClient {
const bank = group.getFirstBankByMint(mintPk);
const mintInfo = group.mintInfosMapByTokenIndex.get(bank.tokenIndex)!;
let oracleConf;
if (oracleConfFilter !== null) {
oracleConf = {
confFilter: {
val: I80F48.fromNumber(oracleConfFilter).getData(),
},
} as any; // future: nested custom types dont typecheck, fix if possible?
} else {
oracleConf = null;
}
return await this.program.methods
.tokenEdit(
oracle,
oracleConf,
oracleConfig,
groupInsuranceFund,
interestRateParams,
loanFeeRate,
@ -1384,7 +1364,7 @@ export class MangoClient {
oraclePk: PublicKey,
perpMarketIndex: number,
name: string,
oracleConfFilter: number,
oracleConfig: OracleConfigParams,
baseDecimals: number,
quoteLotSize: number,
baseLotSize: number,
@ -1421,11 +1401,7 @@ export class MangoClient {
.perpCreateMarket(
perpMarketIndex,
name,
{
confFilter: {
val: I80F48.fromNumber(oracleConfFilter).getData(),
},
} as any, // future: nested custom types dont typecheck, fix if possible?
oracleConfig,
baseDecimals,
new BN(quoteLotSize),
new BN(baseLotSize),
@ -1501,7 +1477,7 @@ export class MangoClient {
group: Group,
perpMarketIndex: PerpMarketIndex,
oracle: PublicKey,
oracleConfFilter: number,
oracleConfig: OracleConfigParams,
baseDecimals: number,
maintAssetWeight: number,
initAssetWeight: number,
@ -1525,11 +1501,7 @@ export class MangoClient {
return await this.program.methods
.perpEditMarket(
oracle,
{
confFilter: {
val: I80F48.fromNumber(oracleConfFilter).getData(),
},
} as any, // future: nested custom types dont typecheck, fix if possible?
oracleConfig,
baseDecimals,
maintAssetWeight,
initAssetWeight,

View File

@ -3,6 +3,7 @@ import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import fs from 'fs';
import { MangoClient } from '../client';
import { MANGO_V4_ID, MSRM_MINTS } from '../constants';
import { InterestRateParams } from '../types';
const GROUP_NUM = Number(process.env.GROUP_NUM || 0);
@ -92,6 +93,20 @@ async function registerTokens() {
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
// hoping that dynamic rate parameter adjustment would be enough to tune their rates to the markets needs
const defaultInterestRate = {
adjustmentFactor: 0.004, // rate parameters are chosen to be the same for all high asset weight tokens,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
};
console.log(`Creating USDC stub oracle...`);
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
await client.stubOracleCreate(group, usdcMainnetMint, 1.0);
@ -105,16 +120,10 @@ async function registerTokens() {
group,
usdcMainnetMint,
usdcMainnetOracle.publicKey,
0.1,
defaultOracleConfig,
0, // insurance vault token should be the first to be registered
'USDC',
0.004, // rate parameters are chosen to be the same for all high asset weight tokens,
// hoping that dynamic rate parameter adjustment would be enough to tune their rates to the markets needs
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005, // 50 bps
0.0005, // 5 bps
1,
@ -131,15 +140,10 @@ async function registerTokens() {
group,
usdtMainnetMint,
usdtMainnetOracle,
0.1,
defaultOracleConfig,
1,
'USDT',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.95,
@ -156,15 +160,10 @@ async function registerTokens() {
group,
btcMainnetMint,
btcMainnetOracle,
0.1,
defaultOracleConfig,
2,
'BTC',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -181,15 +180,10 @@ async function registerTokens() {
group,
ethMainnetMint,
ethMainnetOracle,
0.1,
defaultOracleConfig,
3,
'ETH',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -206,15 +200,10 @@ async function registerTokens() {
group,
soEthMainnetMint,
soEthMainnetOracle,
0.1,
defaultOracleConfig,
4,
'soETH',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -231,15 +220,10 @@ async function registerTokens() {
group,
solMainnetMint,
solMainnetOracle,
0.1,
defaultOracleConfig,
5,
'SOL',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -256,15 +240,10 @@ async function registerTokens() {
group,
msolMainnetMint,
msolMainnetOracle,
0.1,
defaultOracleConfig,
6,
'mSOL',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,

View File

@ -389,7 +389,7 @@ export type MangoV4 = {
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
},
{
@ -596,7 +596,7 @@ export type MangoV4 = {
"name": "oracleConfigOpt",
"type": {
"option": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
}
},
@ -2403,7 +2403,7 @@ export type MangoV4 = {
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
},
{
@ -2518,7 +2518,7 @@ export type MangoV4 = {
"name": "oracleConfigOpt",
"type": {
"option": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
}
},
@ -2761,6 +2761,10 @@ export type MangoV4 = {
"defined": "PlaceOrderType"
}
},
{
"name": "reduceOnly",
"type": "bool"
},
{
"name": "expiryTimestamp",
"type": "u64"
@ -3413,9 +3417,9 @@ export type MangoV4 = {
"type": "publicKey"
},
{
"name": "oracleConfig",
"name": "oracleConfFilter",
"type": {
"defined": "OracleConfig"
"defined": "I80F48"
}
},
{
@ -3602,12 +3606,18 @@ export type MangoV4 = {
"name": "bankNum",
"type": "u32"
},
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
}
},
{
"name": "reserved",
"type": {
"array": [
"u8",
2560
2464
]
}
}
@ -3962,25 +3972,33 @@ export type MangoV4 = {
"kind": "struct",
"fields": [
{
"name": "bidsFixed",
"name": "bids",
"type": {
"defined": "BookSide"
}
},
{
"name": "asks",
"type": {
"defined": "BookSide"
}
}
]
}
},
{
"name": "bookSide",
"type": {
"kind": "struct",
"fields": [
{
"name": "fixed",
"type": {
"defined": "OrderTree"
}
},
{
"name": "asksFixed",
"type": {
"defined": "OrderTree"
}
},
{
"name": "bidsOraclePegged",
"type": {
"defined": "OrderTree"
}
},
{
"name": "asksOraclePegged",
"name": "oraclePegged",
"type": {
"defined": "OrderTree"
}
@ -4147,15 +4165,6 @@ export type MangoV4 = {
"name": "orderbook",
"type": "publicKey"
},
{
"name": "padding3",
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "eventQueue",
"type": "publicKey"
@ -4341,7 +4350,7 @@ export type MangoV4 = {
"type": {
"array": [
"u8",
92
2244
]
}
}
@ -4968,15 +4977,6 @@ export type MangoV4 = {
"name": "takerQuoteLots",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
24
]
}
},
{
"name": "cumulativeLongFunding",
"type": "f64"
@ -4996,6 +4996,15 @@ export type MangoV4 = {
{
"name": "perpSpotTransfers",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
24
]
}
}
]
}
@ -5063,6 +5072,37 @@ export type MangoV4 = {
"type": {
"defined": "I80F48"
}
},
{
"name": "maxStalenessSlots",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
72
]
}
}
]
}
},
{
"name": "OracleConfigParams",
"type": {
"kind": "struct",
"fields": [
{
"name": "confFilter",
"type": "f32"
},
{
"name": "maxStalenessSlots",
"type": {
"option": "u32"
}
}
]
}
@ -7315,7 +7355,7 @@ export const IDL: MangoV4 = {
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
},
{
@ -7522,7 +7562,7 @@ export const IDL: MangoV4 = {
"name": "oracleConfigOpt",
"type": {
"option": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
}
},
@ -9329,7 +9369,7 @@ export const IDL: MangoV4 = {
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
},
{
@ -9444,7 +9484,7 @@ export const IDL: MangoV4 = {
"name": "oracleConfigOpt",
"type": {
"option": {
"defined": "OracleConfig"
"defined": "OracleConfigParams"
}
}
},
@ -9687,6 +9727,10 @@ export const IDL: MangoV4 = {
"defined": "PlaceOrderType"
}
},
{
"name": "reduceOnly",
"type": "bool"
},
{
"name": "expiryTimestamp",
"type": "u64"
@ -10339,9 +10383,9 @@ export const IDL: MangoV4 = {
"type": "publicKey"
},
{
"name": "oracleConfig",
"name": "oracleConfFilter",
"type": {
"defined": "OracleConfig"
"defined": "I80F48"
}
},
{
@ -10528,12 +10572,18 @@ export const IDL: MangoV4 = {
"name": "bankNum",
"type": "u32"
},
{
"name": "oracleConfig",
"type": {
"defined": "OracleConfig"
}
},
{
"name": "reserved",
"type": {
"array": [
"u8",
2560
2464
]
}
}
@ -10888,25 +10938,33 @@ export const IDL: MangoV4 = {
"kind": "struct",
"fields": [
{
"name": "bidsFixed",
"name": "bids",
"type": {
"defined": "BookSide"
}
},
{
"name": "asks",
"type": {
"defined": "BookSide"
}
}
]
}
},
{
"name": "bookSide",
"type": {
"kind": "struct",
"fields": [
{
"name": "fixed",
"type": {
"defined": "OrderTree"
}
},
{
"name": "asksFixed",
"type": {
"defined": "OrderTree"
}
},
{
"name": "bidsOraclePegged",
"type": {
"defined": "OrderTree"
}
},
{
"name": "asksOraclePegged",
"name": "oraclePegged",
"type": {
"defined": "OrderTree"
}
@ -11073,15 +11131,6 @@ export const IDL: MangoV4 = {
"name": "orderbook",
"type": "publicKey"
},
{
"name": "padding3",
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "eventQueue",
"type": "publicKey"
@ -11267,7 +11316,7 @@ export const IDL: MangoV4 = {
"type": {
"array": [
"u8",
92
2244
]
}
}
@ -11894,15 +11943,6 @@ export const IDL: MangoV4 = {
"name": "takerQuoteLots",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
24
]
}
},
{
"name": "cumulativeLongFunding",
"type": "f64"
@ -11922,6 +11962,15 @@ export const IDL: MangoV4 = {
{
"name": "perpSpotTransfers",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
24
]
}
}
]
}
@ -11989,6 +12038,37 @@ export const IDL: MangoV4 = {
"type": {
"defined": "I80F48"
}
},
{
"name": "maxStalenessSlots",
"type": "i64"
},
{
"name": "reserved",
"type": {
"array": [
"u8",
72
]
}
}
]
}
},
{
"name": "OracleConfigParams",
"type": {
"kind": "struct",
"fields": [
{
"name": "confFilter",
"type": "f32"
},
{
"name": "maxStalenessSlots",
"type": {
"option": "u32"
}
}
]
}

View File

@ -87,6 +87,19 @@ async function main() {
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
console.log(`...registered group ${group.publicKey}`);
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
const defaultInterestRate = {
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
};
// stub oracle + register token 0
console.log(`Registering USDC...`);
const usdcDevnetMint = new PublicKey(DEVNET_MINTS.get('USDC')!);
@ -104,15 +117,10 @@ async function main() {
group,
usdcDevnetMint,
usdcDevnetOracle.publicKey,
0.1,
defaultOracleConfig,
0, // tokenIndex
'USDC',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
1,
@ -133,15 +141,10 @@ async function main() {
group,
btcDevnetMint,
btcDevnetOracle,
0.1,
defaultOracleConfig,
1, // tokenIndex
'BTC',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -164,15 +167,10 @@ async function main() {
group,
solDevnetMint,
solDevnetOracle,
0.1,
defaultOracleConfig,
2, // tokenIndex
'SOL',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -195,15 +193,17 @@ async function main() {
group,
orcaDevnetMint,
orcaDevnetOracle,
0.1,
defaultOracleConfig,
3, // tokenIndex
'ORCA',
0.01,
0.4,
0.07,
0.8,
0.9,
0.63,
{
adjustmentFactor: 0.01,
util0: 0.4,
rate0: 0.07,
util1: 0.8,
rate1: 0.9,
maxRate: 0.63, // weird?
},
0.0005,
0.0005,
0.8,
@ -226,15 +226,10 @@ async function main() {
group,
ethDevnetMint,
ethDevnetOracle,
0.1,
defaultOracleConfig,
7, // tokenIndex
'ETH',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -257,15 +252,10 @@ async function main() {
group,
srmDevnetMint,
srmDevnetOracle,
0.1,
defaultOracleConfig,
5, // tokenIndex
'SRM',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -369,7 +359,7 @@ async function main() {
btcDevnetOracle,
0,
'BTC-PERP',
0.1,
defaultOracleConfig,
6,
10,
100,
@ -409,16 +399,9 @@ async function main() {
group,
usdcDevnetMint,
usdcDevnetOracle.publicKey,
0.1,
defaultOracleConfig,
null,
{
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
},
defaultInterestRate,
0.005,
0.0005,
1,
@ -440,16 +423,9 @@ async function main() {
group,
usdcDevnetMint,
usdcDevnetOracle.publicKey,
0.1,
defaultOracleConfig,
null,
{
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
},
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -471,16 +447,9 @@ async function main() {
group,
usdcDevnetMint,
usdcDevnetOracle.publicKey,
0.1,
defaultOracleConfig,
null,
{
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
},
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -502,7 +471,7 @@ async function main() {
group,
group.getPerpMarketByName('BTC-PERP').perpMarketIndex,
btcDevnetOracle,
0.1,
defaultOracleConfig,
6,
0.975,
0.95,

View File

@ -128,6 +128,20 @@ async function registerTokens() {
const group = await client.getGroupForCreator(admin.publicKey, 2);
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
// hoping that dynamic rate parameter adjustment would be enough to tune their rates to the markets needs
const defaultInterestRate = {
adjustmentFactor: 0.004, // rate parameters are chosen to be the same for all high asset weight tokens,
util0: 0.7,
rate0: 0.1,
util1: 0.85,
rate1: 0.2,
maxRate: 2.0,
};
console.log(`Creating USDC stub oracle...`);
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
await client.stubOracleCreate(group, usdcMainnetMint, 1.0);
@ -141,15 +155,10 @@ async function registerTokens() {
group,
usdcMainnetMint,
usdcMainnetOracle.publicKey,
0.1,
defaultOracleConfig,
0,
'USDC',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
1,
@ -166,15 +175,10 @@ async function registerTokens() {
group,
usdtMainnetMint,
usdtMainnetOracle,
0.1,
defaultOracleConfig,
1,
'USDT',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.95,
@ -191,15 +195,10 @@ async function registerTokens() {
group,
btcMainnetMint,
btcMainnetOracle,
0.1,
defaultOracleConfig,
2,
'BTC',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -216,15 +215,10 @@ async function registerTokens() {
group,
ethMainnetMint,
ethMainnetOracle,
0.1,
defaultOracleConfig,
3,
'ETH',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -241,15 +235,10 @@ async function registerTokens() {
group,
soEthMainnetMint,
soEthMainnetOracle,
0.1,
defaultOracleConfig,
4,
'soETH',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -266,15 +255,10 @@ async function registerTokens() {
group,
solMainnetMint,
solMainnetOracle,
0.1,
defaultOracleConfig,
5,
'SOL',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -291,15 +275,10 @@ async function registerTokens() {
group,
msolMainnetMint,
msolMainnetOracle,
0.1,
defaultOracleConfig,
6,
'MSOL',
0.004,
0.7,
0.1,
0.85,
0.2,
2.0,
defaultInterestRate,
0.005,
0.0005,
0.9,
@ -315,15 +294,17 @@ async function registerTokens() {
group,
rayMainnetMint,
rayMainnetOracle,
0.1,
defaultOracleConfig,
7,
'RAY',
0.004,
0.7,
0.2,
0.85,
0.4,
4.0,
{
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.2,
util1: 0.85,
rate1: 0.4,
maxRate: 4.0,
},
0.005,
0.0005,
7 / 8,
@ -340,15 +321,17 @@ async function registerTokens() {
group,
dustMainnetMint,
dustMainnetOracle,
0.1,
defaultOracleConfig,
8,
'DUST',
0.004,
0.7,
0.3,
0.85,
0.6,
6.0,
{
adjustmentFactor: 0.004,
util0: 0.7,
rate0: 0.3,
util1: 0.85,
rate1: 0.6,
maxRate: 6.0,
},
0.005,
0.0005,
0, // no asset weight for isolation

View File

@ -89,6 +89,19 @@ async function main() {
oracles.set(name, oracle.publicKey);
}
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
const defaultInterestRate = {
adjustmentFactor: 0.01,
util0: 0.4,
rate0: 0.07,
util1: 0.8,
rate1: 0.9,
maxRate: 1.5,
};
// register token 0
console.log(`Registering USDC...`);
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
@ -98,15 +111,10 @@ async function main() {
group,
usdcMainnetMint,
usdcMainnetOracle,
0.1,
defaultOracleConfig,
0,
'USDC',
0.01,
0.4,
0.07,
0.8,
0.9,
1.5,
defaultInterestRate,
0.0,
0.0001,
1,
@ -129,15 +137,10 @@ async function main() {
group,
btcMainnetMint,
btcMainnetOracle,
0.1,
defaultOracleConfig,
1,
'BTC',
0.01,
0.4,
0.07,
0.7,
0.88,
1.5,
defaultInterestRate,
0.0,
0.0001,
0.9,
@ -160,15 +163,10 @@ async function main() {
group,
solMainnetMint,
solMainnetOracle,
0.1,
defaultOracleConfig,
2, // tokenIndex
'SOL',
0.01,
0.4,
0.07,
0.8,
0.9,
1.5,
defaultInterestRate,
0.0,
0.0001,
0.9,
@ -209,7 +207,7 @@ async function main() {
mngoMainnetOracle,
0,
'MNGO-PERP',
0.1,
defaultOracleConfig,
9,
10,
100000, // base lots

View File

@ -18,3 +18,8 @@ export class InterestRateParams {
maxRate: number;
adjustmentFactor: number;
}
export class OracleConfigParams {
confFilter: number;
maxStalenessSlots: number | null;
}