Skip to content

Commit

Permalink
Marinade LP: implement extract yield and update epoch record
Browse files Browse the repository at this point in the history
  • Loading branch information
dankelleher committed Feb 12, 2024
1 parent b789822 commit 4dcdb89
Show file tree
Hide file tree
Showing 26 changed files with 846 additions and 199 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions lib/marinade-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "marinade-common"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anchor-lang = '0.29.0'
marinade-cpi = { git = "https://github.com/sunrise-stake/anchor-gen", branch = "update/anchor-v0.29" }
73 changes: 73 additions & 0 deletions lib/marinade-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
pub mod vault_authority_seed;

use anchor_lang::prelude::*;
use marinade_cpi::state::State as MarinadeState;
use std::num::TryFromIntError;

/// calculate amount*numerator/denominator
/// as value = shares * share_price where share_price=total_value/total_shares
/// or shares = amount_value / share_price where share_price=total_value/total_shares
/// => shares = amount_value * 1/share_price where 1/share_price=total_shares/total_value
pub fn proportional(
amount: u64,
numerator: u64,
denominator: u64,
) -> std::result::Result<u64, TryFromIntError> {
if denominator == 0 {
return Ok(amount);
}
u64::try_from((amount as u128) * (numerator as u128) / (denominator as u128))
}

// All lifted from https://github.com/marinade-finance/liquid-staking-program/blob/447f9607a8c755cac7ad63223febf047142c6c8f/programs/marinade-finance/src/state.rs#L227
pub fn calc_msol_from_lamports(
marinade_state: &MarinadeState,
stake_lamports: u64,
) -> std::result::Result<u64, TryFromIntError> {
msg!("calc_msol_from_lamports");
msg!("stake_lamports: {}", stake_lamports);
msg!("marinade_state.msol_supply: {}", marinade_state.msol_supply);
msg!(
"total_virtual_staked_lamports: {}",
total_virtual_staked_lamports(marinade_state)
);
proportional(
stake_lamports,
marinade_state.msol_supply,
total_virtual_staked_lamports(marinade_state),
)
}
pub fn calc_lamports_from_msol_amount(
marinade_state: &MarinadeState,
msol_amount: u64,
) -> std::result::Result<u64, TryFromIntError> {
proportional(
msol_amount,
total_virtual_staked_lamports(marinade_state),
marinade_state.msol_supply,
)
}

fn total_cooling_down(marinade_state: &MarinadeState) -> u64 {
marinade_state
.stake_system
.delayed_unstake_cooling_down
.checked_add(marinade_state.emergency_cooling_down)
.expect("Total cooling down overflow")
}

fn total_lamports_under_control(marinade_state: &MarinadeState) -> u64 {
marinade_state
.validator_system
.total_active_balance
.checked_add(total_cooling_down(marinade_state))
.expect("Stake balance overflow")
.checked_add(marinade_state.available_reserve_balance) // reserve_pda.lamports() - self.rent_exempt_for_token_acc
.expect("Total SOLs under control overflow")
}

fn total_virtual_staked_lamports(marinade_state: &MarinadeState) -> u64 {
// if we get slashed it may be negative but we must use 0 instead
total_lamports_under_control(marinade_state)
.saturating_sub(marinade_state.circulating_ticket_balance) //tickets created -> cooling down lamports or lamports already in reserve and not claimed yet
}
33 changes: 33 additions & 0 deletions lib/marinade-common/src/vault_authority_seed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use anchor_lang::prelude::{Account, Key};
use anchor_lang::{AccountDeserialize, AccountSerialize};

// NOTE: this must match the constant used by the programs themselves
const VAULT_AUTHORITY: &[u8] = b"vault-authority";

pub struct VaultAuthoritySeed<'a> {
state_address: Vec<u8>,
vault_authority: &'a [u8],
bump: Vec<u8>,
}

pub trait HasVaultAuthority: AccountSerialize + AccountDeserialize + Clone {
fn vault_authority_bump(&self) -> u8;
}

impl<'a> VaultAuthoritySeed<'a> {
pub fn new<'info>(state: &'a Account<'info, impl HasVaultAuthority>) -> Self {
let state_address = state.key().to_bytes().to_vec();
let vault_authority = VAULT_AUTHORITY;
let bump = vec![state.vault_authority_bump()];

VaultAuthoritySeed {
state_address,
vault_authority,
bump,
}
}

pub fn as_slices(&self) -> [&[u8]; 3] {
[&self.state_address, self.vault_authority, &self.bump]
}
}
Loading

0 comments on commit 4dcdb89

Please sign in to comment.