Skip to content

Commit

Permalink
Boilerplate to init staked banks with group-level default settings
Browse files Browse the repository at this point in the history
  • Loading branch information
jgur-psyops committed Oct 29, 2024
1 parent 414f18a commit 16c98f5
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
// Adds a ASSET_TAG_STAKED type bank to a group with sane defaults. Used by validators to add their
// freshly-minted LST to a group so users can borrow SOL against it

// TODO should we support this for riskTier::Isolated too?

// TODO pick a hardcoded oracle

// TODO pick a hardcoded interest regmine

// TODO pick a hardcoded asset weight (~85%?) and `total_asset_value_init_limit`

// TODO pick a hardcoded max oracle age (~30s?)

// TODO pick a hardcoded initial deposit limit () //

// TODO should the group admin need to opt in to this functionality (configure the group)? We could
// also configure the key that assumes default admin here instead of using the group's admin
// stake pool to a group so users can borrow SOL against it
use crate::{
check,
constants::{
ASSET_TAG_STAKED, FEE_VAULT_AUTHORITY_SEED, FEE_VAULT_SEED, INSURANCE_VAULT_AUTHORITY_SEED,
INSURANCE_VAULT_SEED, LIQUIDITY_VAULT_AUTHORITY_SEED, LIQUIDITY_VAULT_SEED,
NATIVE_STAKE_ID, SPL_SINGLE_POOL_ID, STAKED_SETTINGS_SEED,
NATIVE_STAKE_ID, SPL_SINGLE_POOL_ID,
},
events::{GroupEventHeader, LendingPoolBankCreateEvent},
state::{
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,63 @@
// TODO
// Used by the group admin to edit the default features of staked collateral banks. Remember to
// propagate afterwards.
use crate::state::marginfi_group::{RiskTier, WrappedI80F48};
use crate::state::staked_settings::StakedSettings;
use crate::{set_if_some, MarginfiGroup};
use anchor_lang::prelude::*;

pub fn edit_staked_settings(
ctx: Context<EditStakedSettings>,
settings: StakedSettingsEditConfig,
) -> Result<()> {
let mut staked_settings = ctx.accounts.staked_settings.load_mut()?;

set_if_some!(staked_settings.oracle, settings.oracle);
set_if_some!(
staked_settings.asset_weight_init,
settings.asset_weight_init
);
set_if_some!(
staked_settings.asset_weight_maint,
settings.asset_weight_maint
);
set_if_some!(staked_settings.deposit_limit, settings.deposit_limit);
set_if_some!(
staked_settings.total_asset_value_init_limit,
settings.total_asset_value_init_limit
);
set_if_some!(staked_settings.oracle_max_age, settings.oracle_max_age);
set_if_some!(staked_settings.risk_tier, settings.risk_tier);

Ok(())
}

#[derive(Accounts)]
pub struct EditStakedSettings<'info> {
#[account(
has_one = admin
)]
pub marginfi_group: AccountLoader<'info, MarginfiGroup>,

#[account(mut)]
pub admin: Signer<'info>,

#[account(
mut,
has_one = marginfi_group
)]
pub staked_settings: AccountLoader<'info, StakedSettings>,
}

#[derive(AnchorDeserialize, AnchorSerialize, Default)]
pub struct StakedSettingsEditConfig {
pub oracle: Option<Pubkey>,

pub asset_weight_init: Option<WrappedI80F48>,
pub asset_weight_maint: Option<WrappedI80F48>,

pub deposit_limit: Option<u64>,
pub total_asset_value_init_limit: Option<u64>,

pub oracle_max_age: Option<u16>,
pub risk_tier: Option<RiskTier>,
}
Original file line number Diff line number Diff line change
@@ -1 +1,71 @@
// TODO
// Used by the group admin to enable staked collateral banks and configure their default features
use crate::constants::STAKED_SETTINGS_SEED;
use crate::state::marginfi_group::{RiskTier, WrappedI80F48};
use crate::state::staked_settings::StakedSettings;
use crate::MarginfiGroup;
use anchor_lang::prelude::*;

