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

[mtg-584] Penalties/restrict batch minting #29

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions programs/mpl-staking/src/cpi_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,50 @@ pub enum RewardsInstruction {
/// [S] Reward pool account
/// [W] Mining
AllowTokenFlow { mining_owner: Pubkey },

/// Restricts batch minting until the specified time
///
/// Accounts:
/// [RS] Deposit authority
/// [S] Reward pool account
/// [W] Mining
RestrictBatchMinting {
/// Time until batch minting is restricted
until_ts: u64,
/// Owner of the mining account
mining_owner: Pubkey,
},
}

pub fn restrict_batch_minting<'a>(
program_id: AccountInfo<'a>,
deposit_authority: AccountInfo<'a>,
reward_pool: AccountInfo<'a>,
mining: AccountInfo<'a>,
mining_owner: &Pubkey,
until_ts: u64,
signers_seeds: &[&[u8]],
) -> ProgramResult {
let accounts = vec![
AccountMeta::new_readonly(deposit_authority.key(), true),
AccountMeta::new_readonly(reward_pool.key(), false),
AccountMeta::new(mining.key(), false),
];

let ix = Instruction::new_with_borsh(
program_id.key(),
&RewardsInstruction::RestrictBatchMinting {
until_ts,
mining_owner: *mining_owner,
},
accounts,
);

invoke_signed(
&ix,
&[deposit_authority, reward_pool, mining, program_id],
&[signers_seeds],
)
}

pub fn restrict_tokenflow<'a>(
Expand Down
3 changes: 3 additions & 0 deletions programs/mpl-staking/src/instructions/penalties/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ use anchor_lang::{
prelude::{AccountLoader, Signer, ToAccountInfo, UncheckedAccount},
Accounts,
};

pub use restrict_batch_minting::*;
pub use restrict_tokenflow::*;

mod allow_tokenflow;
mod restrict_batch_minting;
mod restrict_tokenflow;

use mplx_staking_states::state::Registrar;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use super::Penalty;
use crate::cpi_instructions;
use anchor_lang::prelude::*;
use mplx_staking_states::error::MplStakingError;

/// Restricts batch minting operation for the account until the specified timestamp.
pub fn restrict_batch_minting(
ctx: Context<Penalty>,
until_ts: u64,
mining_owner: Pubkey,
) -> Result<()> {
let registrar = ctx.accounts.registrar.load()?;

require_keys_eq!(
registrar.realm_authority,
ctx.accounts.realm_authority.key(),
MplStakingError::InvalidRealmAuthority
);

let signers_seeds = &[
&registrar.realm.key().to_bytes(),
b"registrar".as_ref(),
&registrar.realm_governing_token_mint.key().to_bytes(),
&[registrar.bump][..],
];

cpi_instructions::restrict_batch_minting(
ctx.accounts.rewards_program.to_account_info(),
ctx.accounts.registrar.to_account_info(),
ctx.accounts.reward_pool.to_account_info(),
ctx.accounts.deposit_mining.to_account_info(),
&mining_owner,
until_ts,
signers_seeds,
)?;

Ok(())
}
8 changes: 8 additions & 0 deletions programs/mpl-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ pub mod mpl_staking {
pub fn allow_tokenflow(ctx: Context<Penalty>, mining_owner: Pubkey) -> Result<()> {
instructions::allow_tokenflow(ctx, mining_owner)
}

pub fn restrict_batch_minting(
ctx: Context<Penalty>,
until_ts: u64,
mining_owner: Pubkey,
) -> Result<()> {
instructions::restrict_batch_minting(ctx, until_ts, mining_owner)
}
}

#[derive(Accounts)]
Expand Down
Binary file modified programs/mpl-staking/tests/fixtures/mplx_rewards.so
Binary file not shown.
Binary file not shown.
37 changes: 37 additions & 0 deletions programs/mpl-staking/tests/program_test/addin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,43 @@ impl AddinCookie {
self.solana.context.borrow_mut().set_sysvar(&new_clock);
}

