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

change fund permission #68

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
89 changes: 82 additions & 7 deletions programs/farming/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![allow(rustdoc::missing_doc_code_examples)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::integer_arithmetic)]
#![warn(missing_docs)]
// #![warn(missing_docs)]

use std::convert::Into;
use std::convert::TryInto;
Expand All @@ -21,6 +21,25 @@ pub mod pool;

declare_id!("FarmuwXPWXvefWUeqFAa5w6rifLkq5X6E8bimYvrhCB1");

/// Admin
pub mod admin {
use super::*;
use anchor_lang::solana_program::pubkey;
/// admin
pub const ADMINS: [Pubkey; 3] = [
pubkey!("5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi"),
pubkey!("ChSAh3XXTxpp5n2EmgSCm6vVvVPoD1L9VrK3mcQkYz7m"),
pubkey!("DHLXnJdACTY83yKwnUkeoDjqi4QBbsYGa1v8tJL76ViX"),
];
}

/// assert eq admin
pub fn assert_eq_admin(admin: Pubkey) -> bool {
crate::admin::ADMINS
.iter()
.any(|predefined_admin| predefined_admin.eq(&admin))
}

const PRECISION: u128 = 1_000_000_000;

/// Updates the pool with the total reward per token that is due stakers
Expand Down Expand Up @@ -66,10 +85,10 @@ fn last_time_reward_applicable(reward_duration_end: u64) -> u64 {
std::cmp::min(c.unix_timestamp.try_into().unwrap(), reward_duration_end)
}

/// Dual farming program
#[program]
pub mod farming {
use super::*;
/// Min duration for fund
pub const MIN_DURATION: u64 = 1;
/// Initializes a new pool. Able to create pool with single reward by passing the same Mint account for reward_a_mint and reward_a_mint
pub fn initialize_pool(ctx: Context<InitializePool>, reward_duration: u64) -> Result<()> {
Expand Down Expand Up @@ -130,6 +149,17 @@ pub mod farming {
Ok(())
}

/// Toggle permission
pub fn toggle_permission(ctx: Context<TogglePermission>) -> Result<()> {
let pool = &mut ctx.accounts.pool;
if pool.permission_lag == 0 {
pool.permission_lag = 1;
} else {
pool.permission_lag = 0;
}
Ok(())
}

/// User deposit tokens in the pool.
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
if amount == 0 {
Expand Down Expand Up @@ -265,6 +295,14 @@ pub mod farming {
pub fn fund(ctx: Context<Fund>, amount_a: u64, amount_b: u64) -> Result<()> {
let pool = &mut ctx.accounts.pool;

if pool.is_permissioned() {
let funder = ctx.accounts.funder.key();
require!(
funder == pool.authority || pool.funders.iter().any(|x| *x == funder),
ErrorCode::InvalidFunder
);
}

//can't compare using reward_vault because it is PDA. The PDA seed contain different prefix
//if mint are the same, we just use a
if amount_b > 0 && ctx.accounts.reward_a_vault.mint == ctx.accounts.reward_b_vault.mint {
Expand Down Expand Up @@ -731,6 +769,17 @@ pub struct Unpause<'info> {
authority: Signer<'info>,
}

/// Accounts for [TogglePermission](/dual_farming/instruction/struct.TogglePermission.html) instruction
#[derive(Accounts)]
pub struct TogglePermission<'info> {
/// Global accounts for the staking instance.
#[account(mut)]
pool: Box<Account<'info, Pool>>,
/// Authority program
#[account(constraint = assert_eq_admin(authority.key()) @ ErrorCode::InvalidAdmin)]
authority: Signer<'info>,
}

/// Accounts for [Deposit](/dual_farming/instruction/struct.Deposit.html) and [Withdraw](/dual_farming/instruction/struct.Withdraw.html) instructions.
#[derive(Accounts)]
pub struct Deposit<'info> {
Expand Down Expand Up @@ -803,7 +852,7 @@ pub struct Fund<'info> {
/// Funder
#[account(
//require signed funder auth - otherwise constant micro fund could hold funds hostage
constraint = funder.key() == pool.authority || pool.funders.iter().any(|x| *x == funder.key()),
// constraint = funder.key() == pool.authority || pool.funders.iter().any(|x| *x == funder.key()),
)]
funder: Signer<'info>,
/// Funder reward A ATA
Expand Down Expand Up @@ -838,8 +887,8 @@ pub struct WithdrawExtraToken<'info> {
token_program: Program<'info, Token>,
}

/// Accounts for [Claim](/dual_farming/instruction/struct.Claim.html) instruction.
#[derive(Accounts)]
/// Accounts for [Claim](/dual_farming/instruction/struct.Claim.html) instruction.
pub struct ClaimReward<'info> {
/// Global accounts for the staking instance.
#[account(
Expand Down Expand Up @@ -879,14 +928,16 @@ pub struct ClaimReward<'info> {
/// User's Reward B ATA
#[account(mut)]
reward_b_account: Box<Account<'info, TokenAccount>>,
// Misc.
/// Misc.
token_program: Program<'info, Token>,
}
/// Accounts for [CloseUser](/dual_farming/instruction/struct.CloseUser.html) instruction
#[derive(Accounts)]
pub struct CloseUser<'info> {
/// pool
#[account(mut)]
pool: Box<Account<'info, Pool>>,
/// user
#[account(
mut,
close = owner,
Expand All @@ -902,30 +953,36 @@ pub struct CloseUser<'info> {
constraint = user.reward_b_per_token_pending == 0,
)]
user: Account<'info, User>,
// To receive lamports when close the user account
/// To receive lamports when close the user account
#[account(mut)]
owner: Signer<'info>,
}