pub fn initialize_staked_settings(
ctx: Context<InitStakedSettings>,
settings: StakedSettingsConfig,
) -> Result<()> {
let mut staked_settings = ctx.accounts.staked_settings.load_init()?;

*staked_settings = StakedSettings::new(
ctx.accounts.staked_settings.key(),
ctx.accounts.marginfi_group.key(),
settings.oracle,
settings.asset_weight_init,
settings.asset_weight_maint,
settings.deposit_limit,
settings.total_asset_value_init_limit,
settings.oracle_max_age,
settings.risk_tier,
);

Ok(())
}

#[derive(Accounts)]
pub struct InitStakedSettings<'info> {
#[account(
has_one = admin
)]
pub marginfi_group: AccountLoader<'info, MarginfiGroup>,

#[account(mut)]
pub admin: Signer<'info>,

/// Pays the init fee
#[account(mut)]
pub fee_payer: Signer<'info>,

#[account(
init,
seeds = [
marginfi_group.key().as_ref(),
STAKED_SETTINGS_SEED.as_bytes()
],
bump,
payer = fee_payer,
space = 8 + StakedSettings::LEN,
)]
pub staked_settings: AccountLoader<'info, StakedSettings>,

pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}

#[derive(AnchorDeserialize, AnchorSerialize, Default)]
pub struct StakedSettingsConfig {
pub oracle: Pubkey,

pub asset_weight_init: WrappedI80F48,
pub asset_weight_maint: WrappedI80F48,

pub deposit_limit: u64,
pub total_asset_value_init_limit: u64,

pub oracle_max_age: u16,
pub risk_tier: RiskTier,
}
6 changes: 6 additions & 0 deletions programs/marginfi/src/instructions/marginfi_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ mod config_group_fee;
mod configure;
mod configure_bank;
mod edit_global_fee;
mod edit_stake_settings;
mod handle_bankruptcy;
mod init_global_fee_state;
mod init_staked_settings;
mod initialize;
mod propagate_fee_state;
mod propagate_staked_settings;

pub use accrue_bank_interest::*;
pub use add_pool::*;
Expand All @@ -23,7 +26,10 @@ pub use config_group_fee::*;
pub use configure::*;
pub use configure_bank::*;
pub use edit_global_fee::*;
pub use edit_stake_settings::*;
pub use handle_bankruptcy::*;
pub use init_global_fee_state::*;
pub use init_staked_settings::*;
pub use initialize::*;
pub use propagate_fee_state::*;
pub use propagate_staked_settings::*;
Original file line number Diff line number Diff line change
@@ -1 +1,36 @@
// TODO
// Permissionless ix to propagate a group's staked collateral settings to any bank in that group
use crate::state::marginfi_group::Bank;
use crate::state::staked_settings::StakedSettings;
use crate::MarginfiGroup;
use anchor_lang::prelude::*;

pub fn propagate_staked_settings(ctx: Context<PropagateStakedSettings>) -> Result<()> {
let settings = ctx.accounts.staked_settings.load()?;
let mut bank = ctx.accounts.bank.load_mut()?;

bank.config.oracle_keys[0] = settings.oracle;
bank.config.asset_weight_init = settings.asset_weight_init;
bank.config.asset_weight_maint = settings.asset_weight_maint;
bank.config.deposit_limit = settings.deposit_limit;
bank.config.total_asset_value_init_limit = settings.total_asset_value_init_limit;
bank.config.oracle_max_age = settings.oracle_max_age;
bank.config.risk_tier = settings.risk_tier;

Ok(())
}

#[derive(Accounts)]
pub struct PropagateStakedSettings<'info> {
pub marginfi_group: AccountLoader<'info, MarginfiGroup>,

#[account(
has_one = marginfi_group
)]
pub staked_settings: AccountLoader<'info, StakedSettings>,

