cardinal-configs 1.0.0

Cardinal Configs
Documentation
use crate::errors::ErrorCode;
use anchor_lang::prelude::*;
use solana_program::{program::invoke, system_instruction::transfer};
use std::{cmp::Ordering, slice::Iter, str::FromStr};

pub const GLOBAL_AUTHORITY: &str = "gmdS6fDgVbeCCYwwvTPJRKM9bFbAgSZh6MTDUT2DcgV";
pub const CONFIG_ENTRY_SEED_PREFIX: &str = "config-entry";
pub const CONFIG_ENTRY_SIZE: usize = 8 + std::mem::size_of::<ConfigEntry>() + 16;

#[account]
pub struct ConfigEntry {
    pub bump: u8,
    pub key: String,
    pub value: String,
    pub extends: Vec<Pubkey>,
}

pub fn assert_authority<'info>(key: &String, authority: Pubkey, remaining_accounts: &mut Iter<AccountInfo<'info>>) -> Result<()> {
    if authority == Pubkey::from_str(GLOBAL_AUTHORITY).unwrap() {
        return Ok(());
    }
    if key.starts_with("s:") {
        let stake_pool_account_info_unsafe = next_account_info(remaining_accounts);
        if stake_pool_account_info_unsafe.is_err() {
            return Err(error!(ErrorCode::MissingRemainingAccountsForConfigEntry));
        }
        let stake_pool_account_info = stake_pool_account_info_unsafe.unwrap();
        if stake_pool_account_info.owner == &cardinal_stake_pool::id() {
            let stake_pool_unsafe = Account::<cardinal_stake_pool::state::StakePool>::try_from(stake_pool_account_info);
            if stake_pool_unsafe.is_err() {
                return Err(error!(ErrorCode::InvalidStakePoolAccount));
            }
            let stake_pool = stake_pool_unsafe.unwrap();
            if stake_pool.authority != authority.key() {
                return Err(error!(ErrorCode::InvalidPoolAuthority));
            }
        } else if stake_pool_account_info.owner == &cardinal_rewards_center::id() {
            let stake_pool_unsafe = Account::<cardinal_rewards_center::StakePool>::try_from(stake_pool_account_info);
            if stake_pool_unsafe.is_err() {
                return Err(error!(ErrorCode::InvalidStakePoolAccount));
            }
            let stake_pool = stake_pool_unsafe.unwrap();
            if stake_pool.authority != authority.key() {
                return Err(error!(ErrorCode::InvalidPoolAuthority));
            }
        }
    }
    Ok(())
}

pub fn resize_account<'info>(account_info: &AccountInfo<'info>, new_space: usize, payer: &AccountInfo<'info>, system_program: &AccountInfo<'info>) -> Result<()> {
    let rent = Rent::get()?;
    msg!("resize {} => {}", account_info.data_len(), new_space);
    let new_minimum_balance = rent.minimum_balance(new_space);
    let current_balance = account_info.lamports();

    match new_minimum_balance.cmp(&current_balance) {
        Ordering::Greater => {
            let lamports_diff = new_minimum_balance.saturating_sub(current_balance);
            invoke(
                &transfer(&payer.key(), &account_info.key(), lamports_diff),
                &[payer.clone(), account_info.clone(), system_program.clone()],
            )?;
        }
        Ordering::Less => {
            let lamports_diff = current_balance.saturating_sub(new_minimum_balance);
            **account_info.try_borrow_mut_lamports()? = new_minimum_balance;
            **payer.try_borrow_mut_lamports()? = payer.lamports().checked_add(lamports_diff).expect("Add error");
        }
        Ordering::Equal => {}
    }
    account_info.realloc(new_space, false)?;
    Ok(())
}