/// Accounts for [MigrateFarmingRate](/dual_farming/instruction/struct.MigrateFarmingRate.html) instruction
#[derive(Accounts)]
pub struct MigrateFarmingRate<'info> {
/// pool account
#[account(mut)]
pool: Box<Account<'info, Pool>>,
}

/// Accounts for [ClosePool](/dual_farming/instruction/struct.ClosePool.html) instruction
#[derive(Accounts)]
pub struct ClosePool<'info> {
#[account(mut)]
/// CHECK: refundee
/// refundee
#[account(mut)]
refundee: UncheckedAccount<'info>,
/// staking_refundee
#[account(mut)]
staking_refundee: Box<Account<'info, TokenAccount>>,
/// reward_a_refundee
#[account(mut)]
reward_a_refundee: Box<Account<'info, TokenAccount>>,
/// reward_b_refundee
#[account(mut)]
reward_b_refundee: Box<Account<'info, TokenAccount>>,
/// pool
#[account(
mut,
close = refundee,
Expand All @@ -939,15 +996,20 @@ pub struct ClosePool<'info> {
constraint = pool.user_stake_count == 0,
)]
pool: Account<'info, Pool>,
/// authority
authority: Signer<'info>,
/// staking_vault
#[account(mut,
constraint = staking_vault.amount == 0, // Admin need to withdraw out mistakenly deposited token firstly
)]
staking_vault: Box<Account<'info, TokenAccount>>,
/// reward_a_vault
#[account(mut)]
reward_a_vault: Box<Account<'info, TokenAccount>>,
/// reward_b_vault
#[account(mut)]
reward_b_vault: Box<Account<'info, TokenAccount>>,
/// token_program
token_program: Program<'info, Token>,
}

Expand Down Expand Up @@ -1001,6 +1063,8 @@ pub struct Pool {
pub pool_bump: u8, // 1
/// Total staked amount
pub total_staked: u64,
/// permission_lag, 0 as permissionless, anyone can fund the pool, 1 as permissioned, only funder is able to fund
pub permission_lag: u8,
}

impl Pool {
Expand All @@ -1019,6 +1083,11 @@ impl Pool {
}
return self.reward_b_rate_u128;
}

/// return permission status
pub fn is_permissioned(&self) -> bool {
self.permission_lag == 1
}
}

/// Farming user account
Expand Down Expand Up @@ -1114,6 +1183,12 @@ pub enum ErrorCode {
/// Math opeartion overflow
#[msg("Math operation overflow")]
MathOverflow,
/// Invalid admin
#[msg("Invalid admin")]
InvalidAdmin,
/// Invalid funder
#[msg("Invalid funder")]
InvalidFunder,
}

impl Debug for User {
Expand Down
1 change: 1 addition & 0 deletions programs/farming/src/pool.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! pool
pub use crate::*;
use spl_math::uint::U192;

Expand Down
Loading