Merge branch 'dev'
This commit is contained in:
commit
30714fb0dc
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"programs/*",
|
"programs/*",
|
||||||
|
"keeper",
|
||||||
"lib/*"
|
"lib/*"
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
[package]
|
||||||
|
name = "keeper"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anchor-client = "0.22.0"
|
||||||
|
anchor-lang = "0.22.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
mango-v4 = { path = "../programs/mango-v4" }
|
||||||
|
solana-account-decoder = "1.9.5"
|
||||||
|
solana-client = "1.9.5"
|
||||||
|
solana-program = "1.9.5"
|
||||||
|
solana-rpc = "1.9.5"
|
||||||
|
solana-sdk = "1.9.5"
|
||||||
|
solana-transaction-status = "1.9.5"
|
||||||
|
tokio = { version = "1.17", features = ["rt-multi-thread", "time", "macros", "sync"] }
|
||||||
|
shellexpand = "2.1"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
|
@ -0,0 +1,66 @@
|
||||||
|
use std::{rc::Rc, str::FromStr, time::Duration};
|
||||||
|
|
||||||
|
use solana_sdk::{instruction::Instruction, signature::Keypair};
|
||||||
|
use tokio::time;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// cmd line args with defaults
|
||||||
|
// make keypair, rpc server, net, etc. configurable
|
||||||
|
// expand to various tasks e.g. crank event queue, crank banks, run liquidators
|
||||||
|
// support multiple workers
|
||||||
|
// logging facility
|
||||||
|
// robust error handling
|
||||||
|
fn main() {
|
||||||
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
rt.block_on(update_index_runner())
|
||||||
|
.expect("Something went wrong here...");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_index_runner() -> anyhow::Result<()> {
|
||||||
|
let mut interval = time::interval(Duration::from_millis(10));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
update_index().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_index() -> anyhow::Result<()> {
|
||||||
|
let keypair = load_default_keypair()?;
|
||||||
|
let rpc = "https://mango.devnet.rpcpool.com".to_owned();
|
||||||
|
let wss = rpc.replace("https", "wss");
|
||||||
|
let connection =
|
||||||
|
anchor_client::Client::new(anchor_client::Cluster::Custom(rpc, wss), Rc::new(keypair));
|
||||||
|
let client = connection.program(mango_v4::ID);
|
||||||
|
|
||||||
|
let update_index_ix = Instruction {
|
||||||
|
program_id: mango_v4::id(),
|
||||||
|
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
||||||
|
&mango_v4::accounts::UpdateIndex {
|
||||||
|
bank: anchor_lang::prelude::Pubkey::from_str(
|
||||||
|
"9xmZdkWbYNYsBshr7PwjhU8c7mmrvzmocu8dSQeNCKTG",
|
||||||
|
)?,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
data: anchor_lang::InstructionData::data(&mango_v4::instruction::UpdateIndex {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig = client.request().instruction(update_index_ix).send()?;
|
||||||
|
println!("update_index: {:?}", sig);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_default_keypair() -> anyhow::Result<Keypair> {
|
||||||
|
let keypair_path = shellexpand::tilde("~/.config/solana/mango-devnet.json");
|
||||||
|
let keypair_data = std::fs::read_to_string(keypair_path.to_string())?;
|
||||||
|
let keypair_bytes: Vec<u8> = serde_json::from_str(&keypair_data)?;
|
||||||
|
let keypair = Keypair::from_bytes(&keypair_bytes)?;
|
||||||
|
|
||||||
|
Ok(keypair)
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ use anchor_lang::prelude::*;
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::state::*;
|
use crate::state::*;
|
||||||
|
use crate::util::fill32_from_str;
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(account_num: u8)]
|
#[instruction(account_num: u8)]
|
||||||
|
@ -25,10 +26,11 @@ pub struct CreateAccount<'info> {
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_account(ctx: Context<CreateAccount>, account_num: u8) -> Result<()> {
|
pub fn create_account(ctx: Context<CreateAccount>, account_num: u8, name: String) -> Result<()> {
|
||||||
let mut account = ctx.accounts.account.load_init()?;
|
let mut account = ctx.accounts.account.load_init()?;
|
||||||
// TODO: dont init on stack
|
// TODO: dont init on stack
|
||||||
*account = MangoAccount {
|
*account = MangoAccount {
|
||||||
|
name: fill32_from_str(name)?,
|
||||||
group: ctx.accounts.group.key(),
|
group: ctx.accounts.group.key(),
|
||||||
owner: ctx.accounts.owner.key(),
|
owner: ctx.accounts.owner.key(),
|
||||||
delegate: Pubkey::default(),
|
delegate: Pubkey::default(),
|
||||||
|
|
|
@ -8,6 +8,7 @@ use fixed_macro::types::I80F48;
|
||||||
// TODO: ALTs are unavailable
|
// TODO: ALTs are unavailable
|
||||||
//use crate::address_lookup_table;
|
//use crate::address_lookup_table;
|
||||||
use crate::state::*;
|
use crate::state::*;
|
||||||
|
use crate::util::fill16_from_str;
|
||||||
|
|
||||||
const INDEX_START: I80F48 = I80F48!(1_000_000);
|
const INDEX_START: I80F48 = I80F48!(1_000_000);
|
||||||
|
|
||||||
|
@ -74,17 +75,23 @@ pub struct RegisterToken<'info> {
|
||||||
pub rent: Sysvar<'info, Rent>,
|
pub rent: Sysvar<'info, Rent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(AnchorSerialize, AnchorDeserialize, Default)]
|
||||||
|
pub struct InterestRateParams {
|
||||||
|
pub util0: f32,
|
||||||
|
pub rate0: f32,
|
||||||
|
pub util1: f32,
|
||||||
|
pub rate1: f32,
|
||||||
|
pub max_rate: f32,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should this be "configure_mint", we pass an explicit index, and allow
|
// TODO: should this be "configure_mint", we pass an explicit index, and allow
|
||||||
// overwriting config as long as the mint account stays the same?
|
// overwriting config as long as the mint account stays the same?
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn register_token(
|
pub fn register_token(
|
||||||
ctx: Context<RegisterToken>,
|
ctx: Context<RegisterToken>,
|
||||||
token_index: TokenIndex,
|
token_index: TokenIndex,
|
||||||
util0: f32,
|
name: String,
|
||||||
rate0: f32,
|
interest_rate_params: InterestRateParams,
|
||||||
util1: f32,
|
|
||||||
rate1: f32,
|
|
||||||
max_rate: f32,
|
|
||||||
maint_asset_weight: f32,
|
maint_asset_weight: f32,
|
||||||
init_asset_weight: f32,
|
init_asset_weight: f32,
|
||||||
maint_liab_weight: f32,
|
maint_liab_weight: f32,
|
||||||
|
@ -95,6 +102,7 @@ pub fn register_token(
|
||||||
|
|
||||||
let mut bank = ctx.accounts.bank.load_init()?;
|
let mut bank = ctx.accounts.bank.load_init()?;
|
||||||
*bank = Bank {
|
*bank = Bank {
|
||||||
|
name: fill16_from_str(name)?,
|
||||||
group: ctx.accounts.group.key(),
|
group: ctx.accounts.group.key(),
|
||||||
mint: ctx.accounts.mint.key(),
|
mint: ctx.accounts.mint.key(),
|
||||||
vault: ctx.accounts.vault.key(),
|
vault: ctx.accounts.vault.key(),
|
||||||
|
@ -104,11 +112,12 @@ pub fn register_token(
|
||||||
indexed_total_deposits: I80F48::ZERO,
|
indexed_total_deposits: I80F48::ZERO,
|
||||||
indexed_total_borrows: I80F48::ZERO,
|
indexed_total_borrows: I80F48::ZERO,
|
||||||
last_updated: Clock::get()?.unix_timestamp,
|
last_updated: Clock::get()?.unix_timestamp,
|
||||||
util0: I80F48::from_num(util0),
|
// TODO: add a require! verifying relation between the parameters
|
||||||
rate0: I80F48::from_num(rate0),
|
util0: I80F48::from_num(interest_rate_params.util0),
|
||||||
util1: I80F48::from_num(util1),
|
rate0: I80F48::from_num(interest_rate_params.rate0),
|
||||||
rate1: I80F48::from_num(rate1),
|
util1: I80F48::from_num(interest_rate_params.util1),
|
||||||
max_rate: I80F48::from_num(max_rate),
|
rate1: I80F48::from_num(interest_rate_params.rate1),
|
||||||
|
max_rate: I80F48::from_num(interest_rate_params.max_rate),
|
||||||
maint_asset_weight: I80F48::from_num(maint_asset_weight),
|
maint_asset_weight: I80F48::from_num(maint_asset_weight),
|
||||||
init_asset_weight: I80F48::from_num(init_asset_weight),
|
init_asset_weight: I80F48::from_num(init_asset_weight),
|
||||||
maint_liab_weight: I80F48::from_num(maint_liab_weight),
|
maint_liab_weight: I80F48::from_num(maint_liab_weight),
|
||||||
|
|
|
@ -3,6 +3,7 @@ use anchor_lang::prelude::*;
|
||||||
use crate::error::MangoError;
|
use crate::error::MangoError;
|
||||||
use crate::serum3_cpi::{load_market_state, pubkey_from_u64_array};
|
use crate::serum3_cpi::{load_market_state, pubkey_from_u64_array};
|
||||||
use crate::state::*;
|
use crate::state::*;
|
||||||
|
use crate::util::fill16_from_str;
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct Serum3RegisterMarket<'info> {
|
pub struct Serum3RegisterMarket<'info> {
|
||||||
|
@ -42,6 +43,7 @@ pub struct Serum3RegisterMarket<'info> {
|
||||||
pub fn serum3_register_market(
|
pub fn serum3_register_market(
|
||||||
ctx: Context<Serum3RegisterMarket>,
|
ctx: Context<Serum3RegisterMarket>,
|
||||||
market_index: Serum3MarketIndex,
|
market_index: Serum3MarketIndex,
|
||||||
|
name: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO: must guard against accidentally using the same market_index twice!
|
// TODO: must guard against accidentally using the same market_index twice!
|
||||||
|
|
||||||
|
@ -62,6 +64,7 @@ pub fn serum3_register_market(
|
||||||
|
|
||||||
let mut serum_market = ctx.accounts.serum_market.load_init()?;
|
let mut serum_market = ctx.accounts.serum_market.load_init()?;
|
||||||
*serum_market = Serum3Market {
|
*serum_market = Serum3Market {
|
||||||
|
name: fill16_from_str(name)?,
|
||||||
group: ctx.accounts.group.key(),
|
group: ctx.accounts.group.key(),
|
||||||
serum_program: ctx.accounts.serum_program.key(),
|
serum_program: ctx.accounts.serum_program.key(),
|
||||||
serum_market_external: ctx.accounts.serum_market_external.key(),
|
serum_market_external: ctx.accounts.serum_market_external.key(),
|
||||||
|
|
|
@ -4,10 +4,13 @@ use crate::state::Bank;
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct UpdateIndex<'info> {
|
pub struct UpdateIndex<'info> {
|
||||||
|
// TODO: should we support arbitrary number of banks with remaining accounts?
|
||||||
|
// ix - consumed 17641 of 101000 compute units, so we have a lot of compute
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
pub bank: AccountLoader<'info, Bank>,
|
pub bank: AccountLoader<'info, Bank>,
|
||||||
}
|
}
|
||||||
pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
pub fn update_index(ctx: Context<UpdateIndex>) -> Result<()> {
|
||||||
|
// TODO: should we enforce a minimum window between 2 update_index ix calls?
|
||||||
let now_ts = Clock::get()?.unix_timestamp;
|
let now_ts = Clock::get()?.unix_timestamp;
|
||||||
|
|
||||||
let mut bank = ctx.accounts.bank.load_mut()?;
|
let mut bank = ctx.accounts.bank.load_mut()?;
|
||||||
|
|
|
@ -37,11 +37,8 @@ pub mod mango_v4 {
|
||||||
pub fn register_token(
|
pub fn register_token(
|
||||||
ctx: Context<RegisterToken>,
|
ctx: Context<RegisterToken>,
|
||||||
token_index: TokenIndex,
|
token_index: TokenIndex,
|
||||||
util0: f32,
|
name: String,
|
||||||
rate0: f32,
|
interest_rate_params: InterestRateParams,
|
||||||
util1: f32,
|
|
||||||
rate1: f32,
|
|
||||||
max_rate: f32,
|
|
||||||
maint_asset_weight: f32,
|
maint_asset_weight: f32,
|
||||||
init_asset_weight: f32,
|
init_asset_weight: f32,
|
||||||
maint_liab_weight: f32,
|
maint_liab_weight: f32,
|
||||||
|
@ -51,11 +48,8 @@ pub mod mango_v4 {
|
||||||
instructions::register_token(
|
instructions::register_token(
|
||||||
ctx,
|
ctx,
|
||||||
token_index,
|
token_index,
|
||||||
util0,
|
name,
|
||||||
rate0,
|
interest_rate_params,
|
||||||
util1,
|
|
||||||
rate1,
|
|
||||||
max_rate,
|
|
||||||
maint_asset_weight,
|
maint_asset_weight,
|
||||||
init_asset_weight,
|
init_asset_weight,
|
||||||
maint_liab_weight,
|
maint_liab_weight,
|
||||||
|
@ -68,8 +62,12 @@ pub mod mango_v4 {
|
||||||
instructions::update_index(ctx)
|
instructions::update_index(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_account(ctx: Context<CreateAccount>, account_num: u8) -> Result<()> {
|
pub fn create_account(
|
||||||
instructions::create_account(ctx, account_num)
|
ctx: Context<CreateAccount>,
|
||||||
|
account_num: u8,
|
||||||
|
name: String,
|
||||||
|
) -> Result<()> {
|
||||||
|
instructions::create_account(ctx, account_num, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_account(ctx: Context<CloseAccount>) -> Result<()> {
|
pub fn close_account(ctx: Context<CloseAccount>) -> Result<()> {
|
||||||
|
@ -112,8 +110,9 @@ pub mod mango_v4 {
|
||||||
pub fn serum3_register_market(
|
pub fn serum3_register_market(
|
||||||
ctx: Context<Serum3RegisterMarket>,
|
ctx: Context<Serum3RegisterMarket>,
|
||||||
market_index: Serum3MarketIndex,
|
market_index: Serum3MarketIndex,
|
||||||
|
name: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
instructions::serum3_register_market(ctx, market_index)
|
instructions::serum3_register_market(ctx, market_index, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result<()> {
|
pub fn serum3_create_open_orders(ctx: Context<Serum3CreateOpenOrders>) -> Result<()> {
|
||||||
|
|
|
@ -10,6 +10,8 @@ pub const YEAR: I80F48 = I80F48!(31536000);
|
||||||
|
|
||||||
#[account(zero_copy)]
|
#[account(zero_copy)]
|
||||||
pub struct Bank {
|
pub struct Bank {
|
||||||
|
pub name: [u8; 16],
|
||||||
|
|
||||||
pub group: Pubkey,
|
pub group: Pubkey,
|
||||||
pub mint: Pubkey,
|
pub mint: Pubkey,
|
||||||
pub vault: Pubkey,
|
pub vault: Pubkey,
|
||||||
|
@ -52,7 +54,7 @@ pub struct Bank {
|
||||||
|
|
||||||
pub reserved: [u8; 6],
|
pub reserved: [u8; 6],
|
||||||
}
|
}
|
||||||
const_assert_eq!(size_of::<Bank>(), 32 * 4 + 8 + 16 * 15 + 2 + 6);
|
const_assert_eq!(size_of::<Bank>(), 16 + 32 * 4 + 8 + 16 * 15 + 2 + 6);
|
||||||
const_assert_eq!(size_of::<Bank>() % 8, 0);
|
const_assert_eq!(size_of::<Bank>() % 8, 0);
|
||||||
|
|
||||||
impl Bank {
|
impl Bank {
|
||||||
|
@ -165,17 +167,20 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_index(&mut self, now_ts: i64) -> Result<()> {
|
pub fn update_index(&mut self, now_ts: i64) -> Result<()> {
|
||||||
let utilization = cm!(self.native_total_borrows() / self.native_total_deposits());
|
let utilization = if self.native_total_deposits() == I80F48::ZERO {
|
||||||
|
I80F48::ZERO
|
||||||
|
} else {
|
||||||
|
cm!(self.native_total_borrows() / self.native_total_deposits())
|
||||||
|
};
|
||||||
|
|
||||||
let interest_rate = self.compute_interest_rate(utilization);
|
let interest_rate = self.compute_interest_rate(utilization);
|
||||||
|
|
||||||
let diff_ts = I80F48::from_num(now_ts - self.last_updated);
|
let diff_ts = I80F48::from_num(now_ts - self.last_updated);
|
||||||
|
self.last_updated = now_ts;
|
||||||
|
|
||||||
let borrow_interest: I80F48 = cm!(interest_rate * diff_ts);
|
let borrow_interest: I80F48 = cm!(interest_rate * diff_ts);
|
||||||
let deposit_interest = cm!(borrow_interest * utilization);
|
let deposit_interest = cm!(borrow_interest * utilization);
|
||||||
|
|
||||||
self.last_updated = Clock::get()?.unix_timestamp;
|
|
||||||
|
|
||||||
if borrow_interest <= I80F48::ZERO || deposit_interest <= I80F48::ZERO {
|
if borrow_interest <= I80F48::ZERO || deposit_interest <= I80F48::ZERO {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -219,9 +224,9 @@ impl Bank {
|
||||||
let slope = cm!((rate1 - rate0) / (util1 - util0));
|
let slope = cm!((rate1 - rate0) / (util1 - util0));
|
||||||
cm!(rate0 + slope * extra_util)
|
cm!(rate0 + slope * extra_util)
|
||||||
} else {
|
} else {
|
||||||
let extra_util = utilization - util1;
|
let extra_util = cm!(utilization - util1);
|
||||||
let slope = (max_rate - rate1) / (I80F48::ONE - util1);
|
let slope = cm!((max_rate - rate1) / (I80F48::ONE - util1));
|
||||||
rate1 + slope * extra_util
|
cm!(rate1 + slope * extra_util)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,6 +512,8 @@ impl Default for MangoAccountPerps {
|
||||||
|
|
||||||
#[account(zero_copy)]
|
#[account(zero_copy)]
|
||||||
pub struct MangoAccount {
|
pub struct MangoAccount {
|
||||||
|
pub name: [u8; 32],
|
||||||
|
|
||||||
pub group: Pubkey,
|
pub group: Pubkey,
|
||||||
pub owner: Pubkey,
|
pub owner: Pubkey,
|
||||||
|
|
||||||
|
@ -542,7 +544,7 @@ pub struct MangoAccount {
|
||||||
}
|
}
|
||||||
const_assert_eq!(
|
const_assert_eq!(
|
||||||
size_of::<MangoAccount>(),
|
size_of::<MangoAccount>(),
|
||||||
3 * 32
|
32 + 3 * 32
|
||||||
+ size_of::<MangoAccountTokens>()
|
+ size_of::<MangoAccountTokens>()
|
||||||
+ size_of::<MangoAccountSerum3>()
|
+ size_of::<MangoAccountSerum3>()
|
||||||
+ size_of::<MangoAccountPerps>()
|
+ size_of::<MangoAccountPerps>()
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub type Serum3MarketIndex = u16;
|
||||||
|
|
||||||
#[account(zero_copy)]
|
#[account(zero_copy)]
|
||||||
pub struct Serum3Market {
|
pub struct Serum3Market {
|
||||||
|
pub name: [u8; 16],
|
||||||
pub group: Pubkey,
|
pub group: Pubkey,
|
||||||
pub serum_program: Pubkey,
|
pub serum_program: Pubkey,
|
||||||
pub serum_market_external: Pubkey,
|
pub serum_market_external: Pubkey,
|
||||||
|
@ -19,7 +20,7 @@ pub struct Serum3Market {
|
||||||
pub bump: u8,
|
pub bump: u8,
|
||||||
pub reserved: [u8; 1],
|
pub reserved: [u8; 1],
|
||||||
}
|
}
|
||||||
const_assert_eq!(size_of::<Serum3Market>(), 32 * 3 + 3 * 2 + 1 + 1);
|
const_assert_eq!(size_of::<Serum3Market>(), 16 + 32 * 3 + 3 * 2 + 1 + 1);
|
||||||
const_assert_eq!(size_of::<Serum3Market>() % 8, 0);
|
const_assert_eq!(size_of::<Serum3Market>() % 8, 0);
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::error::MangoError;
|
||||||
use anchor_lang::prelude::*;
|
use anchor_lang::prelude::*;
|
||||||
use anchor_lang::ZeroCopy;
|
use anchor_lang::ZeroCopy;
|
||||||
use arrayref::array_ref;
|
use arrayref::array_ref;
|
||||||
use fixed::types::I80F48;
|
|
||||||
use std::cell::RefMut;
|
use std::cell::RefMut;
|
||||||
use std::{cell::Ref, mem};
|
use std::{cell::Ref, mem};
|
||||||
|
|
||||||
|
@ -90,10 +90,20 @@ impl<'info> LoadZeroCopy for AccountInfo<'info> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns asset_weight and liab_weight
|
pub fn fill16_from_str(name: String) -> Result<[u8; 16]> {
|
||||||
pub fn get_leverage_weights(leverage: I80F48) -> (I80F48, I80F48) {
|
let name_bytes = name.as_bytes();
|
||||||
(
|
msg!("{}", name);
|
||||||
(leverage - I80F48::ONE).checked_div(leverage).unwrap(),
|
require!(name_bytes.len() < 16, MangoError::SomeError);
|
||||||
(leverage + I80F48::ONE).checked_div(leverage).unwrap(),
|
let mut name_ = [0u8; 16];
|
||||||
)
|
name_[..name_bytes.len()].copy_from_slice(name_bytes);
|
||||||
|
Ok(name_)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill32_from_str(name: String) -> Result<[u8; 32]> {
|
||||||
|
let name_bytes = name.as_bytes();
|
||||||
|
msg!("{}", name);
|
||||||
|
require!(name_bytes.len() < 32, MangoError::SomeError);
|
||||||
|
let mut name_ = [0u8; 32];
|
||||||
|
name_[..name_bytes.len()].copy_from_slice(name_bytes);
|
||||||
|
Ok(name_)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,14 @@ use anchor_lang::solana_program::sysvar::{self, SysvarId};
|
||||||
use anchor_spl::token::{Token, TokenAccount};
|
use anchor_spl::token::{Token, TokenAccount};
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use mango_v4::instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side};
|
use mango_v4::instructions::{
|
||||||
|
InterestRateParams, Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side,
|
||||||
|
};
|
||||||
use solana_program::instruction::Instruction;
|
use solana_program::instruction::Instruction;
|
||||||
|
use solana_program_test::BanksClientError;
|
||||||
use solana_sdk::instruction;
|
use solana_sdk::instruction;
|
||||||
use solana_sdk::signature::{Keypair, Signer};
|
use solana_sdk::signature::{Keypair, Signer};
|
||||||
use solana_sdk::transport::TransportError;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::solana::SolanaCookie;
|
use super::solana::SolanaCookie;
|
||||||
|
@ -35,7 +38,7 @@ impl ClientAccountLoader for &SolanaCookie {
|
||||||
pub async fn send_tx<CI: ClientInstruction>(
|
pub async fn send_tx<CI: ClientInstruction>(
|
||||||
solana: &SolanaCookie,
|
solana: &SolanaCookie,
|
||||||
ix: CI,
|
ix: CI,
|
||||||
) -> std::result::Result<CI::Accounts, TransportError> {
|
) -> std::result::Result<CI::Accounts, BanksClientError> {
|
||||||
let (accounts, instruction) = ix.to_instruction(solana).await;
|
let (accounts, instruction) = ix.to_instruction(solana).await;
|
||||||
let signers = ix.signers();
|
let signers = ix.signers();
|
||||||
let instructions = vec![instruction];
|
let instructions = vec![instruction];
|
||||||
|
@ -471,12 +474,15 @@ impl<'keypair> ClientInstruction for RegisterTokenInstruction<'keypair> {
|
||||||
) -> (Self::Accounts, instruction::Instruction) {
|
) -> (Self::Accounts, instruction::Instruction) {
|
||||||
let program_id = mango_v4::id();
|
let program_id = mango_v4::id();
|
||||||
let instruction = Self::Instruction {
|
let instruction = Self::Instruction {
|
||||||
|
name: "some_ticker".to_string(),
|
||||||
token_index: self.token_index,
|
token_index: self.token_index,
|
||||||
util0: self.util0,
|
interest_rate_params: InterestRateParams {
|
||||||
rate0: self.rate0,
|
util0: self.util0,
|
||||||
util1: self.util1,
|
rate0: self.rate0,
|
||||||
rate1: self.rate1,
|
util1: self.util1,
|
||||||
max_rate: self.max_rate,
|
rate1: self.rate1,
|
||||||
|
max_rate: self.max_rate,
|
||||||
|
},
|
||||||
maint_asset_weight: self.maint_asset_weight,
|
maint_asset_weight: self.maint_asset_weight,
|
||||||
init_asset_weight: self.init_asset_weight,
|
init_asset_weight: self.init_asset_weight,
|
||||||
maint_liab_weight: self.maint_liab_weight,
|
maint_liab_weight: self.maint_liab_weight,
|
||||||
|
@ -699,6 +705,7 @@ impl<'keypair> ClientInstruction for CreateAccountInstruction<'keypair> {
|
||||||
let program_id = mango_v4::id();
|
let program_id = mango_v4::id();
|
||||||
let instruction = mango_v4::instruction::CreateAccount {
|
let instruction = mango_v4::instruction::CreateAccount {
|
||||||
account_num: self.account_num,
|
account_num: self.account_num,
|
||||||
|
name: "my_mango_account".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let account = Pubkey::find_program_address(
|
let account = Pubkey::find_program_address(
|
||||||
|
@ -785,6 +792,7 @@ impl<'keypair> ClientInstruction for Serum3RegisterMarketInstruction<'keypair> {
|
||||||
let program_id = mango_v4::id();
|
let program_id = mango_v4::id();
|
||||||
let instruction = Self::Instruction {
|
let instruction = Self::Instruction {
|
||||||
market_index: self.market_index,
|
market_index: self.market_index,
|
||||||
|
name: "UUU/usdc".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let serum_market = Pubkey::find_program_address(
|
let serum_market = Pubkey::find_program_address(
|
||||||
|
|
|
@ -72,10 +72,10 @@ impl<'a> GroupWithTokensConfig<'a> {
|
||||||
RegisterTokenInstruction {
|
RegisterTokenInstruction {
|
||||||
token_index,
|
token_index,
|
||||||
decimals: mint.decimals,
|
decimals: mint.decimals,
|
||||||
util0: 0.50,
|
util0: 0.40,
|
||||||
rate0: 0.06,
|
rate0: 0.07,
|
||||||
util1: 0.70,
|
util1: 0.80,
|
||||||
rate1: 1.3,
|
rate1: 0.9,
|
||||||
max_rate: 1.50,
|
max_rate: 1.50,
|
||||||
maint_asset_weight: 0.8,
|
maint_asset_weight: 0.8,
|
||||||
init_asset_weight: 0.6,
|
init_asset_weight: 0.6,
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use anchor_lang::AccountDeserialize;
|
use anchor_lang::AccountDeserialize;
|
||||||
use anchor_spl::token::TokenAccount;
|
use anchor_spl::token::TokenAccount;
|
||||||
use solana_program::clock::UnixTimestamp;
|
|
||||||
use solana_program::{program_pack::Pack, rent::*, system_instruction};
|
use solana_program::{program_pack::Pack, rent::*, system_instruction};
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
@ -12,12 +11,9 @@ use solana_sdk::{
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
transport::TransportError,
|
|
||||||
};
|
};
|
||||||
use spl_token::*;
|
use spl_token::*;
|
||||||
|
|
||||||
use super::mango_client::ClientAccountLoader;
|
|
||||||
|
|
||||||
pub struct SolanaCookie {
|
pub struct SolanaCookie {
|
||||||
pub context: RefCell<ProgramTestContext>,
|
pub context: RefCell<ProgramTestContext>,
|
||||||
pub rent: Rent,
|
pub rent: Rent,
|
||||||
|
@ -30,7 +26,7 @@ impl SolanaCookie {
|
||||||
&self,
|
&self,
|
||||||
instructions: &[Instruction],
|
instructions: &[Instruction],
|
||||||
signers: Option<&[&Keypair]>,
|
signers: Option<&[&Keypair]>,
|
||||||
) -> Result<(), TransportError> {
|
) -> Result<(), BanksClientError> {
|
||||||
self.program_log.write().unwrap().clear();
|
self.program_log.write().unwrap().clear();
|
||||||
|
|
||||||
let mut context = self.context.borrow_mut();
|
let mut context = self.context.borrow_mut();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, signature::Signer, transport::TransportError};
|
use solana_sdk::{signature::Keypair, signature::Signer};
|
||||||
|
|
||||||
use mango_v4::state::*;
|
use mango_v4::state::*;
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
|
@ -12,7 +12,7 @@ mod program_test;
|
||||||
// This is an unspecific happy-case test that just runs a few instructions to check
|
// This is an unspecific happy-case test that just runs a few instructions to check
|
||||||
// that they work in principle. It should be split up / renamed.
|
// that they work in principle. It should be split up / renamed.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_basic() -> Result<(), TransportError> {
|
async fn test_basic() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::transport::TransportError;
|
|
||||||
mod program_test;
|
mod program_test;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_benchmark() -> Result<(), TransportError> {
|
async fn test_benchmark() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![cfg(feature = "test-bpf")]
|
#![cfg(feature = "test-bpf")]
|
||||||
|
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
use solana_sdk::signature::Keypair;
|
||||||
|
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ mod program_test;
|
||||||
|
|
||||||
// Try to reach compute limits in health checks by having many different tokens in an account
|
// Try to reach compute limits in health checks by having many different tokens in an account
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_health_compute_tokens() -> Result<(), TransportError> {
|
async fn test_health_compute_tokens() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> {
|
||||||
|
|
||||||
// Try to reach compute limits in health checks by having many serum markets in an account
|
// Try to reach compute limits in health checks by having many serum markets in an account
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_health_compute_serum() -> Result<(), TransportError> {
|
async fn test_health_compute_serum() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
use solana_sdk::signature::Keypair;
|
||||||
|
|
||||||
use mango_v4::{
|
use mango_v4::{
|
||||||
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
|
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
|
||||||
|
@ -13,7 +13,7 @@ use program_test::*;
|
||||||
mod program_test;
|
mod program_test;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
async fn test_liq_tokens_force_cancel() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ async fn test_liq_tokens_force_cancel() -> Result<(), TransportError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
async fn test_liq_tokens_with_token() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
use anchor_lang::InstructionData;
|
use anchor_lang::InstructionData;
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
|
use solana_sdk::signature::Keypair;
|
||||||
use solana_sdk::signature::Signer;
|
use solana_sdk::signature::Signer;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
|
||||||
|
|
||||||
use mango_v4::state::*;
|
use mango_v4::state::*;
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
|
@ -14,7 +14,7 @@ mod program_test;
|
||||||
// This is an unspecific happy-case test that just runs a few instructions to check
|
// This is an unspecific happy-case test that just runs a few instructions to check
|
||||||
// that they work in principle. It should be split up / renamed.
|
// that they work in principle. It should be split up / renamed.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_margin_trade() -> Result<(), TransportError> {
|
async fn test_margin_trade() -> Result<(), BanksClientError> {
|
||||||
let mut builder = TestContextBuilder::new();
|
let mut builder = TestContextBuilder::new();
|
||||||
let margin_trade = builder.add_margin_trade_program();
|
let margin_trade = builder.add_margin_trade_program();
|
||||||
let context = builder.start_default().await;
|
let context = builder.start_default().await;
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
use mango_v4::state::*;
|
use mango_v4::state::*;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
use solana_sdk::signature::Keypair;
|
||||||
|
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
|
|
||||||
mod program_test;
|
mod program_test;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_perp() -> Result<(), TransportError> {
|
async fn test_perp() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![cfg(feature = "test-bpf")]
|
#![cfg(feature = "test-bpf")]
|
||||||
|
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
use solana_sdk::signature::Keypair;
|
||||||
|
|
||||||
use mango_v4::{
|
use mango_v4::{
|
||||||
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
|
instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side},
|
||||||
|
@ -12,7 +12,7 @@ use program_test::*;
|
||||||
mod program_test;
|
mod program_test;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_serum() -> Result<(), TransportError> {
|
async fn test_serum() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
use mango_v4::state::Bank;
|
use mango_v4::state::Bank;
|
||||||
use solana_program_test::*;
|
use solana_program_test::*;
|
||||||
use solana_sdk::{signature::Keypair, transport::TransportError};
|
use solana_sdk::signature::Keypair;
|
||||||
|
|
||||||
use program_test::*;
|
use program_test::*;
|
||||||
|
|
||||||
mod program_test;
|
mod program_test;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_update_index() -> Result<(), TransportError> {
|
async fn test_update_index() -> Result<(), BanksClientError> {
|
||||||
let context = TestContext::new().await;
|
let context = TestContext::new().await;
|
||||||
let solana = &context.solana.clone();
|
let solana = &context.solana.clone();
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"example0": "ts-node ts/example0.ts",
|
"example1-user": "ts-node src/example1-user.ts",
|
||||||
"example1-user": "ts-node ts/example1-user.ts",
|
"example1-admin": "ts-node src/example1-admin.ts",
|
||||||
"example1-admin": "ts-node ts/example1-admin.ts",
|
|
||||||
"format": "prettier --check .",
|
"format": "prettier --check .",
|
||||||
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
|
"lint": "eslint . --ext ts --ext tsx --ext js --quiet",
|
||||||
"type-check": "tsc --pretty --noEmit"
|
"type-check": "tsc --pretty --noEmit"
|
|
@ -1,15 +1,18 @@
|
||||||
|
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
import { MangoClient } from '../../client';
|
import { MangoClient } from '../client';
|
||||||
import { I80F48, I80F48Dto } from './I80F48';
|
import { I80F48, I80F48Dto } from './I80F48';
|
||||||
|
|
||||||
export class Bank {
|
export class Bank {
|
||||||
|
public name: string;
|
||||||
public depositIndex: I80F48;
|
public depositIndex: I80F48;
|
||||||
public borrowIndex: I80F48;
|
public borrowIndex: I80F48;
|
||||||
|
|
||||||
static from(
|
static from(
|
||||||
publicKey: PublicKey,
|
publicKey: PublicKey,
|
||||||
obj: {
|
obj: {
|
||||||
|
name: number[];
|
||||||
group: PublicKey;
|
group: PublicKey;
|
||||||
mint: PublicKey;
|
mint: PublicKey;
|
||||||
vault: PublicKey;
|
vault: PublicKey;
|
||||||
|
@ -29,6 +32,7 @@ export class Bank {
|
||||||
) {
|
) {
|
||||||
return new Bank(
|
return new Bank(
|
||||||
publicKey,
|
publicKey,
|
||||||
|
obj.name,
|
||||||
obj.group,
|
obj.group,
|
||||||
obj.mint,
|
obj.mint,
|
||||||
obj.vault,
|
obj.vault,
|
||||||
|
@ -49,6 +53,7 @@ export class Bank {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public publicKey: PublicKey,
|
public publicKey: PublicKey,
|
||||||
|
name: number[],
|
||||||
public group: PublicKey,
|
public group: PublicKey,
|
||||||
public mint: PublicKey,
|
public mint: PublicKey,
|
||||||
public vault: PublicKey,
|
public vault: PublicKey,
|
||||||
|
@ -65,6 +70,7 @@ export class Bank {
|
||||||
dust: Object,
|
dust: Object,
|
||||||
public tokenIndex: number,
|
public tokenIndex: number,
|
||||||
) {
|
) {
|
||||||
|
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||||
this.depositIndex = I80F48.from(depositIndex);
|
this.depositIndex = I80F48.from(depositIndex);
|
||||||
this.borrowIndex = I80F48.from(borrowIndex);
|
this.borrowIndex = I80F48.from(borrowIndex);
|
||||||
}
|
}
|
|
@ -1,9 +1,5 @@
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import { MangoClient } from '../../client';
|
import { MangoClient } from '../client';
|
||||||
import {
|
|
||||||
DEVNET_MINTS_REVERSE,
|
|
||||||
DEVNET_SERUM3_MARKETS_REVERSE,
|
|
||||||
} from '../../constants';
|
|
||||||
import { Bank } from './bank';
|
import { Bank } from './bank';
|
||||||
import { Serum3Market } from './serum3';
|
import { Serum3Market } from './serum3';
|
||||||
|
|
||||||
|
@ -32,20 +28,13 @@ export class Group {
|
||||||
|
|
||||||
public async reloadBanks(client: MangoClient) {
|
public async reloadBanks(client: MangoClient) {
|
||||||
const banks = await client.getBanksForGroup(this);
|
const banks = await client.getBanksForGroup(this);
|
||||||
this.banksMap = new Map(
|
this.banksMap = new Map(banks.map((bank) => [bank.name, bank]));
|
||||||
banks.map((bank) => [DEVNET_MINTS_REVERSE[bank.mint.toBase58()], bank]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async reloadSerum3Markets(client: MangoClient) {
|
public async reloadSerum3Markets(client: MangoClient) {
|
||||||
const serum3Markets = await client.serum3GetMarket(this);
|
const serum3Markets = await client.serum3GetMarket(this);
|
||||||
this.serum3MarketsMap = new Map(
|
this.serum3MarketsMap = new Map(
|
||||||
serum3Markets.map((serum3Market) => [
|
serum3Markets.map((serum3Market) => [serum3Market.name, serum3Market]),
|
||||||
DEVNET_SERUM3_MARKETS_REVERSE[
|
|
||||||
serum3Market.serumMarketExternal.toBase58()
|
|
||||||
],
|
|
||||||
serum3Market,
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
|
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import { Bank } from './bank';
|
import { Bank } from './bank';
|
||||||
import { I80F48, I80F48Dto } from './I80F48';
|
import { I80F48, I80F48Dto } from './I80F48';
|
||||||
|
|
||||||
export class MangoAccount {
|
export class MangoAccount {
|
||||||
public tokens: TokenAccount[];
|
public tokens: TokenAccount[];
|
||||||
public serum3: Serum3Account[];
|
public serum3: Serum3Account[];
|
||||||
|
public name: string;
|
||||||
|
|
||||||
static from(
|
static from(
|
||||||
publicKey: PublicKey,
|
publicKey: PublicKey,
|
||||||
obj: {
|
obj: {
|
||||||
|
name: number[];
|
||||||
group: PublicKey;
|
group: PublicKey;
|
||||||
owner: PublicKey;
|
owner: PublicKey;
|
||||||
delegate: PublicKey;
|
delegate: PublicKey;
|
||||||
|
@ -24,6 +26,7 @@ export class MangoAccount {
|
||||||
) {
|
) {
|
||||||
return new MangoAccount(
|
return new MangoAccount(
|
||||||
publicKey,
|
publicKey,
|
||||||
|
obj.name,
|
||||||
obj.group,
|
obj.group,
|
||||||
obj.owner,
|
obj.owner,
|
||||||
obj.delegate,
|
obj.delegate,
|
||||||
|
@ -40,6 +43,7 @@ export class MangoAccount {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public publicKey: PublicKey,
|
public publicKey: PublicKey,
|
||||||
|
name: number[],
|
||||||
public group: PublicKey,
|
public group: PublicKey,
|
||||||
public owner: PublicKey,
|
public owner: PublicKey,
|
||||||
public delegate: PublicKey,
|
public delegate: PublicKey,
|
||||||
|
@ -52,6 +56,7 @@ export class MangoAccount {
|
||||||
bump: number,
|
bump: number,
|
||||||
reserved: number[],
|
reserved: number[],
|
||||||
) {
|
) {
|
||||||
|
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||||
this.tokens = tokens.values.map((dto) => TokenAccount.from(dto));
|
this.tokens = tokens.values.map((dto) => TokenAccount.from(dto));
|
||||||
this.serum3 = serum3.values.map((dto) => Serum3Account.from(dto));
|
this.serum3 = serum3.values.map((dto) => Serum3Account.from(dto));
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { PublicKey, TransactionSignature } from '@solana/web3.js';
|
import { PublicKey, TransactionSignature } from '@solana/web3.js';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import { MangoClient } from '../../client';
|
import { MangoClient } from '../client';
|
||||||
import { I80F48, I80F48Dto } from './I80F48';
|
import { I80F48, I80F48Dto } from './I80F48';
|
||||||
|
|
||||||
export class StubOracle {
|
export class StubOracle {
|
|
@ -1,9 +1,12 @@
|
||||||
|
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
|
|
||||||
export class Serum3Market {
|
export class Serum3Market {
|
||||||
|
public name: string;
|
||||||
static from(
|
static from(
|
||||||
publicKey: PublicKey,
|
publicKey: PublicKey,
|
||||||
obj: {
|
obj: {
|
||||||
|
name: number[];
|
||||||
group: PublicKey;
|
group: PublicKey;
|
||||||
serumProgram: PublicKey;
|
serumProgram: PublicKey;
|
||||||
serumMarketExternal: PublicKey;
|
serumMarketExternal: PublicKey;
|
||||||
|
@ -16,6 +19,7 @@ export class Serum3Market {
|
||||||
): Serum3Market {
|
): Serum3Market {
|
||||||
return new Serum3Market(
|
return new Serum3Market(
|
||||||
publicKey,
|
publicKey,
|
||||||
|
obj.name,
|
||||||
obj.group,
|
obj.group,
|
||||||
obj.serumProgram,
|
obj.serumProgram,
|
||||||
obj.serumMarketExternal,
|
obj.serumMarketExternal,
|
||||||
|
@ -27,13 +31,16 @@ export class Serum3Market {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public publicKey: PublicKey,
|
public publicKey: PublicKey,
|
||||||
|
name: number[],
|
||||||
public group: PublicKey,
|
public group: PublicKey,
|
||||||
public serumProgram: PublicKey,
|
public serumProgram: PublicKey,
|
||||||
public serumMarketExternal: PublicKey,
|
public serumMarketExternal: PublicKey,
|
||||||
public marketIndex: number,
|
public marketIndex: number,
|
||||||
public baseTokenIndex: number,
|
public baseTokenIndex: number,
|
||||||
public quoteTokenIndex: number,
|
public quoteTokenIndex: number,
|
||||||
) {}
|
) {
|
||||||
|
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Serum3SelfTradeBehavior {
|
export class Serum3SelfTradeBehavior {
|
|
@ -10,17 +10,17 @@ import {
|
||||||
TransactionSignature,
|
TransactionSignature,
|
||||||
} from '@solana/web3.js';
|
} from '@solana/web3.js';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
import { Bank, getMintInfoForTokenIndex } from './accounts/types/bank';
|
import { Bank, getMintInfoForTokenIndex } from './accounts/bank';
|
||||||
import { Group } from './accounts/types/group';
|
import { Group } from './accounts/group';
|
||||||
import { I80F48 } from './accounts/types/I80F48';
|
import { I80F48 } from './accounts/I80F48';
|
||||||
import { MangoAccount } from './accounts/types/mangoAccount';
|
import { MangoAccount } from './accounts/mangoAccount';
|
||||||
import { StubOracle } from './accounts/types/oracle';
|
import { StubOracle } from './accounts/oracle';
|
||||||
import {
|
import {
|
||||||
Serum3Market,
|
Serum3Market,
|
||||||
Serum3OrderType,
|
Serum3OrderType,
|
||||||
Serum3SelfTradeBehavior,
|
Serum3SelfTradeBehavior,
|
||||||
Serum3Side,
|
Serum3Side,
|
||||||
} from './accounts/types/serum3';
|
} from './accounts/serum3';
|
||||||
import { IDL, MangoV4 } from './mango_v4';
|
import { IDL, MangoV4 } from './mango_v4';
|
||||||
|
|
||||||
export const MANGO_V4_ID = new PublicKey(
|
export const MANGO_V4_ID = new PublicKey(
|
||||||
|
@ -76,15 +76,28 @@ export class MangoClient {
|
||||||
mintPk: PublicKey,
|
mintPk: PublicKey,
|
||||||
oraclePk: PublicKey,
|
oraclePk: PublicKey,
|
||||||
tokenIndex: number,
|
tokenIndex: number,
|
||||||
|
name: string,
|
||||||
|
util0: number,
|
||||||
|
rate0: number,
|
||||||
|
util1: number,
|
||||||
|
rate1: number,
|
||||||
|
maxRate: number,
|
||||||
|
maintAssetWeight: number,
|
||||||
|
initAssetWeight: number,
|
||||||
|
maintLiabWeight: number,
|
||||||
|
initLiabWeight: number,
|
||||||
|
liquidationFee: number,
|
||||||
): Promise<TransactionSignature> {
|
): Promise<TransactionSignature> {
|
||||||
return await this.program.methods
|
return await this.program.methods
|
||||||
.registerToken(
|
.registerToken(
|
||||||
tokenIndex,
|
tokenIndex,
|
||||||
0.8,
|
name,
|
||||||
0.6,
|
{ util0, rate0, util1, rate1, maxRate },
|
||||||
1.2,
|
maintAssetWeight,
|
||||||
1.4,
|
initAssetWeight,
|
||||||
0.02 /*TODO expose as args*/,
|
maintLiabWeight,
|
||||||
|
initLiabWeight,
|
||||||
|
liquidationFee,
|
||||||
)
|
)
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
|
@ -103,7 +116,7 @@ export class MangoClient {
|
||||||
{
|
{
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: group.publicKey.toBase58(),
|
bytes: group.publicKey.toBase58(),
|
||||||
offset: 8,
|
offset: 24,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
@ -173,10 +186,11 @@ export class MangoClient {
|
||||||
group: Group,
|
group: Group,
|
||||||
ownerPk: PublicKey,
|
ownerPk: PublicKey,
|
||||||
accountNumber?: number,
|
accountNumber?: number,
|
||||||
|
name?: string,
|
||||||
): Promise<MangoAccount> {
|
): Promise<MangoAccount> {
|
||||||
let mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk);
|
let mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk);
|
||||||
if (mangoAccounts.length === 0) {
|
if (mangoAccounts.length === 0) {
|
||||||
await this.createMangoAccount(group, accountNumber ?? 0);
|
await this.createMangoAccount(group, accountNumber ?? 0, name ?? '');
|
||||||
mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk);
|
mangoAccounts = await this.getMangoAccountForOwner(group, ownerPk);
|
||||||
}
|
}
|
||||||
return mangoAccounts[0];
|
return mangoAccounts[0];
|
||||||
|
@ -185,9 +199,10 @@ export class MangoClient {
|
||||||
public async createMangoAccount(
|
public async createMangoAccount(
|
||||||
group: Group,
|
group: Group,
|
||||||
accountNumber: number,
|
accountNumber: number,
|
||||||
|
name?: string,
|
||||||
): Promise<TransactionSignature> {
|
): Promise<TransactionSignature> {
|
||||||
return await this.program.methods
|
return await this.program.methods
|
||||||
.createAccount(accountNumber)
|
.createAccount(accountNumber, name ?? '')
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
owner: this.program.provider.wallet.publicKey,
|
owner: this.program.provider.wallet.publicKey,
|
||||||
|
@ -212,13 +227,13 @@ export class MangoClient {
|
||||||
{
|
{
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: group.publicKey.toBase58(),
|
bytes: group.publicKey.toBase58(),
|
||||||
offset: 8,
|
offset: 24,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: ownerPk.toBase58(),
|
bytes: ownerPk.toBase58(),
|
||||||
offset: 40,
|
offset: 56,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
@ -320,9 +335,10 @@ export class MangoClient {
|
||||||
baseBank: Bank,
|
baseBank: Bank,
|
||||||
quoteBank: Bank,
|
quoteBank: Bank,
|
||||||
marketIndex: number,
|
marketIndex: number,
|
||||||
|
name: string,
|
||||||
): Promise<TransactionSignature> {
|
): Promise<TransactionSignature> {
|
||||||
return await this.program.methods
|
return await this.program.methods
|
||||||
.serum3RegisterMarket(marketIndex)
|
.serum3RegisterMarket(marketIndex, name)
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
admin: this.program.provider.wallet.publicKey,
|
admin: this.program.provider.wallet.publicKey,
|
||||||
|
@ -347,7 +363,7 @@ export class MangoClient {
|
||||||
{
|
{
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: group.publicKey.toBase58(),
|
bytes: group.publicKey.toBase58(),
|
||||||
offset: 8,
|
offset: 24,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -358,7 +374,7 @@ export class MangoClient {
|
||||||
filters.push({
|
filters.push({
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: bs58.encode(bbuf),
|
bytes: bs58.encode(bbuf),
|
||||||
offset: 106,
|
offset: 122,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -369,7 +385,7 @@ export class MangoClient {
|
||||||
filters.push({
|
filters.push({
|
||||||
memcmp: {
|
memcmp: {
|
||||||
bytes: bs58.encode(qbuf),
|
bytes: bs58.encode(qbuf),
|
||||||
offset: 108,
|
offset: 124,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
|
|
||||||
export const DEVNET_GROUP = 'Fwhv1B7yysktAqmoKbV6f1p25ap26Q81NKvd4jApmiB2';
|
export const DEVNET_GROUP = '4Fv4jWsd9kYZjCMvkpcXnS63x9cHHHTqCDHTTTB5MbQt';
|
||||||
|
|
||||||
export const DEVNET_MINTS = new Map([
|
export const DEVNET_MINTS = new Map([
|
||||||
['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'],
|
['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'],
|
|
@ -42,7 +42,23 @@ async function main() {
|
||||||
const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!);
|
const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!);
|
||||||
const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!);
|
const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!);
|
||||||
try {
|
try {
|
||||||
await client.registerToken(group, btcDevnetMint, btcDevnetOracle, 0);
|
await client.registerToken(
|
||||||
|
group,
|
||||||
|
btcDevnetMint,
|
||||||
|
btcDevnetOracle,
|
||||||
|
0,
|
||||||
|
'BTC',
|
||||||
|
0.4,
|
||||||
|
0.07,
|
||||||
|
0.8,
|
||||||
|
0.9,
|
||||||
|
1.5,
|
||||||
|
0.8,
|
||||||
|
0.6,
|
||||||
|
1.2,
|
||||||
|
1.4,
|
||||||
|
0.02,
|
||||||
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
|
||||||
// stub oracle + register token 1
|
// stub oracle + register token 1
|
||||||
|
@ -58,6 +74,17 @@ async function main() {
|
||||||
usdcDevnetMint,
|
usdcDevnetMint,
|
||||||
usdcDevnetOracle.publicKey,
|
usdcDevnetOracle.publicKey,
|
||||||
1,
|
1,
|
||||||
|
'USDC',
|
||||||
|
0.4,
|
||||||
|
0.07,
|
||||||
|
0.8,
|
||||||
|
0.9,
|
||||||
|
1.5,
|
||||||
|
0.8,
|
||||||
|
0.6,
|
||||||
|
1.2,
|
||||||
|
1.4,
|
||||||
|
0.02,
|
||||||
);
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
|
||||||
|
@ -82,6 +109,7 @@ async function main() {
|
||||||
banks[0],
|
banks[0],
|
||||||
banks[1],
|
banks[1],
|
||||||
0,
|
0,
|
||||||
|
'BTC/USDC',
|
||||||
);
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
const markets = await client.serum3GetMarket(
|
const markets = await client.serum3GetMarket(
|
|
@ -5,7 +5,7 @@ import {
|
||||||
Serum3OrderType,
|
Serum3OrderType,
|
||||||
Serum3SelfTradeBehavior,
|
Serum3SelfTradeBehavior,
|
||||||
Serum3Side,
|
Serum3Side,
|
||||||
} from './accounts/types/serum3';
|
} from './accounts/serum3';
|
||||||
import { MangoClient } from './client';
|
import { MangoClient } from './client';
|
||||||
import { DEVNET_GROUP, DEVNET_SERUM3_PROGRAM_ID } from './constants';
|
import { DEVNET_GROUP, DEVNET_SERUM3_PROGRAM_ID } from './constants';
|
||||||
|
|
||||||
|
@ -33,11 +33,16 @@ async function main() {
|
||||||
const group = await client.getGroup(new PublicKey(DEVNET_GROUP));
|
const group = await client.getGroup(new PublicKey(DEVNET_GROUP));
|
||||||
console.log(`Group ${group.publicKey.toBase58()}`);
|
console.log(`Group ${group.publicKey.toBase58()}`);
|
||||||
|
|
||||||
|
for (const bank of group.banksMap.values()) {
|
||||||
|
console.log(bank.publicKey.toBase58());
|
||||||
|
}
|
||||||
|
|
||||||
// create + fetch account
|
// create + fetch account
|
||||||
const mangoAccount = await client.getOrCreateMangoAccount(
|
const mangoAccount = await client.getOrCreateMangoAccount(
|
||||||
group,
|
group,
|
||||||
user.publicKey,
|
user.publicKey,
|
||||||
0,
|
0,
|
||||||
|
'my_mango_account',
|
||||||
);
|
);
|
||||||
console.log(`MangoAccount ${mangoAccount.publicKey}`);
|
console.log(`MangoAccount ${mangoAccount.publicKey}`);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export { Group } from './client/accounts/group';
|
||||||
|
export * from './client/accounts/I80F48';
|
||||||
|
export {
|
||||||
|
MangoAccount,
|
||||||
|
TokenAccount,
|
||||||
|
TokenAccountDto,
|
||||||
|
} from './client/accounts/mangoAccount';
|
||||||
|
export { StubOracle } from './client/accounts/oracle';
|
||||||
|
export { Serum3Market } from './client/accounts/serum3';
|
||||||
|
export * from './client/client';
|
|
@ -164,6 +164,16 @@ export type MangoV4 = {
|
||||||
"name": "tokenIndex",
|
"name": "tokenIndex",
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "interestRateParams",
|
||||||
|
"type": {
|
||||||
|
"defined": "InterestRateParams"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
|
@ -186,6 +196,17 @@ export type MangoV4 = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "updateIndex",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "bank",
|
||||||
|
"isMut": true,
|
||||||
|
"isSigner": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createAccount",
|
"name": "createAccount",
|
||||||
"accounts": [
|
"accounts": [
|
||||||
|
@ -243,6 +264,10 @@ export type MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "accountNum",
|
"name": "accountNum",
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -568,6 +593,10 @@ export type MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "marketIndex",
|
"name": "marketIndex",
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1315,6 +1344,15 @@ export type MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -1355,6 +1393,40 @@ export type MangoV4 = {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "lastUpdated",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util0",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate0",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util1",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate1",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maxRate",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -1492,6 +1564,15 @@ export type MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -1802,6 +1883,15 @@ export type MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -2050,6 +2140,34 @@ export type MangoV4 = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "InterestRateParams",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "util0",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate0",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util1",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate1",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maxRate",
|
||||||
|
"type": "f32"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TokenIndex",
|
"name": "TokenIndex",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -2562,6 +2680,16 @@ export const IDL: MangoV4 = {
|
||||||
"name": "tokenIndex",
|
"name": "tokenIndex",
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "interestRateParams",
|
||||||
|
"type": {
|
||||||
|
"defined": "InterestRateParams"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintAssetWeight",
|
||||||
"type": "f32"
|
"type": "f32"
|
||||||
|
@ -2584,6 +2712,17 @@ export const IDL: MangoV4 = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "updateIndex",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "bank",
|
||||||
|
"isMut": true,
|
||||||
|
"isSigner": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "createAccount",
|
"name": "createAccount",
|
||||||
"accounts": [
|
"accounts": [
|
||||||
|
@ -2641,6 +2780,10 @@ export const IDL: MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "accountNum",
|
"name": "accountNum",
|
||||||
"type": "u8"
|
"type": "u8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2966,6 +3109,10 @@ export const IDL: MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "marketIndex",
|
"name": "marketIndex",
|
||||||
"type": "u16"
|
"type": "u16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -3713,6 +3860,15 @@ export const IDL: MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -3753,6 +3909,40 @@ export const IDL: MangoV4 = {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "lastUpdated",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util0",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate0",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util1",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate1",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maxRate",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maintAssetWeight",
|
"name": "maintAssetWeight",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -3890,6 +4080,15 @@ export const IDL: MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -4200,6 +4399,15 @@ export const IDL: MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "struct",
|
"kind": "struct",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": {
|
||||||
|
"array": [
|
||||||
|
"u8",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"type": "publicKey"
|
"type": "publicKey"
|
||||||
|
@ -4448,6 +4656,34 @@ export const IDL: MangoV4 = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "InterestRateParams",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "util0",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate0",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "util1",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rate1",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maxRate",
|
||||||
|
"type": "f32"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TokenIndex",
|
"name": "TokenIndex",
|
||||||
"type": {
|
"type": {
|
10
ts/index.ts
10
ts/index.ts
|
@ -1,10 +0,0 @@
|
||||||
export { Group } from './accounts/types/group';
|
|
||||||
export * from './accounts/types/I80F48';
|
|
||||||
export {
|
|
||||||
MangoAccount,
|
|
||||||
TokenAccount,
|
|
||||||
TokenAccountDto,
|
|
||||||
} from './accounts/types/mangoAccount';
|
|
||||||
export { StubOracle } from './accounts/types/oracle';
|
|
||||||
export { Serum3Market } from './accounts/types/serum3';
|
|
||||||
export * from './client';
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e pipefail
|
||||||
|
|
||||||
|
anchor build --skip-lint
|
||||||
|
./idl-fixup.sh
|
||||||
|
cp -v ./target/types/mango_v4.ts ./ts/mango_v4.ts
|
||||||
|
tsc
|
Loading…
Reference in New Issue