commit
5221bbd53b
|
@ -1577,6 +1577,17 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0"
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.39",
|
||||
"quote 1.0.18",
|
||||
"syn 1.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
|
@ -3192,6 +3203,7 @@ dependencies = [
|
|||
"borsh",
|
||||
"bytemuck",
|
||||
"checked_math",
|
||||
"derivative",
|
||||
"env_logger 0.9.0",
|
||||
"fixed",
|
||||
"fixed-macro",
|
||||
|
|
|
@ -16,6 +16,6 @@ RUN --mount=type=cache,target=/usr/local/cargo,from=rust,source=/usr/local/cargo
|
|||
# Copy bins out of cache
|
||||
RUN --mount=type=cache,target=target mkdir .bin && cp target/release/keeper target/release/liquidator .bin/
|
||||
|
||||
FROM debian:buster-slim as run
|
||||
RUN apt-get update && apt-get -y install ca-certificates
|
||||
FROM debian:bullseye-slim as run
|
||||
RUN apt-get update && apt-get -y install ca-certificates libc6
|
||||
COPY --from=build /app/.bin/* /usr/local/bin/
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
# heroku container:push keeper -R -a HEROKU_APP_NAME
|
||||
# heroku container:release -a HEROKU_APP_NAME
|
||||
FROM us-docker.pkg.dev/mango-markets/gcr.io/mango-v4:latest
|
||||
ENTRYPOINT ["liquidator"]
|
||||
CMD ["liquidator"]
|
||||
|
|
|
@ -28,6 +28,7 @@ bincode = "1.3.3"
|
|||
borsh = { version = "0.9.3", features = ["const-generics"] }
|
||||
bytemuck = "^1.7.2"
|
||||
checked_math = { path = "../../lib/checked_math" }
|
||||
derivative = "2.2.0"
|
||||
fixed = { version = "=1.11.0", features = ["serde", "borsh"] } # todo: higher versions don't work
|
||||
fixed-macro = "^1.1.1"
|
||||
mango-macro = { path = "../../mango-macro" }
|
||||
|
|
|
@ -27,13 +27,11 @@ pub struct AccountClose<'info> {
|
|||
pub fn account_close(ctx: Context<AccountClose>) -> Result<()> {
|
||||
let group = ctx.accounts.group.load()?;
|
||||
|
||||
{
|
||||
let account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
// don't perform checks if group is just testing
|
||||
if group.testing == 0 {
|
||||
if !group.is_testing() {
|
||||
require!(!account.fixed.being_liquidated(), MangoError::SomeError);
|
||||
require_eq!(account.fixed.delegate, Pubkey::default());
|
||||
for ele in account.token_iter() {
|
||||
require_eq!(ele.is_active(), false);
|
||||
}
|
||||
|
@ -44,7 +42,6 @@ pub fn account_close(ctx: Context<AccountClose>) -> Result<()> {
|
|||
require_eq!(ele.is_active(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use anchor_lang::prelude::*;
|
|||
|
||||
use crate::error::*;
|
||||
use crate::state::*;
|
||||
use crate::util::fill32_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(account_num: u32, token_count: u8, serum3_count: u8, perp_count: u8, perp_oo_count: u8)]
|
||||
|
@ -11,7 +11,7 @@ pub struct AccountCreate<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"MangoAccount".as_ref(), owner.key().as_ref(), &account_num.to_le_bytes()],
|
||||
seeds = [b"MangoAccount".as_ref(), group.key().as_ref(), owner.key().as_ref(), &account_num.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = MangoAccount::space(token_count, serum3_count, perp_count, perp_oo_count)?,
|
||||
|
@ -41,7 +41,7 @@ pub fn account_create(
|
|||
account.header_version()
|
||||
);
|
||||
|
||||
account.fixed.name = fill32_from_str(name)?;
|
||||
account.fixed.name = fill_from_str(&name)?;
|
||||
account.fixed.group = ctx.accounts.group.key();
|
||||
account.fixed.owner = ctx.accounts.owner.key();
|
||||
account.fixed.account_num = account_num;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::error::MangoError;
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
use crate::error::MangoError;
|
||||
use crate::state::*;
|
||||
use crate::util::fill32_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AccountEdit<'info> {
|
||||
|
@ -34,7 +34,7 @@ pub fn account_edit(
|
|||
// please maintain, and don't remove, makes it easy to reason about which support modification by owner
|
||||
|
||||
if let Some(name) = name_opt {
|
||||
account.fixed.name = fill32_from_str(name)?;
|
||||
account.fixed.name = fill_from_str(&name)?;
|
||||
}
|
||||
|
||||
// unchanged -
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
use crate::state::*;
|
||||
use crate::util::checked_math as cm;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AccountExpand<'info> {
|
||||
|
@ -32,6 +33,7 @@ pub fn account_expand(
|
|||
|
||||
let realloc_account = ctx.accounts.account.as_ref();
|
||||
let old_space = realloc_account.data_len();
|
||||
let old_lamports = realloc_account.lamports();
|
||||
|
||||
require_gt!(new_space, old_space);
|
||||
|
||||
|
@ -44,13 +46,11 @@ pub fn account_expand(
|
|||
to: realloc_account.clone(),
|
||||
},
|
||||
),
|
||||
new_rent_minimum
|
||||
.checked_sub(realloc_account.lamports())
|
||||
.unwrap(),
|
||||
cm!(new_rent_minimum - old_lamports),
|
||||
)?;
|
||||
|
||||
// realloc
|
||||
realloc_account.realloc(new_space, true)?;
|
||||
// realloc: it's safe to not re-zero-init since we never shrink accounts
|
||||
realloc_account.realloc(new_space, false)?;
|
||||
|
||||
// expand dynamic content, e.g. to grow token positions, we need to slide serum3orders further later, and so on....
|
||||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
|
|
|
@ -26,9 +26,7 @@ pub struct GroupClose<'info> {
|
|||
}
|
||||
|
||||
pub fn group_close(ctx: Context<GroupClose>) -> Result<()> {
|
||||
// TODO: checks
|
||||
|
||||
// close insurance vault
|
||||
// close insurance vault (must be empty)
|
||||
let group = ctx.accounts.group.load()?;
|
||||
let group_seeds = group_seeds!(group);
|
||||
let cpi_accounts = CloseAccount {
|
||||
|
|
|
@ -22,7 +22,7 @@ pub struct GroupCreate<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"InsuranceVault".as_ref()],
|
||||
seeds = [b"InsuranceVault".as_ref(), group.key().as_ref()],
|
||||
bump,
|
||||
token::authority = group,
|
||||
token::mint = insurance_mint,
|
||||
|
@ -46,12 +46,12 @@ pub fn group_create(
|
|||
) -> Result<()> {
|
||||
let mut group = ctx.accounts.group.load_init()?;
|
||||
group.creator = ctx.accounts.creator.key();
|
||||
group.group_num = group_num;
|
||||
group.admin = ctx.accounts.creator.key();
|
||||
group.fast_listing_admin = Pubkey::default();
|
||||
group.insurance_vault = ctx.accounts.insurance_vault.key();
|
||||
group.insurance_mint = ctx.accounts.insurance_mint.key();
|
||||
group.bump = *ctx.bumps.get("group").ok_or(MangoError::SomeError)?;
|
||||
group.group_num = group_num;
|
||||
group.testing = testing;
|
||||
group.version = version;
|
||||
Ok(())
|
||||
|
|
|
@ -13,14 +13,31 @@ pub struct GroupEdit<'info> {
|
|||
}
|
||||
|
||||
// use case - transfer group ownership to governance, where
|
||||
// new_admin and new_fast_listing_admin are PDAs
|
||||
// admin and fast_listing_admin are PDAs
|
||||
pub fn group_edit(
|
||||
ctx: Context<GroupEdit>,
|
||||
new_admin: Pubkey,
|
||||
new_fast_listing_admin: Pubkey,
|
||||
admin_opt: Option<Pubkey>,
|
||||
fast_listing_admin_opt: Option<Pubkey>,
|
||||
testing_opt: Option<u8>,
|
||||
version_opt: Option<u8>,
|
||||
) -> Result<()> {
|
||||
let mut group = ctx.accounts.group.load_mut()?;
|
||||
group.admin = new_admin;
|
||||
group.fast_listing_admin = new_fast_listing_admin;
|
||||
|
||||
if let Some(admin) = admin_opt {
|
||||
group.admin = admin;
|
||||
}
|
||||
|
||||
if let Some(fast_listing_admin) = fast_listing_admin_opt {
|
||||
group.fast_listing_admin = fast_listing_admin;
|
||||
}
|
||||
|
||||
if let Some(testing) = testing_opt {
|
||||
group.testing = testing;
|
||||
}
|
||||
|
||||
if let Some(version) = version_opt {
|
||||
group.version = version;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use fixed::types::I80F48;
|
|||
use crate::error::MangoError;
|
||||
|
||||
use crate::state::*;
|
||||
use crate::util::fill16_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(perp_market_index: PerpMarketIndex)]
|
||||
|
@ -21,7 +21,7 @@ pub struct PerpCreateMarket<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"PerpMarket".as_ref(), perp_market_index.to_le_bytes().as_ref()],
|
||||
seeds = [b"PerpMarket".as_ref(), group.key().as_ref(), perp_market_index.to_le_bytes().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<PerpMarket>(),
|
||||
|
@ -66,7 +66,7 @@ pub fn perp_create_market(
|
|||
) -> Result<()> {
|
||||
let mut perp_market = ctx.accounts.perp_market.load_init()?;
|
||||
*perp_market = PerpMarket {
|
||||
name: fill16_from_str(name)?,
|
||||
name: fill_from_str(&name)?,
|
||||
group: ctx.accounts.group.key(),
|
||||
oracle: ctx.accounts.oracle.key(),
|
||||
oracle_config,
|
||||
|
|
|
@ -25,7 +25,7 @@ pub struct Serum3CreateOpenOrders<'info> {
|
|||
// initialized by this instruction via cpi to serum
|
||||
#[account(
|
||||
init,
|
||||
seeds = [account.key().as_ref(), b"Serum3OO".as_ref(), serum_market.key().as_ref()],
|
||||
seeds = [b"Serum3OO".as_ref(), account.key().as_ref(), serum_market.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
owner = serum_program.key(),
|
||||
|
|
|
@ -3,7 +3,7 @@ use anchor_lang::prelude::*;
|
|||
use crate::error::MangoError;
|
||||
use crate::serum3_cpi::{load_market_state, pubkey_from_u64_array};
|
||||
use crate::state::*;
|
||||
use crate::util::fill16_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Serum3RegisterMarket<'info> {
|
||||
|
@ -24,7 +24,7 @@ pub struct Serum3RegisterMarket<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the serum_market_external in the seed guards against registering the same market twice
|
||||
seeds = [group.key().as_ref(), b"Serum3Market".as_ref(), serum_market_external.key().as_ref()],
|
||||
seeds = [b"Serum3Market".as_ref(), group.key().as_ref(), serum_market_external.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<Serum3Market>(),
|
||||
|
@ -67,7 +67,7 @@ pub fn serum3_register_market(
|
|||
|
||||
let mut serum_market = ctx.accounts.serum_market.load_init()?;
|
||||
*serum_market = Serum3Market {
|
||||
name: fill16_from_str(name)?,
|
||||
name: fill_from_str(&name)?,
|
||||
group: ctx.accounts.group.key(),
|
||||
serum_program: ctx.accounts.serum_program.key(),
|
||||
serum_market_external: ctx.accounts.serum_market_external.key(),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct StubOracleCreate<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"StubOracle".as_ref(), mint.key().as_ref()],
|
||||
seeds = [b"StubOracle".as_ref(), group.key().as_ref(), mint.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<StubOracle>(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use anchor_spl::token::{Mint, Token, TokenAccount};
|
||||
|
||||
use crate::error::*;
|
||||
use crate::state::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -25,7 +26,7 @@ pub struct TokenAddBank<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the token_index in this seed guards against reusing it
|
||||
seeds = [group.key().as_ref(), b"Bank".as_ref(), &token_index.to_le_bytes(), &bank_num.to_le_bytes()],
|
||||
seeds = [b"Bank".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &bank_num.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<Bank>(),
|
||||
|
@ -34,7 +35,7 @@ pub struct TokenAddBank<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"Vault".as_ref(), &token_index.to_le_bytes(), &bank_num.to_le_bytes()],
|
||||
seeds = [b"Vault".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &bank_num.to_le_bytes()],
|
||||
bump,
|
||||
token::authority = group,
|
||||
token::mint = mint,
|
||||
|
@ -44,10 +45,12 @@ pub struct TokenAddBank<'info> {
|
|||
|
||||
#[account(
|
||||
mut,
|
||||
seeds = [group.key().as_ref(), b"MintInfo".as_ref(), mint.key().as_ref()],
|
||||
bump
|
||||
constraint = mint_info.load()?.token_index == token_index,
|
||||
has_one = group,
|
||||
has_one = mint,
|
||||
)]
|
||||
pub mint_info: AccountLoader<'info, MintInfo>,
|
||||
|
||||
#[account(mut)]
|
||||
pub payer: Signer<'info>,
|
||||
|
||||
|
@ -56,8 +59,6 @@ pub struct TokenAddBank<'info> {
|
|||
pub rent: Sysvar<'info, Rent>,
|
||||
}
|
||||
|
||||
// TODO: should this be "configure_mint", we pass an explicit index, and allow
|
||||
// overwriting config as long as the mint account stays the same?
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(unused_variables)]
|
||||
pub fn token_add_bank(
|
||||
|
@ -65,11 +66,10 @@ pub fn token_add_bank(
|
|||
token_index: TokenIndex,
|
||||
bank_num: u32,
|
||||
) -> Result<()> {
|
||||
// TODO: Error if mint is already configured (technically, init of vault will fail)
|
||||
|
||||
let existing_bank = ctx.accounts.existing_bank.load()?;
|
||||
let mut bank = ctx.accounts.bank.load_init()?;
|
||||
*bank = Bank::from_existing_bank(&existing_bank, ctx.accounts.vault.key(), bank_num);
|
||||
let bump = *ctx.bumps.get("bank").ok_or(MangoError::SomeError)?;
|
||||
*bank = Bank::from_existing_bank(&existing_bank, ctx.accounts.vault.key(), bank_num, bump);
|
||||
|
||||
let mut mint_info = ctx.accounts.mint_info.load_mut()?;
|
||||
let free_slot = mint_info
|
||||
|
|
|
@ -48,9 +48,6 @@ impl<'info> TokenDeposit<'info> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: It may make sense to have the token_index passed in from the outside.
|
||||
// That would save a lot of computation that needs to go into finding the
|
||||
// right index for the mint.
|
||||
pub fn token_deposit(ctx: Context<TokenDeposit>, amount: u64) -> Result<()> {
|
||||
require_msg!(amount > 0, "deposit amount must be positive");
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@ use crate::accounts_zerocopy::LoadMutZeroCopyRef;
|
|||
|
||||
use crate::state::*;
|
||||
|
||||
/// Changes a token's parameters.
|
||||
///
|
||||
/// In addition to these accounts, all banks must be passed as remaining_accounts
|
||||
/// in MintInfo order.
|
||||
#[derive(Accounts)]
|
||||
#[instruction(bank_num: u64)]
|
||||
pub struct TokenEdit<'info> {
|
||||
|
|
|
@ -5,7 +5,7 @@ use fixed_macro::types::I80F48;
|
|||
|
||||
use crate::error::*;
|
||||
use crate::state::*;
|
||||
use crate::util::fill16_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
pub const INDEX_START: I80F48 = I80F48!(1_000_000);
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub struct TokenRegister<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the token_index in this seed guards against reusing it
|
||||
seeds = [group.key().as_ref(), b"Bank".as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
seeds = [b"Bank".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<Bank>(),
|
||||
|
@ -34,7 +34,7 @@ pub struct TokenRegister<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"Vault".as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
seeds = [b"Vault".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
bump,
|
||||
token::authority = group,
|
||||
token::mint = mint,
|
||||
|
@ -45,7 +45,7 @@ pub struct TokenRegister<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the mint in this seed guards against registering the same mint twice
|
||||
seeds = [group.key().as_ref(), b"MintInfo".as_ref(), mint.key().as_ref()],
|
||||
seeds = [b"MintInfo".as_ref(), group.key().as_ref(), mint.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<MintInfo>(),
|
||||
|
@ -73,8 +73,6 @@ pub struct InterestRateParams {
|
|||
pub adjustment_factor: f32,
|
||||
}
|
||||
|
||||
// TODO: should this be "configure_mint", we pass an explicit index, and allow
|
||||
// overwriting config as long as the mint account stays the same?
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn token_register(
|
||||
ctx: Context<TokenRegister>,
|
||||
|
@ -101,7 +99,7 @@ pub fn token_register(
|
|||
let mut bank = ctx.accounts.bank.load_init()?;
|
||||
*bank = Bank {
|
||||
group: ctx.accounts.group.key(),
|
||||
name: fill16_from_str(name)?,
|
||||
name: fill_from_str(&name)?,
|
||||
mint: ctx.accounts.mint.key(),
|
||||
vault: ctx.accounts.vault.key(),
|
||||
oracle: ctx.accounts.oracle.key(),
|
||||
|
|
|
@ -5,7 +5,7 @@ use fixed::types::I80F48;
|
|||
use crate::error::*;
|
||||
use crate::instructions::INDEX_START;
|
||||
use crate::state::*;
|
||||
use crate::util::fill16_from_str;
|
||||
use crate::util::fill_from_str;
|
||||
|
||||
const FIRST_BANK_NUM: u32 = 0;
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub struct TokenRegisterTrustless<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the token_index in this seed guards against reusing it
|
||||
seeds = [group.key().as_ref(), b"Bank".as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
seeds = [b"Bank".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<Bank>(),
|
||||
|
@ -32,7 +32,7 @@ pub struct TokenRegisterTrustless<'info> {
|
|||
|
||||
#[account(
|
||||
init,
|
||||
seeds = [group.key().as_ref(), b"Vault".as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
seeds = [b"Vault".as_ref(), group.key().as_ref(), &token_index.to_le_bytes(), &FIRST_BANK_NUM.to_le_bytes()],
|
||||
bump,
|
||||
token::authority = group,
|
||||
token::mint = mint,
|
||||
|
@ -43,7 +43,7 @@ pub struct TokenRegisterTrustless<'info> {
|
|||
#[account(
|
||||
init,
|
||||
// using the mint in this seed guards against registering the same mint twice
|
||||
seeds = [group.key().as_ref(), b"MintInfo".as_ref(), mint.key().as_ref()],
|
||||
seeds = [b"MintInfo".as_ref(), group.key().as_ref(), mint.key().as_ref()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 8 + std::mem::size_of::<MintInfo>(),
|
||||
|
@ -72,7 +72,7 @@ pub fn token_register_trustless(
|
|||
let mut bank = ctx.accounts.bank.load_init()?;
|
||||
*bank = Bank {
|
||||
group: ctx.accounts.group.key(),
|
||||
name: fill16_from_str(name)?,
|
||||
name: fill_from_str(&name)?,
|
||||
mint: ctx.accounts.mint.key(),
|
||||
vault: ctx.accounts.vault.key(),
|
||||
oracle: ctx.accounts.oracle.key(),
|
||||
|
|
|
@ -17,6 +17,13 @@ pub mod compute_budget {
|
|||
declare_id!("ComputeBudget111111111111111111111111111111");
|
||||
}
|
||||
|
||||
/// Updates token interest and interest rates.
|
||||
///
|
||||
/// In addition to these accounts, all banks must be passed as remaining_accounts
|
||||
/// in MintInfo order.
|
||||
///
|
||||
/// This instruction may only be used alongside other instructions of the same kind
|
||||
/// or ComputeBudget instructions.
|
||||
#[derive(Accounts)]
|
||||
pub struct TokenUpdateIndexAndRate<'info> {
|
||||
pub group: AccountLoader<'info, Group>, // Required for group metadata parsing
|
||||
|
|
|
@ -41,10 +41,18 @@ pub mod mango_v4 {
|
|||
|
||||
pub fn group_edit(
|
||||
ctx: Context<GroupEdit>,
|
||||
new_admin: Pubkey,
|
||||
new_fast_listing_admin: Pubkey,
|
||||
admin_opt: Option<Pubkey>,
|
||||
fast_listing_admin_opt: Option<Pubkey>,
|
||||
testing_opt: Option<u8>,
|
||||
version_opt: Option<u8>,
|
||||
) -> Result<()> {
|
||||
instructions::group_edit(ctx, new_admin, new_fast_listing_admin)
|
||||
instructions::group_edit(
|
||||
ctx,
|
||||
admin_opt,
|
||||
fast_listing_admin_opt,
|
||||
testing_opt,
|
||||
version_opt,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn group_close(ctx: Context<GroupClose>) -> Result<()> {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use super::{OracleConfig, TokenIndex, TokenPosition};
|
||||
use crate::util;
|
||||
use crate::util::checked_math as cm;
|
||||
use anchor_lang::prelude::*;
|
||||
use derivative::Derivative;
|
||||
use fixed::types::I80F48;
|
||||
use fixed_macro::types::I80F48;
|
||||
use static_assertions::const_assert_eq;
|
||||
|
@ -13,11 +15,14 @@ pub const DAY_I80F48: I80F48 = I80F48!(86400);
|
|||
pub const YEAR_I80F48: I80F48 = I80F48!(31536000);
|
||||
pub const MINIMUM_MAX_RATE: I80F48 = I80F48!(0.5);
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug)]
|
||||
#[account(zero_copy)]
|
||||
pub struct Bank {
|
||||
// ABI: Clients rely on this being at offset 8
|
||||
pub group: Pubkey,
|
||||
|
||||
#[derivative(Debug(format_with = "util::format_zero_terminated_utf8_bytes"))]
|
||||
pub name: [u8; 16],
|
||||
|
||||
pub mint: Pubkey,
|
||||
|
@ -94,6 +99,7 @@ pub struct Bank {
|
|||
|
||||
pub bank_num: u32,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub reserved: [u8; 2560],
|
||||
}
|
||||
const_assert_eq!(
|
||||
|
@ -102,73 +108,37 @@ const_assert_eq!(
|
|||
);
|
||||
const_assert_eq!(size_of::<Bank>() % 8, 0);
|
||||
|
||||
impl std::fmt::Debug for Bank {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Bank")
|
||||
.field("name", &self.name())
|
||||
.field("group", &self.group)
|
||||
.field("mint", &self.mint)
|
||||
.field("vault", &self.vault)
|
||||
.field("oracle", &self.oracle)
|
||||
.field("oracle_config", &self.oracle_config)
|
||||
.field("deposit_index", &self.deposit_index)
|
||||
.field("borrow_index", &self.borrow_index)
|
||||
.field(
|
||||
"cached_indexed_total_deposits",
|
||||
&self.cached_indexed_total_deposits,
|
||||
)
|
||||
.field(
|
||||
"cached_indexed_total_borrows",
|
||||
&self.cached_indexed_total_borrows,
|
||||
)
|
||||
.field("indexed_deposits", &self.indexed_deposits)
|
||||
.field("indexed_borrows", &self.indexed_borrows)
|
||||
.field("index_last_updated", &self.index_last_updated)
|
||||
.field("bank_rate_last_updated", &self.bank_rate_last_updated)
|
||||
.field("avg_utilization", &self.avg_utilization)
|
||||
.field("util0", &self.util0)
|
||||
.field("rate0", &self.rate0)
|
||||
.field("util1", &self.util1)
|
||||
.field("rate1", &self.rate1)
|
||||
.field("max_rate", &self.max_rate)
|
||||
.field("collected_fees_native", &self.collected_fees_native)
|
||||
.field("loan_origination_fee_rate", &self.loan_origination_fee_rate)
|
||||
.field("loan_fee_rate", &self.loan_fee_rate)
|
||||
.field("maint_asset_weight", &self.maint_asset_weight)
|
||||
.field("init_asset_weight", &self.init_asset_weight)
|
||||
.field("maint_liab_weight", &self.maint_liab_weight)
|
||||
.field("init_liab_weight", &self.init_liab_weight)
|
||||
.field("liquidation_fee", &self.liquidation_fee)
|
||||
.field("dust", &self.dust)
|
||||
.field("token_index", &self.token_index)
|
||||
.field(
|
||||
"flash_loan_approved_amount",
|
||||
&self.flash_loan_approved_amount,
|
||||
)
|
||||
.field(
|
||||
"flash_loan_token_account_initial",
|
||||
&self.flash_loan_token_account_initial,
|
||||
)
|
||||
.field("reserved", &self.reserved)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Bank {
|
||||
pub fn from_existing_bank(existing_bank: &Bank, vault: Pubkey, bank_num: u32) -> Self {
|
||||
pub fn from_existing_bank(
|
||||
existing_bank: &Bank,
|
||||
vault: Pubkey,
|
||||
bank_num: u32,
|
||||
bump: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
// values that must be reset/changed
|
||||
vault,
|
||||
indexed_deposits: I80F48::ZERO,
|
||||
indexed_borrows: I80F48::ZERO,
|
||||
collected_fees_native: I80F48::ZERO,
|
||||
dust: I80F48::ZERO,
|
||||
flash_loan_approved_amount: 0,
|
||||
flash_loan_token_account_initial: u64::MAX,
|
||||
bump,
|
||||
bank_num,
|
||||
|
||||
// values that can be copied
|
||||
// these are listed explicitly, so someone must make the decision when a
|
||||
// new field is added!
|
||||
name: existing_bank.name,
|
||||
group: existing_bank.group,
|
||||
mint: existing_bank.mint,
|
||||
vault,
|
||||
oracle: existing_bank.oracle,
|
||||
oracle_config: existing_bank.oracle_config,
|
||||
deposit_index: existing_bank.deposit_index,
|
||||
borrow_index: existing_bank.borrow_index,
|
||||
cached_indexed_total_deposits: existing_bank.cached_indexed_total_deposits,
|
||||
cached_indexed_total_borrows: existing_bank.cached_indexed_total_borrows,
|
||||
indexed_deposits: I80F48::ZERO,
|
||||
indexed_borrows: I80F48::ZERO,
|
||||
index_last_updated: existing_bank.index_last_updated,
|
||||
bank_rate_last_updated: existing_bank.bank_rate_last_updated,
|
||||
avg_utilization: existing_bank.avg_utilization,
|
||||
|
@ -178,7 +148,6 @@ impl Bank {
|
|||
util1: existing_bank.util1,
|
||||
rate1: existing_bank.rate1,
|
||||
max_rate: existing_bank.max_rate,
|
||||
collected_fees_native: existing_bank.collected_fees_native,
|
||||
loan_origination_fee_rate: existing_bank.loan_origination_fee_rate,
|
||||
loan_fee_rate: existing_bank.loan_fee_rate,
|
||||
maint_asset_weight: existing_bank.maint_asset_weight,
|
||||
|
@ -186,14 +155,9 @@ impl Bank {
|
|||
maint_liab_weight: existing_bank.maint_liab_weight,
|
||||
init_liab_weight: existing_bank.init_liab_weight,
|
||||
liquidation_fee: existing_bank.liquidation_fee,
|
||||
dust: I80F48::ZERO,
|
||||
flash_loan_approved_amount: 0,
|
||||
flash_loan_token_account_initial: u64::MAX,
|
||||
token_index: existing_bank.token_index,
|
||||
bump: existing_bank.bump,
|
||||
mint_decimals: existing_bank.mint_decimals,
|
||||
reserved: [0; 2560],
|
||||
bank_num,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,8 +499,8 @@ impl Bank {
|
|||
macro_rules! bank_seeds {
|
||||
( $bank:expr ) => {
|
||||
&[
|
||||
$bank.group.as_ref(),
|
||||
b"Bank".as_ref(),
|
||||
$bank.group.as_ref(),
|
||||
$bank.token_index.to_le_bytes(),
|
||||
&bank.bank_num.to_le_bytes(),
|
||||
&[$bank.bump],
|
||||
|
|
|
@ -956,14 +956,10 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
// update header
|
||||
let header_mut = self.header_mut();
|
||||
header_mut.token_count = new_token_count;
|
||||
header_mut.serum3_count = new_serum3_count;
|
||||
header_mut.perp_count = new_perp_count;
|
||||
header_mut.perp_oo_count = new_perp_oo_count;
|
||||
// update the already-parsed header
|
||||
*self.header_mut() = new_header;
|
||||
|
||||
// write new lengths (uses header)
|
||||
// write new lengths to the dynamic data (uses header)
|
||||
self.write_token_length();
|
||||
self.write_serum3_length();
|
||||
self.write_perp_length();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use checked_math as cm;
|
||||
use derivative::Derivative;
|
||||
use fixed::types::I80F48;
|
||||
use static_assertions::const_assert_eq;
|
||||
use std::cmp::Ordering;
|
||||
|
@ -10,7 +11,8 @@ use crate::state::*;
|
|||
pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX;
|
||||
|
||||
#[zero_copy]
|
||||
#[derive(AnchorDeserialize, AnchorSerialize, Debug)]
|
||||
#[derive(AnchorDeserialize, AnchorSerialize, Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct TokenPosition {
|
||||
// TODO: Why did we have deposits and borrows as two different values
|
||||
// if only one of them was allowed to be != 0 at a time?
|
||||
|
@ -26,8 +28,10 @@ pub struct TokenPosition {
|
|||
/// incremented when a market requires this position to stay alive
|
||||
pub in_use_count: u8,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding: [u8; 5],
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub reserved: [u8; 40],
|
||||
}
|
||||
|
||||
|
@ -82,7 +86,8 @@ impl TokenPosition {
|
|||
}
|
||||
|
||||
#[zero_copy]
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Debug)]
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct Serum3Orders {
|
||||
pub open_orders: Pubkey,
|
||||
|
||||
|
@ -101,8 +106,10 @@ pub struct Serum3Orders {
|
|||
pub base_token_index: TokenIndex,
|
||||
pub quote_token_index: TokenIndex,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding: [u8; 2],
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub reserved: [u8; 64],
|
||||
}
|
||||
const_assert_eq!(size_of::<Serum3Orders>(), 32 + 8 * 2 + 2 * 3 + 2 + 64);
|
||||
|
@ -137,9 +144,11 @@ impl Default for Serum3Orders {
|
|||
}
|
||||
|
||||
#[zero_copy]
|
||||
#[derive(AnchorSerialize, AnchorDeserialize)]
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct PerpPositions {
|
||||
pub market_index: PerpMarketIndex,
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding: [u8; 6],
|
||||
|
||||
/// Active position size, measured in base lots
|
||||
|
@ -168,22 +177,9 @@ pub struct PerpPositions {
|
|||
pub taker_base_lots: i64,
|
||||
pub taker_quote_lots: i64,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub reserved: [u8; 64],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PerpPositions {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("PerpAccount")
|
||||
.field("market_index", &self.market_index)
|
||||
.field("base_position_lots", &self.base_position_lots)
|
||||
.field("quote_position_native", &self.quote_position_native)
|
||||
.field("bids_base_lots", &self.bids_base_lots)
|
||||
.field("asks_base_lots", &self.asks_base_lots)
|
||||
.field("taker_base_lots", &self.taker_base_lots)
|
||||
.field("taker_quote_lots", &self.taker_quote_lots)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
const_assert_eq!(size_of::<PerpPositions>(), 8 + 7 * 8 + 3 * 16 + 64);
|
||||
const_assert_eq!(size_of::<PerpPositions>() % 8, 0);
|
||||
|
||||
|
@ -358,8 +354,8 @@ const_assert_eq!(size_of::<PerpOpenOrders>() % 8, 0);
|
|||
macro_rules! account_seeds {
|
||||
( $account:expr ) => {
|
||||
&[
|
||||
$account.group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
$account.group.as_ref(),
|
||||
$account.owner.as_ref(),
|
||||
&$account.account_num.to_le_bytes(),
|
||||
&[$account.bump],
|
||||
|
|
|
@ -48,8 +48,8 @@ impl Serum3Market {
|
|||
macro_rules! serum_market_seeds {
|
||||
( $acc:expr ) => {
|
||||
&[
|
||||
$acc.group.as_ref(),
|
||||
b"Serum3Market".as_ref(),
|
||||
$acc.group.as_ref(),
|
||||
$acc.serum_market_external.as_ref(),
|
||||
&[$acc.bump],
|
||||
]
|
||||
|
|
|
@ -20,18 +20,22 @@ macro_rules! checked_math {
|
|||
}
|
||||
pub(crate) use checked_math;
|
||||
|
||||
pub fn fill16_from_str(name: String) -> Result<[u8; 16]> {
|
||||
pub fn fill_from_str<const N: usize>(name: &str) -> Result<[u8; N]> {
|
||||
let name_bytes = name.as_bytes();
|
||||
require!(name_bytes.len() < 16, MangoError::SomeError);
|
||||
let mut name_ = [0u8; 16];
|
||||
require!(name_bytes.len() < N, MangoError::SomeError);
|
||||
let mut name_ = [0u8; N];
|
||||
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();
|
||||
require!(name_bytes.len() < 32, MangoError::SomeError);
|
||||
let mut name_ = [0u8; 32];
|
||||
name_[..name_bytes.len()].copy_from_slice(name_bytes);
|
||||
Ok(name_)
|
||||
pub fn format_zero_terminated_utf8_bytes(
|
||||
name: &[u8],
|
||||
fmt: &mut std::fmt::Formatter,
|
||||
) -> std::result::Result<(), std::fmt::Error> {
|
||||
fmt.write_str(
|
||||
std::str::from_utf8(name)
|
||||
.unwrap()
|
||||
.trim_matches(char::from(0)),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
|
|
@ -128,8 +128,8 @@ async fn get_mint_info_by_mint(
|
|||
) -> MintInfo {
|
||||
let mint_info_pk = Pubkey::find_program_address(
|
||||
&[
|
||||
account.fixed.group.as_ref(),
|
||||
b"MintInfo".as_ref(),
|
||||
account.fixed.group.as_ref(),
|
||||
mint.as_ref(),
|
||||
],
|
||||
&mango_v4::id(),
|
||||
|
@ -145,8 +145,8 @@ async fn get_mint_info_by_token_index(
|
|||
) -> MintInfo {
|
||||
let bank_pk = Pubkey::find_program_address(
|
||||
&[
|
||||
account.fixed.group.as_ref(),
|
||||
b"Bank".as_ref(),
|
||||
account.fixed.group.as_ref(),
|
||||
&token_index.to_le_bytes(),
|
||||
&0u32.to_le_bytes(),
|
||||
],
|
||||
|
@ -160,8 +160,8 @@ async fn get_mint_info_by_token_index(
|
|||
fn get_perp_market_address_by_index(group: Pubkey, perp_market_index: PerpMarketIndex) -> Pubkey {
|
||||
Pubkey::find_program_address(
|
||||
&[
|
||||
group.as_ref(),
|
||||
b"PerpMarket".as_ref(),
|
||||
group.as_ref(),
|
||||
&perp_market_index.to_le_bytes(),
|
||||
],
|
||||
&mango_v4::id(),
|
||||
|
@ -466,8 +466,8 @@ impl<'keypair> ClientInstruction for TokenWithdrawInstruction<'keypair> {
|
|||
.unwrap();
|
||||
let mint_info = Pubkey::find_program_address(
|
||||
&[
|
||||
account.fixed.group.as_ref(),
|
||||
b"MintInfo".as_ref(),
|
||||
account.fixed.group.as_ref(),
|
||||
token_account.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -534,8 +534,8 @@ impl ClientInstruction for TokenDepositInstruction {
|
|||
.unwrap();
|
||||
let mint_info = Pubkey::find_program_address(
|
||||
&[
|
||||
account.fixed.group.as_ref(),
|
||||
b"MintInfo".as_ref(),
|
||||
account.fixed.group.as_ref(),
|
||||
token_account.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -633,8 +633,8 @@ impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
|
|||
|
||||
let bank = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Bank".as_ref(),
|
||||
self.group.as_ref(),
|
||||
&self.token_index.to_le_bytes(),
|
||||
&0u32.to_le_bytes(),
|
||||
],
|
||||
|
@ -643,8 +643,8 @@ impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
|
|||
.0;
|
||||
let vault = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Vault".as_ref(),
|
||||
self.group.as_ref(),
|
||||
&self.token_index.to_le_bytes(),
|
||||
&0u32.to_le_bytes(),
|
||||
],
|
||||
|
@ -653,8 +653,8 @@ impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
|
|||
.0;
|
||||
let mint_info = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"MintInfo".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -663,8 +663,8 @@ impl<'keypair> ClientInstruction for TokenRegisterInstruction<'keypair> {
|
|||
// TODO: remove copy pasta of pda derivation, use reference
|
||||
let oracle = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"StubOracle".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -718,8 +718,8 @@ impl<'keypair> ClientInstruction for TokenAddBankInstruction<'keypair> {
|
|||
|
||||
let existing_bank = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Bank".as_ref(),
|
||||
self.group.as_ref(),
|
||||
&self.token_index.to_le_bytes(),
|
||||
&0u32.to_le_bytes(),
|
||||
],
|
||||
|
@ -728,8 +728,8 @@ impl<'keypair> ClientInstruction for TokenAddBankInstruction<'keypair> {
|
|||
.0;
|
||||
let bank = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Bank".as_ref(),
|
||||
self.group.as_ref(),
|
||||
&self.token_index.to_le_bytes(),
|
||||
&self.bank_num.to_le_bytes(),
|
||||
],
|
||||
|
@ -738,8 +738,8 @@ impl<'keypair> ClientInstruction for TokenAddBankInstruction<'keypair> {
|
|||
.0;
|
||||
let vault = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Vault".as_ref(),
|
||||
self.group.as_ref(),
|
||||
&self.token_index.to_le_bytes(),
|
||||
&self.bank_num.to_le_bytes(),
|
||||
],
|
||||
|
@ -751,7 +751,7 @@ impl<'keypair> ClientInstruction for TokenAddBankInstruction<'keypair> {
|
|||
let mint = existing_bank_data.mint;
|
||||
|
||||
let mint_info = Pubkey::find_program_address(
|
||||
&[self.group.as_ref(), b"MintInfo".as_ref(), mint.as_ref()],
|
||||
&[b"MintInfo".as_ref(), self.group.as_ref(), mint.as_ref()],
|
||||
&program_id,
|
||||
)
|
||||
.0;
|
||||
|
@ -869,8 +869,8 @@ impl<'keypair> ClientInstruction for StubOracleSetInstruction<'keypair> {
|
|||
// TODO: remove copy pasta of pda derivation, use reference
|
||||
let oracle = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"StubOracle".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -915,8 +915,8 @@ impl<'keypair> ClientInstruction for StubOracleCreate<'keypair> {
|
|||
|
||||
let oracle = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"StubOracle".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -961,8 +961,8 @@ impl<'keypair> ClientInstruction for StubOracleCloseInstruction<'keypair> {
|
|||
|
||||
let oracle = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"StubOracle".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -1017,7 +1017,7 @@ impl<'keypair> ClientInstruction for GroupCreateInstruction<'keypair> {
|
|||
.0;
|
||||
|
||||
let insurance_vault = Pubkey::find_program_address(
|
||||
&[group.as_ref(), b"InsuranceVault".as_ref()],
|
||||
&[b"InsuranceVault".as_ref(), group.as_ref()],
|
||||
&program_id,
|
||||
)
|
||||
.0;
|
||||
|
@ -1059,7 +1059,7 @@ impl<'keypair> ClientInstruction for GroupCloseInstruction<'keypair> {
|
|||
let instruction = Self::Instruction {};
|
||||
|
||||
let insurance_vault = Pubkey::find_program_address(
|
||||
&[self.group.as_ref(), b"InsuranceVault".as_ref()],
|
||||
&[b"InsuranceVault".as_ref(), self.group.as_ref()],
|
||||
&program_id,
|
||||
)
|
||||
.0;
|
||||
|
@ -1111,8 +1111,8 @@ impl<'keypair> ClientInstruction for AccountCreateInstruction<'keypair> {
|
|||
|
||||
let account = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.owner.pubkey().as_ref(),
|
||||
&self.account_num.to_le_bytes(),
|
||||
],
|
||||
|
@ -1165,8 +1165,8 @@ impl<'keypair> ClientInstruction for AccountExpandInstruction<'keypair> {
|
|||
|
||||
let account = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.owner.pubkey().as_ref(),
|
||||
&self.account_num.to_le_bytes(),
|
||||
],
|
||||
|
@ -1214,8 +1214,8 @@ impl<'keypair> ClientInstruction for AccountEditInstruction<'keypair> {
|
|||
|
||||
let account = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.owner.pubkey().as_ref(),
|
||||
&self.account_num.to_le_bytes(),
|
||||
],
|
||||
|
@ -1301,8 +1301,8 @@ impl<'keypair> ClientInstruction for Serum3RegisterMarketInstruction<'keypair> {
|
|||
|
||||
let serum_market = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Serum3Market".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.serum_market_external.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -1349,8 +1349,8 @@ impl<'keypair> ClientInstruction for Serum3DeregisterMarketInstruction<'keypair>
|
|||
|
||||
let serum_market = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"Serum3Market".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.serum_market_external.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -1395,8 +1395,8 @@ impl<'keypair> ClientInstruction for Serum3CreateOpenOrdersInstruction<'keypair>
|
|||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = Pubkey::find_program_address(
|
||||
&[
|
||||
self.account.as_ref(),
|
||||
b"Serum3OO".as_ref(),
|
||||
self.account.as_ref(),
|
||||
self.serum_market.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -1446,8 +1446,8 @@ impl<'keypair> ClientInstruction for Serum3CloseOpenOrdersInstruction<'keypair>
|
|||
let serum_market: Serum3Market = account_loader.load(&self.serum_market).await.unwrap();
|
||||
let open_orders = Pubkey::find_program_address(
|
||||
&[
|
||||
self.account.as_ref(),
|
||||
b"Serum3OO".as_ref(),
|
||||
self.account.as_ref(),
|
||||
self.serum_market.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -1996,8 +1996,8 @@ impl<'keypair> ClientInstruction for LiqTokenBankruptcyInstruction<'keypair> {
|
|||
|
||||
let quote_mint_info = Pubkey::find_program_address(
|
||||
&[
|
||||
liqee.fixed.group.as_ref(),
|
||||
b"MintInfo".as_ref(),
|
||||
liqee.fixed.group.as_ref(),
|
||||
group.insurance_mint.as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
@ -2006,7 +2006,7 @@ impl<'keypair> ClientInstruction for LiqTokenBankruptcyInstruction<'keypair> {
|
|||
let quote_mint_info: MintInfo = account_loader.load("e_mint_info).await.unwrap();
|
||||
|
||||
let insurance_vault = Pubkey::find_program_address(
|
||||
&[group_key.as_ref(), b"InsuranceVault".as_ref()],
|
||||
&[b"InsuranceVault".as_ref(), group_key.as_ref()],
|
||||
&program_id,
|
||||
)
|
||||
.0;
|
||||
|
@ -2097,8 +2097,8 @@ impl<'keypair> ClientInstruction for PerpCreateMarketInstruction<'keypair> {
|
|||
|
||||
let perp_market = Pubkey::find_program_address(
|
||||
&[
|
||||
self.group.as_ref(),
|
||||
b"PerpMarket".as_ref(),
|
||||
self.group.as_ref(),
|
||||
self.perp_market_index.to_le_bytes().as_ref(),
|
||||
],
|
||||
&program_id,
|
||||
|
|
|
@ -26,6 +26,7 @@ export class Bank {
|
|||
public util0: I80F48;
|
||||
public util1: I80F48;
|
||||
public price: I80F48;
|
||||
public collectedFeesNative: I80F48;
|
||||
public loanFeeRate: I80F48;
|
||||
public loanOriginationFeeRate: I80F48;
|
||||
public initAssetWeight: I80F48;
|
||||
|
@ -166,6 +167,7 @@ export class Bank {
|
|||
this.rate0 = I80F48.from(rate0);
|
||||
this.util1 = I80F48.from(util1);
|
||||
this.rate1 = I80F48.from(rate1);
|
||||
this.collectedFeesNative = I80F48.from(collectedFeesNative);
|
||||
this.loanFeeRate = I80F48.from(loanFeeRate);
|
||||
this.loanOriginationFeeRate = I80F48.from(loanOriginationFeeRate);
|
||||
this.maintAssetWeight = I80F48.from(maintAssetWeight);
|
||||
|
|
|
@ -104,11 +104,18 @@ export class MangoClient {
|
|||
|
||||
public async groupEdit(
|
||||
group: Group,
|
||||
newAdmin: PublicKey,
|
||||
newFastListingAdmin: PublicKey,
|
||||
admin: PublicKey | undefined,
|
||||
fastListingAdmin: PublicKey | undefined,
|
||||
testing: number | undefined,
|
||||
version: number | undefined,
|
||||
): Promise<TransactionSignature> {
|
||||
return await this.program.methods
|
||||
.groupEdit(newAdmin, newFastListingAdmin)
|
||||
.groupEdit(
|
||||
admin ?? null,
|
||||
fastListingAdmin ?? null,
|
||||
testing ?? null,
|
||||
version ?? null,
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
|
@ -605,6 +612,21 @@ export class MangoClient {
|
|||
});
|
||||
}
|
||||
|
||||
public async getAllMangoAccounts(group: Group): Promise<MangoAccount[]> {
|
||||
return (
|
||||
await this.program.account.mangoAccount.all([
|
||||
{
|
||||
memcmp: {
|
||||
bytes: group.publicKey.toBase58(),
|
||||
offset: 8,
|
||||
},
|
||||
},
|
||||
])
|
||||
).map((pa) => {
|
||||
return MangoAccount.from(pa.publicKey, pa.account);
|
||||
});
|
||||
}
|
||||
|
||||
public async closeMangoAccount(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||
import { coder } from '@project-serum/anchor/dist/cjs/spl/token';
|
||||
import { Connection, Keypair } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { ZERO_I80F48 } from '../accounts/I80F48';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
|
||||
async function main() {
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(process.env.MB_CLUSTER_URL!, options);
|
||||
|
||||
const admin = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.MB_PAYER_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
|
||||
const adminWallet = new Wallet(admin);
|
||||
const adminProvider = new AnchorProvider(connection, adminWallet, options);
|
||||
const client = MangoClient.connect(
|
||||
adminProvider,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
);
|
||||
|
||||
const group = await client.getGroupForCreator(admin.publicKey, 0);
|
||||
console.log(`Group ${group.publicKey.toBase58()}`);
|
||||
|
||||
const banks = await client.getBanksForGroup(group);
|
||||
const banksMapUsingTokenIndex = new Map(
|
||||
banks.map((bank) => {
|
||||
(bank as any).indexedDepositsByMangoAccounts = ZERO_I80F48;
|
||||
(bank as any).indexedBorrowsByMangoAccounts = ZERO_I80F48;
|
||||
return [bank.tokenIndex, bank];
|
||||
}),
|
||||
);
|
||||
|
||||
const mangoAccounts = await client.getAllMangoAccounts(group);
|
||||
mangoAccounts.forEach((mangoAccount) =>
|
||||
console.log(
|
||||
`MangoAccount pk - ${mangoAccount.publicKey}, owner - ${mangoAccount.owner}`,
|
||||
),
|
||||
);
|
||||
mangoAccounts.map((mangoAccount) =>
|
||||
mangoAccount.tokensActive().forEach((token) => {
|
||||
const bank = banksMapUsingTokenIndex.get(token.tokenIndex);
|
||||
if (token.indexedPosition.isPos()) {
|
||||
(bank as any).indexedDepositsByMangoAccounts = (
|
||||
bank as any
|
||||
).indexedDepositsByMangoAccounts.add(
|
||||
token.indexedPosition.mul(
|
||||
banksMapUsingTokenIndex.get(token.tokenIndex).depositIndex,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (token.indexedPosition.isNeg()) {
|
||||
(bank as any).indexedBorrowsByMangoAccounts = (
|
||||
bank as any
|
||||
).indexedBorrowsByMangoAccounts.add(
|
||||
token.indexedPosition
|
||||
.abs()
|
||||
.mul(banksMapUsingTokenIndex.get(token.tokenIndex).borrowIndex),
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
for (const bank of await Array.from(banksMapUsingTokenIndex.values()).sort(
|
||||
(a, b) => a.tokenIndex - b.tokenIndex,
|
||||
)) {
|
||||
let res = `${bank.name}`;
|
||||
res =
|
||||
res +
|
||||
`\n ${'collectedFeesNative'.padEnd(40)} ${bank.collectedFeesNative}` +
|
||||
`\n ${'deposits'.padEnd(40)} ${bank.indexedDeposits.mul(
|
||||
bank.depositIndex,
|
||||
)}` +
|
||||
`\n ${'deposits (sum over all mango accounts)'.padEnd(40)} ${
|
||||
(bank as any).indexedDepositsByMangoAccounts
|
||||
}` +
|
||||
`\n ${'cachedIndexedTotalDeposits'.padEnd(40)} ${(
|
||||
bank as any
|
||||
).cachedIndexedTotalDeposits.mul(bank.depositIndex)}` +
|
||||
`\n ${'indexedBorrows'.padEnd(40)} ${bank.indexedBorrows.mul(
|
||||
bank.borrowIndex,
|
||||
)}` +
|
||||
`\n ${'borrows (sum over all mango accounts)'.padEnd(40)} ${
|
||||
(bank as any).indexedBorrowsByMangoAccounts
|
||||
}` +
|
||||
`\n ${'cachedIndexedTotalBorrows'.padEnd(40)} ${(
|
||||
bank as any
|
||||
).cachedIndexedTotalBorrows.mul(bank.borrowIndex)}` +
|
||||
`\n ${'avgUtilization'.padEnd(40)} ${bank.avgUtilization}` +
|
||||
`\n ${'depositRate'.padEnd(40)} ${bank.getDepositRate()}` +
|
||||
`\n ${'borrowRate'.padEnd(40)} ${bank.getBorrowRate()}` +
|
||||
`\n ${'vault'.padEnd(40)} ${coder()
|
||||
.accounts.decode(
|
||||
'token',
|
||||
await (
|
||||
await client.program.provider.connection.getAccountInfo(bank.vault)
|
||||
).data,
|
||||
)
|
||||
.amount.toNumber()}`;
|
||||
|
||||
console.log(`${res}`);
|
||||
}
|
||||
|
||||
process.exit();
|
||||
}
|
||||
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
|
@ -45,15 +45,15 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "InsuranceVault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -110,12 +110,28 @@ export type MangoV4 = {
|
|||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "newAdmin",
|
||||
"type": "publicKey"
|
||||
"name": "adminOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newFastListingAdmin",
|
||||
"type": "publicKey"
|
||||
"name": "fastListingAdminOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "testingOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "versionOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -174,16 +190,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -203,16 +219,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -232,16 +248,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -352,16 +368,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -381,16 +397,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -410,16 +426,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -591,16 +607,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -620,16 +636,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -646,27 +662,7 @@ export type MangoV4 = {
|
|||
{
|
||||
"name": "mintInfo",
|
||||
"isMut": true,
|
||||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"account": "Mint",
|
||||
"path": "mint"
|
||||
}
|
||||
]
|
||||
}
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
|
@ -781,16 +777,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MangoAccount"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -974,16 +970,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "StubOracle"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -1269,16 +1265,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Serum3Market"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -1389,16 +1385,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "account"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Serum3OO"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "account"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -2049,16 +2045,16 @@ export type MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "PerpMarket"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -4011,18 +4007,14 @@ export type MangoV4 = {
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "baseEntryLots",
|
||||
"name": "quoteEntryNative",
|
||||
"docs": [
|
||||
"Tracks what the position is to calculate average entry & break even price"
|
||||
],
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "quoteEntryNative",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "quoteExitNative",
|
||||
"name": "quoteRunningNative",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
|
@ -5089,15 +5081,15 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "InsuranceVault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -5154,12 +5146,28 @@ export const IDL: MangoV4 = {
|
|||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "newAdmin",
|
||||
"type": "publicKey"
|
||||
"name": "adminOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newFastListingAdmin",
|
||||
"type": "publicKey"
|
||||
"name": "fastListingAdminOpt",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "testingOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "versionOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -5218,16 +5226,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5247,16 +5255,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5276,16 +5284,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -5396,16 +5404,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5425,16 +5433,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5454,16 +5462,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -5635,16 +5643,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Bank"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5664,16 +5672,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Vault"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -5690,27 +5698,7 @@ export const IDL: MangoV4 = {
|
|||
{
|
||||
"name": "mintInfo",
|
||||
"isMut": true,
|
||||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MintInfo"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"account": "Mint",
|
||||
"path": "mint"
|
||||
}
|
||||
]
|
||||
}
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "payer",
|
||||
|
@ -5825,16 +5813,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "MangoAccount"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -6018,16 +6006,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "StubOracle"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -6313,16 +6301,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Serum3Market"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -6433,16 +6421,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "account"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "Serum3OO"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "account"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
|
@ -7093,16 +7081,16 @@ export const IDL: MangoV4 = {
|
|||
"isSigner": false,
|
||||
"pda": {
|
||||
"seeds": [
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "const",
|
||||
"type": "string",
|
||||
"value": "PerpMarket"
|
||||
},
|
||||
{
|
||||
"kind": "account",
|
||||
"type": "publicKey",
|
||||
"path": "group"
|
||||
},
|
||||
{
|
||||
"kind": "arg",
|
||||
"type": "u16",
|
||||
|
@ -9055,18 +9043,14 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "baseEntryLots",
|
||||
"name": "quoteEntryNative",
|
||||
"docs": [
|
||||
"Tracks what the position is to calculate average entry & break even price"
|
||||
],
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "quoteEntryNative",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "quoteExitNative",
|
||||
"name": "quoteRunningNative",
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -204,6 +204,8 @@ async function main() {
|
|||
group,
|
||||
group.admin,
|
||||
new PublicKey('Efhak3qj3MiyzgJr3cUUqXXz5wr3oYHt9sPzuqJf9eBN'),
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
console.log(`sig https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
console.log(`Registering MNGO...`);
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from '../accounts/serum3';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
import { toUiDecimalsForQuote } from '../utils';
|
||||
|
||||
//
|
||||
// An example for users based on high level api i.e. the client
|
||||
|
@ -240,11 +241,15 @@ async function main() {
|
|||
);
|
||||
console.log(
|
||||
'...mangoAccount.getAssetsVal() ' +
|
||||
toUiDecimalsForQuote(mangoAccount.getAssetsVal().toNumber()),
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getAssetsVal(HealthType.init).toNumber(),
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
'...mangoAccount.getLiabsVal() ' +
|
||||
toUiDecimalsForQuote(mangoAccount.getLiabsVal().toNumber()),
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getLiabsVal(HealthType.init).toNumber(),
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
'...mangoAccount.getMaxWithdrawWithBorrowForToken(group, "SOL") ' +
|
||||
|
|
|
@ -209,7 +209,7 @@ async function main() {
|
|||
);
|
||||
|
||||
console.log(`Registering MNGO...`);
|
||||
await client.groupEdit(group, group.admin, group.admin);
|
||||
await client.groupEdit(group, group.admin, group.admin, undefined, undefined);
|
||||
const mngoMainnetMint = new PublicKey(MAINNET_MINTS.get('MNGO')!);
|
||||
const mngoMainnetOracle = new PublicKey(MAINNET_ORACLES.get('MNGO')!);
|
||||
await client.tokenRegisterTrustless(
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Connection, Keypair } from '@solana/web3.js';
|
|||
import fs from 'fs';
|
||||
import { Serum3Side } from '../accounts/serum3';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
|
||||
//
|
||||
// (untested?) script which closes a mango account cleanly, first closes all positions, withdraws all tokens and then closes it
|
||||
|
@ -14,14 +15,15 @@ async function main() {
|
|||
// user
|
||||
const user = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.MB_PAYER_KEYPAIR!, 'utf-8')),
|
||||
JSON.parse(fs.readFileSync(process.env.USER_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
const userWallet = new Wallet(user);
|
||||
const userProvider = new AnchorProvider(connection, userWallet, options);
|
||||
const client = await MangoClient.connectForGroupName(
|
||||
const client = await MangoClient.connect(
|
||||
userProvider,
|
||||
'mainnet-beta.microwavedcola' /* Use ids json instead of getProgramAccounts */,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
);
|
||||
console.log(`User ${userWallet.publicKey.toBase58()}`);
|
||||
|
||||
|
@ -34,7 +36,7 @@ async function main() {
|
|||
console.log(`Admin ${admin.publicKey.toBase58()}`);
|
||||
|
||||
// fetch group
|
||||
const group = await client.getGroupForCreator(admin.publicKey);
|
||||
const group = await client.getGroupForCreator(admin.publicKey, 0);
|
||||
console.log(`Found group ${group.publicKey.toBase58()}`);
|
||||
|
||||
// account
|
||||
|
|
Loading…
Reference in New Issue