#[account(
mut,
constraint = bank.load() ?.group == marginfi_group.key(),
)]
pub bank: AccountLoader<'info, Bank>,
}
24 changes: 24 additions & 0 deletions programs/marginfi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,30 @@ pub mod marginfi {
pub fn config_group_fee(ctx: Context<ConfigGroupFee>, flag: u64) -> MarginfiResult {
marginfi_group::config_group_fee(ctx, flag)
}

/// (group admin only) Init the Staked Settings account, which is used to create staked
/// collateral banks, and must run before any staked collateral bank can be created with
/// `add_pool_permissionless`. Running this ix effectively opts the group into the staked
/// collateral feature.
pub fn init_staked_settings(
ctx: Context<InitStakedSettings>,
settings: StakedSettingsConfig,
) -> MarginfiResult {
marginfi_group::initialize_staked_settings(ctx, settings)
}

pub fn edit_staked_settings(
ctx: Context<EditStakedSettings>,
settings: StakedSettingsEditConfig,
) -> MarginfiResult {
marginfi_group::edit_staked_settings(ctx, settings)
}

pub fn propagate_staked_settings(
ctx: Context<PropagateStakedSettings>,
) -> MarginfiResult {
marginfi_group::propagate_staked_settings(ctx)
}
}

#[cfg(not(feature = "no-entrypoint"))]
Expand Down
5 changes: 5 additions & 0 deletions programs/marginfi/src/state/marginfi_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,11 @@ pub enum RiskTier {

unsafe impl Zeroable for RiskTier {}
unsafe impl Pod for RiskTier {}
impl Default for RiskTier {
fn default() -> Self {
RiskTier::Collateral
}
}

#[repr(C)]
#[cfg_attr(
Expand Down
55 changes: 51 additions & 4 deletions programs/marginfi/src/state/staked_settings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anchor_lang::prelude::*;
use fixed_macro::types::I80F48;

use crate::{assert_struct_align, assert_struct_size};

Expand All @@ -8,14 +9,14 @@ assert_struct_size!(StakedSettings, 256);
assert_struct_align!(StakedSettings, 8);

/// Unique per-group. Staked Collateral banks created under a group automatically use these
/// settings. Groups that have not created this struct cannot use staked collateral positions. When
/// settings. Groups that have not created this struct cannot create staked collateral banks. When
/// this struct updates, changes must be permissionlessly propogated to staked collateral banks.
/// Administrators can also edit the bank manually, i.e. with configure_bank, to temporarily make
/// changes such as raising the deposit limit for a single bank.
#[account(zero_copy)]
#[repr(C)]
pub struct StakedSettings {
/// This account's own key. A PDA derived from `marginfi_group` and `b"staked_settings"`
/// This account's own key. A PDA derived from `marginfi_group` and `STAKED_SETTINGS_SEED`
pub key: Pubkey,
/// Group for which these settings apply
pub marginfi_group: Pubkey,
Expand All @@ -36,9 +37,8 @@ pub struct StakedSettings {
/// borrowing.
// * interest_config,
// * liability_weight_init
// * liability_weight_maint
// * liability_weight_maint
// * borrow_limit

_reserved0: [u8; 8],
_reserved1: [u8; 32],
_reserved2: [u8; 64],
Expand All @@ -47,3 +47,50 @@ pub struct StakedSettings {
impl StakedSettings {
pub const LEN: usize = std::mem::size_of::<StakedSettings>();
}

impl StakedSettings {
pub fn new(
key: Pubkey,
marginfi_group: Pubkey,
oracle: Pubkey,
asset_weight_init: WrappedI80F48,
asset_weight_maint: WrappedI80F48,
deposit_limit: u64,
total_asset_value_init_limit: u64,
oracle_max_age: u16,
risk_tier: RiskTier,
) -> Self {
StakedSettings {
key,
marginfi_group,
oracle,
asset_weight_init,
asset_weight_maint,
deposit_limit,
total_asset_value_init_limit,
oracle_max_age,
risk_tier,
..Default::default()
}
}
}

impl Default for StakedSettings {
fn default() -> Self {
StakedSettings {
key: Pubkey::default(),
marginfi_group: Pubkey::default(),
oracle: Pubkey::default(),
asset_weight_init: I80F48!(0.8).into(),
asset_weight_maint: I80F48!(0.9).into(),
deposit_limit: 1_000_000,
total_asset_value_init_limit: 1_000_000,
oracle_max_age: 10,
risk_tier: RiskTier::Collateral,
_pad0: [0; 5],
_reserved0: [0; 8],
_reserved1: [0; 32],
_reserved2: [0; 64],
}
}
}

0 comments on commit 16c98f5

Please sign in to comment.