Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Epoch report refactor #13

Merged
merged 8 commits into from
Feb 29, 2024
3 changes: 3 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ wallet = "packages/tests/fixtures/provider.json"
[scripts]
test = "packages/tests/run.sh"

[test]
startup_wait = 3000

[test.validator]
slots_per_epoch = "32"
#url = "https://api.mainnet-beta.solana.com"
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions lib/marinade-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[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" }
num-traits = "0.2.17"
95 changes: 95 additions & 0 deletions lib/marinade-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
pub mod vault_authority_seed;

use marinade_cpi::state::State as MarinadeState;
use num_traits::{NumCast, PrimInt};
use std::fmt::Debug;
use std::ops::{Div, Mul};

/// 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<T>(amount: T, numerator: T, denominator: T) -> T
where
T: PrimInt + Mul<Output = T> + Div<Output = T> + TryInto<i128>,
<T as TryInto<i128>>::Error: Debug,
{
proportional_with_rounding(amount, numerator, denominator, RoundingMode::Down)
}

pub enum RoundingMode {
Up,
Down,
}

pub fn proportional_with_rounding<T>(
amount: T,
numerator: T,
denominator: T,
rounding_mode: RoundingMode,
) -> T
where
T: PrimInt + Mul<Output = T> + Div<Output = T> + TryInto<i128>,
<T as TryInto<i128>>::Error: Debug,
{
if denominator == T::zero() {
return amount;
}

let amount_i128: i128 = amount.try_into().unwrap();
let numerator_i128: i128 = numerator.try_into().unwrap();
let denominator_i128: i128 = denominator.try_into().unwrap();

match rounding_mode {
RoundingMode::Up => {
// Round up by adding (denominator - 1) before dividing
let result = (amount_i128 * numerator_i128 + (denominator_i128 - 1)) / denominator_i128;
<T as NumCast>::from(result).unwrap()
}
RoundingMode::Down => {
// Default behavior (round down)
let result = amount_i128 * numerator_i128 / denominator_i128;
<T as NumCast>::from(result).unwrap()
}
}
}

// 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) -> u64 {
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) -> u64 {
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]
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"prettier": "^3.0.3",
"ts-node": "^10.9.1",
"turbo": "^1.10.16",
"typedoc": "^0.25.1",
"typedoc": "^0.25.8",
"typescript": "^5.3.2"
}
}
Loading
Loading