Skip to content

Commit

Permalink
Merge pull request #13 from adm-metaex/feature/delegated-staking-check
Browse files Browse the repository at this point in the history
[MTG-482] using the delegated stake in the minimal requirement check
  • Loading branch information
StanChe authored Aug 8, 2024
2 parents 8202945 + 6de5c68 commit ec3dd4a
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 48 deletions.
101 changes: 87 additions & 14 deletions programs/bubblegum/Cargo.lock

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

5 changes: 3 additions & 2 deletions programs/bubblegum/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ solana-program = "~1.18.11"
spl-account-compression = {git = "https://github.com/StanChe/solana-program-library.git", branch = "feature/init_with_root", features = ["cpi"] }
spl-associated-token-account = { version = ">= 1.1.3, < 3.0", features = ["no-entrypoint"] }
spl-token = { version = ">= 3.5.0, < 5.0", features = ["no-entrypoint"] }
mplx-staking-states = {git = "https://github.com/adm-metaex/mplx-staking.git" }
mplx-staking-states = { git = "https://github.com/adm-metaex/mplx-staking.git" }
mplx-rewards = { git = "https://github.com/adm-metaex/mplx-rewards.git", features = ["no-entrypoint"] }

[dev-dependencies]
async-trait = "0.1.71"
mpl-token-auth-rules = { git = "https://github.com/metaplex-foundation/mpl-token-auth-rules.git", branch = "main", features = ["no-entrypoint"] }
mpl-token-auth-rules = { version = "1.5.1", features = ["no-entrypoint"] }
solana-program-test = "~1.18.11"
solana-sdk = "~1.18.11"
spl-concurrent-merkle-tree = { git = "https://github.com/StanChe/solana-program-library.git", branch = "feature/init_with_root" }
Expand Down
2 changes: 2 additions & 0 deletions programs/bubblegum/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ pub enum BubblegumError {
StakingVoterRegistrarMismatch,
#[msg("Staking voter authority mismatch")]
StakingVoterAuthorityMismatch,
#[msg("Invalid mining owner")]
MiningOwnerMismatch,
}

// Converts certain Token Metadata errors into Bubblegum equivalents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
},
};

const DISCRIMINATOR_LEN: usize = REGISTRAR_DISCRIMINATOR.len();
#[derive(Accounts)]
pub struct FinalizeTreeWithRoot<'info> {
#[account(
Expand All @@ -30,6 +31,8 @@ pub struct FinalizeTreeWithRoot<'info> {
/// CHECK:
pub voter: UncheckedAccount<'info>,
/// CHECK:
pub mining: UncheckedAccount<'info>,
/// CHECK:
#[account(mut)]
pub fee_receiver: UncheckedAccount<'info>,
pub log_wrapper: Program<'info, Noop>,
Expand Down Expand Up @@ -61,6 +64,7 @@ pub(crate) fn finalize_tree_with_root<'info>(
&ctx.accounts.staker.to_account_info(),
&ctx.accounts.registrar.to_account_info(),
&ctx.accounts.voter.to_account_info(),
&ctx.accounts.mining.to_account_info(),
)?;

let num_minted = (rightmost_index + 1) as u64;
Expand Down Expand Up @@ -107,6 +111,7 @@ pub(crate) fn check_stake<'info>(
staker_acc: &AccountInfo<'info>,
registrar_acc: &AccountInfo<'info>,
voter_acc: &AccountInfo<'info>,
mining_acc: &AccountInfo<'info>,
) -> Result<()> {
require!(
registrar_acc.owner == &mplx_staking_states::ID,
Expand All @@ -116,6 +121,10 @@ pub(crate) fn check_stake<'info>(
voter_acc.owner == &mplx_staking_states::ID,
BubblegumError::StakingVoterMismatch
);
require!(
mining_acc.owner == &mplx_rewards::ID,
BubblegumError::MiningOwnerMismatch
);

let generated_registrar = Pubkey::find_program_address(
&[
Expand Down Expand Up @@ -146,13 +155,13 @@ pub(crate) fn check_stake<'info>(
);

let registrar_bytes = registrar_acc.to_account_info().data;

let registrar_bytes = registrar_bytes.borrow();
require!(
(*registrar_bytes.borrow())[..8] == REGISTRAR_DISCRIMINATOR,
registrar_bytes[..DISCRIMINATOR_LEN] == REGISTRAR_DISCRIMINATOR,
BubblegumError::StakingRegistrarDiscriminatorMismatch
);

let registrar: Registrar = *bytemuck::from_bytes(&(*registrar_bytes.borrow())[8..]);
let registrar: &Registrar = bytemuck::from_bytes(&registrar_bytes[DISCRIMINATOR_LEN..]);

require!(
registrar.realm == REALM,
Expand All @@ -164,12 +173,12 @@ pub(crate) fn check_stake<'info>(
);
let voter_bytes = voter_acc.to_account_info().data;

let voter_bytes = voter_bytes.borrow();
require!(
(*voter_bytes.borrow())[..8] == VOTER_DISCRIMINATOR,
voter_bytes[..DISCRIMINATOR_LEN] == VOTER_DISCRIMINATOR,
BubblegumError::StakingVoterDiscriminatorMismatch
);

let voter: Voter = *bytemuck::from_bytes(&(*voter_bytes.borrow())[8..]);
let voter: &Voter = bytemuck::from_bytes(&voter_bytes[DISCRIMINATOR_LEN..]);

require!(
&voter.registrar == registrar_acc.key,
Expand All @@ -179,7 +188,12 @@ pub(crate) fn check_stake<'info>(
&voter.voter_authority == staker_acc.key,
BubblegumError::StakingVoterAuthorityMismatch
);

let mining_data = mining_acc.data.borrow();
let mining = mplx_rewards::state::WrappedImmutableMining::from_bytes(&mining_data)?;
require!(
&mining.mining.owner == staker_acc.key,
BubblegumError::MiningOwnerMismatch
);
let clock = Clock::get()?;
let curr_ts = clock.unix_timestamp as u64;
let weighted_sum: u64 = voter
Expand All @@ -188,7 +202,11 @@ pub(crate) fn check_stake<'info>(
.map(|d| d.weighted_stake(curr_ts))
.sum();

if weighted_sum < MINIMUM_WEIGHTED_STAKE {
if weighted_sum
.checked_add(mining.mining.stake_from_others)
.ok_or(BubblegumError::NumericalOverflowError)?
< MINIMUM_WEIGHTED_STAKE
{
return Err(BubblegumError::NotEnoughStakeForOperation.into());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub struct FinalizeTreeWithRootAndCollection<'info> {
/// CHECK:
pub voter: UncheckedAccount<'info>,
/// CHECK:
pub mining: UncheckedAccount<'info>,
/// CHECK:
#[account(mut)]
pub fee_receiver: UncheckedAccount<'info>,
/// CHECK: Optional collection authority record PDA.
Expand Down Expand Up @@ -95,6 +97,7 @@ impl<'info> From<&mut FinalizeTreeWithRootAndCollection<'info>> for FinalizeTree
staker: value.staker.to_owned(),
registrar: value.registrar.to_owned(),
voter: value.voter.to_owned(),
mining: value.mining.to_owned(),
fee_receiver: value.fee_receiver.to_owned(),
log_wrapper: value.log_wrapper.to_owned(),
compression_program: value.compression_program.to_owned(),
Expand Down
Loading

0 comments on commit ec3dd4a

Please sign in to comment.