pub async fn restrict_batch_minting(
&self,
reward_pool: &Pubkey,
deposit_mining: &Pubkey,
registrar: &RegistrarCookie,
realm_authority: &Keypair,
mining_owner: &Pubkey,
until_ts: u64,
rewards_program: &Pubkey,
) -> std::result::Result<(), BanksClientError> {
let data = InstructionData::data(&mpl_staking::instruction::RestrictBatchMinting {
until_ts,
mining_owner: *mining_owner,
});

let accounts = anchor_lang::ToAccountMetas::to_account_metas(
&mpl_staking::accounts::Penalty {
registrar: registrar.address,
realm_authority: realm_authority.pubkey(),
reward_pool: *reward_pool,
deposit_mining: *deposit_mining,
rewards_program: *rewards_program,
},
None,
);

let instructions = vec![Instruction {
program_id: self.program_id,
accounts,
data,
}];

self.solana
.process_transaction(&instructions, Some(&[realm_authority]))
.await
}

pub async fn restrict_tokenflow(
&self,
reward_pool: &Pubkey,
Expand Down
168 changes: 168 additions & 0 deletions programs/mpl-staking/tests/restrict_batch_minting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use anchor_spl::token::TokenAccount;
use mplx_staking_states::state::{LockupKind, LockupPeriod};
use program_test::*;
use solana_program_test::*;
use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError};

mod program_test;

#[tokio::test]
async fn restrict_batch_minting_poc() -> Result<(), TransportError> {
let context = TestContext::new().await;

let payer = &context.users[0].key;
let realm_authority = Keypair::new();
let realm = context
.governance
.create_realm(
REALM_NAME,
realm_authority.pubkey(),
&context.mints[0],
payer,
&context.addin.program_id,
)
.await;

let deposit_authority = &context.users[1].key;
let token_owner_record = realm
.create_token_owner_record(deposit_authority.pubkey(), payer)
.await;

let fill_authority = Keypair::from_bytes(&context.users[3].key.to_bytes()).unwrap();
let distribution_authority = Keypair::new();
let (registrar, rewards_pool) = context
.addin
.create_registrar(
&realm,
&realm_authority,
payer,
&fill_authority.pubkey(),
&distribution_authority.pubkey(),
&context.rewards.program_id,
)
.await;
context
.addin
.configure_voting_mint(
&registrar,
&realm_authority,
payer,
0,
&context.mints[0],
None,
None,
)
.await;
let mngo_voting_mint = context
.addin
.configure_voting_mint(
&registrar,
&realm_authority,
payer,
0,
&context.mints[0],
None,
None,
)
.await;

// TODO: ??? voter_authority == deposit_authority ???
let voter_authority = deposit_authority;
let (deposit_mining, _) = find_deposit_mining_addr(
&context.rewards.program_id,
&voter_authority.pubkey(),
&rewards_pool,
);

let voter = context
.addin
.create_voter(
&registrar,
&token_owner_record,
voter_authority,
payer,
&rewards_pool,
&deposit_mining,
&context.rewards.program_id,
)
.await;

let depositer_token_account = context.users[1].token_accounts[0];

context
.addin
.create_deposit_entry(
&registrar,
&voter,
&voter,
&mngo_voting_mint,
0,
LockupKind::None,
LockupPeriod::None,
)
.await?;
context
.addin
.create_deposit_entry(
&registrar,
&voter,
&voter,
&mngo_voting_mint,
1,
LockupKind::Constant,
LockupPeriod::ThreeMonths,
)
.await?;

context
.addin
.deposit(
&registrar,
&voter,
&mngo_voting_mint,
deposit_authority,
depositer_token_account,
0,
10000,
)
.await?;

context
.addin
.stake(
&registrar,
&voter,
voter.authority.pubkey(),
&context.rewards.program_id,
0,
1,
10000,
)
.await?;

let distribution_ends_at = context
.solana
.context
.borrow_mut()
.banks_client
.get_sysvar::<solana_program::clock::Clock>()
.await
.unwrap()
.unix_timestamp as u64
+ 86400;

context
.addin
.restrict_batch_minting(
&rewards_pool,
&deposit_mining,
&registrar,
&realm_authority,
&voter_authority.pubkey(),
distribution_ends_at,
&context.rewards.program_id,
)
.await?;

Ok(())
}
Loading