Skip to content

Commit

Permalink
Migrate farming rate (#60)
Browse files Browse the repository at this point in the history
* migrate farming rate

* add migrate farming rate to cli
  • Loading branch information
andrewsource147 authored Dec 6, 2023
1 parent 4ae50cc commit c934153
Show file tree
Hide file tree
Showing 7 changed files with 2,274 additions and 45 deletions.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

.anchor
.DS_Store
target
target/*
!target/types
test-ledger
**/*.rs.bk
/keys/
Expand All @@ -14,4 +15,5 @@ soteria-linux-develop/
testing/
deployment
dist
.env
.env

3 changes: 3 additions & 0 deletions cli/farming-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ pub enum CliCommand {
#[clap(long)]
pool: Pubkey,
},

CheckFunderAllPool {},
MigrateFarmingRate {},
}

#[derive(Parser, Debug)]
Expand Down
48 changes: 48 additions & 0 deletions cli/farming-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ mod utils;

use crate::args::*;
use crate::utils::*;
use anyhow::Ok;
use anyhow::Result;

use anchor_client::solana_client::rpc_filter::RpcFilterType;
use anchor_client::solana_sdk::commitment_config::CommitmentConfig;
use anchor_client::solana_sdk::pubkey::Pubkey;
use anchor_client::solana_sdk::signer::keypair::*;
use anchor_client::solana_sdk::signer::Signer;
use anchor_client::{Client, Program};
use farming::Pool;
use std::rc::Rc;
use std::str::FromStr;

Expand Down Expand Up @@ -93,6 +96,12 @@ fn main() -> Result<()> {
CliCommand::StakeInfo { pool } => {
stake_info(&program, &pool, &payer.pubkey())?;
}
CliCommand::CheckFunderAllPool {} => {
check_funder_all_pool(&program)?;
}
CliCommand::MigrateFarmingRate {} => {
migrate_farming_rate(&program)?;
}
}

Ok(())
Expand Down Expand Up @@ -430,3 +439,42 @@ pub fn stake_info(program: &Program, pool_pda: &Pubkey, user: &Pubkey) -> Result
);
Ok(())
}

fn check_funder_all_pool(program: &Program) -> Result<()> {
let pools: Vec<(Pubkey, Pool)> = program.accounts::<Pool>(vec![]).unwrap();

println!("len pool {}", pools.len());

for pool in pools.iter() {
assert_eq!(pool.1.reward_a_rate_u128, 0);
assert_eq!(pool.1.reward_b_rate_u128, 0);
}
Ok(())
}

fn migrate_farming_rate(program: &Program) -> Result<()> {
let pools: Vec<(Pubkey, Pool)> = program.accounts::<Pool>(vec![]).unwrap();

println!("len pool {}", pools.len());

for pool in pools.iter() {
let pool_state = pool.1.clone();
let mut should_migrate = false;
if pool_state.reward_a_rate_u128 == 0 && pool_state._reward_a_rate != 0 {
should_migrate = true;
}
if pool_state.reward_b_rate_u128 == 0 && pool_state._reward_b_rate != 0 {
should_migrate = true;
}

if should_migrate {
let builder = program
.request()
.accounts(farming::accounts::MigrateFarmingRate { pool: pool.0 })
.args(farming::instruction::MigrateFarmingRate {});
let signature = builder.send()?;
println!("Migrate pool {} signature {:?}", pool.0, signature);
}
}
Ok(())
}
2 changes: 1 addition & 1 deletion programs/farming/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "farming"
version = "0.2.0"
version = "0.2.1"
description = "Created with Anchor"
edition = "2018"

Expand Down
86 changes: 60 additions & 26 deletions programs/farming/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use std::convert::Into;
use std::convert::TryInto;
use std::fmt::Debug;

use crate::pool::*;
use anchor_lang::prelude::*;
use anchor_lang::solana_program::{clock, sysvar};
use anchor_spl::token::{self, Mint, Token, TokenAccount};

use crate::pool::*;
use std::convert::TryFrom;

/// Export for pool implementation
pub mod pool;
Expand Down Expand Up @@ -88,8 +88,6 @@ pub mod farming {
pool.total_staked = 0;
pool.reward_duration_end = 0;
pool.last_update_time = 0;
pool.reward_a_rate = 0;
pool.reward_b_rate = 0;
pool.reward_a_per_token_stored = 0;
pool.reward_b_per_token_stored = 0;
pool.user_stake_count = 0;
Expand Down Expand Up @@ -275,8 +273,16 @@ pub mod farming {
update_rewards(pool, None, pool.total_staked).unwrap();

let (reward_a_rate, reward_b_rate) = rate_after_funding(pool, amount_a, amount_b)?;
pool.reward_a_rate = reward_a_rate;
pool.reward_b_rate = reward_b_rate;
pool.reward_a_rate_u128 = reward_a_rate;
pool.reward_b_rate_u128 = reward_b_rate;

// this is to avoid breaking old integrator
if let Ok(reward_rate) = u64::try_from(reward_a_rate) {
pool._reward_a_rate = reward_rate;
}
if let Ok(reward_rate) = u64::try_from(reward_b_rate) {
pool._reward_b_rate = reward_rate;
}

// Transfer reward A tokens into the A vault.
if amount_a > 0 {
Expand Down Expand Up @@ -437,6 +443,18 @@ pub mod farming {
Ok(())
}

/// anyone can call this
pub fn migrate_farming_rate(ctx: Context<MigrateFarmingRate>) -> Result<()> {
let pool = &mut ctx.accounts.pool;
if pool.reward_a_rate_u128 == 0 && pool._reward_a_rate != 0 {
pool.reward_a_rate_u128 = pool._reward_a_rate.into();
}
if pool.reward_b_rate_u128 == 0 && pool._reward_b_rate != 0 {
pool.reward_b_rate_u128 = pool._reward_b_rate.into();
}
Ok(())
}

/// Closes a pool account. Only able to be done when there are no users staked.
pub fn close_pool(ctx: Context<ClosePool>) -> Result<()> {
let pool = &ctx.accounts.pool;
Expand Down Expand Up @@ -887,6 +905,14 @@ pub struct CloseUser<'info> {
#[account(mut)]
owner: Signer<'info>,
}

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

/// Accounts for [ClosePool](/dual_farming/instruction/struct.ClosePool.html) instruction
#[derive(Accounts)]
pub struct ClosePool<'info> {
Expand Down Expand Up @@ -926,6 +952,7 @@ pub struct ClosePool<'info> {

/// Pool account wrapper
#[account]
#[derive(Debug)]
pub struct Pool {
/// Privileged account.
pub authority: Pubkey, // 32
Expand All @@ -951,10 +978,10 @@ pub struct Pool {
pub reward_duration_end: u64, // 8
/// The last time reward states were updated.
pub last_update_time: u64, // 8
/// Rate of reward A distribution.
pub reward_a_rate: u64, // 8
/// Rate of reward B distribution.
pub reward_b_rate: u64, // 8
/// deprecated field
pub _reward_a_rate: u64, // 8
/// deprecated field
pub _reward_b_rate: u64, // 8
/// Last calculated reward A per pool token.
pub reward_a_per_token_stored: u128, // 16
/// Last calculated reward B per pool token.
Expand All @@ -964,13 +991,35 @@ pub struct Pool {
/// authorized funders
/// [] because short size, fixed account size, and ease of use on
/// client due to auto generated account size property
pub funders: [Pubkey; 4], // 32 * 4 = 128
pub funders: [Pubkey; 3], // 32 * 4 = 128
/// reward_a_rate in u128 form
pub reward_a_rate_u128: u128,
/// reward_b_rate in u128 form
pub reward_b_rate_u128: u128,
/// Pool bump
pub pool_bump: u8, // 1
/// Total staked amount
pub total_staked: u64,
}

impl Pool {
/// return reward a rate
pub fn get_reward_a_rate(&self) -> u128 {
if self.reward_a_rate_u128 == 0 {
return self._reward_a_rate.into();
}
return self.reward_a_rate_u128;
}

/// return reward b rate
pub fn get_reward_b_rate(&self) -> u128 {
if self.reward_b_rate_u128 == 0 {
return self._reward_b_rate.into();
}
return self.reward_b_rate_u128;
}
}

/// Farming user account
#[account]
#[derive(Default)]
Expand Down Expand Up @@ -1066,21 +1115,6 @@ pub enum ErrorCode {
MathOverflow,
}

impl Debug for Pool {
/// writes a subset of pool fields for debugging
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "paused: {} reward_duration: {} reward_duration_end: {} reward_a_rate: {} reward_b_rate: {} reward_a_per_token_stored {} reward_b_per_token_stored {}",
self.paused,
self.reward_duration,
self.reward_duration_end,
self.reward_a_rate,
self.reward_b_rate,
self.reward_a_per_token_stored,
self.reward_b_per_token_stored,
)
}
}

impl Debug for User {
/// writes a subset of user fields for debugging
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
Expand Down
43 changes: 27 additions & 16 deletions programs/farming/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ pub use crate::*;
use spl_math::uint::U192;

/// Rate by funding
fn calculate_reward_rate(funding_amount: u64, reward_duration: u64) -> Option<u64> {
fn calculate_reward_rate(funding_amount: u64, reward_duration: u64) -> Option<u128> {
let funding_amount: u128 = funding_amount.into();
let reward_duration: u128 = reward_duration.into();
let reward_rate = funding_amount
.checked_mul(PRECISION)?
.checked_div(reward_duration)?;
reward_rate.try_into().ok()
Some(reward_rate)
}

/// Calculate reward per token
Expand All @@ -31,7 +31,7 @@ pub fn reward_per_token(
.reward_a_per_token_stored
.checked_add(
time_period
.checked_mul(pool.reward_a_rate.into())
.checked_mul(pool.get_reward_a_rate().into())
.unwrap()
.checked_div(total_staked.into())
.unwrap()
Expand All @@ -44,7 +44,7 @@ pub fn reward_per_token(
.reward_b_per_token_stored
.checked_add(
time_period
.checked_mul(pool.reward_b_rate.into())
.checked_mul(pool.get_reward_b_rate().into())
.unwrap()
.checked_div(total_staked.into())
.unwrap()
Expand All @@ -61,31 +61,29 @@ pub fn rate_after_funding(
pool: &mut Account<Pool>,
funding_amount_a: u64,
funding_amount_b: u64,
) -> Result<(u64, u64)> {
) -> Result<(u128, u128)> {
let current_time = clock::Clock::get()
.unwrap()
.unix_timestamp
.try_into()
.unwrap();
let reward_period_end = pool.reward_duration_end;

let a: u64;
let b: u64;

if current_time >= reward_period_end {
a = calculate_reward_rate(funding_amount_a, pool.reward_duration).unwrap();
b = calculate_reward_rate(funding_amount_b, pool.reward_duration).unwrap();
let a = calculate_reward_rate(funding_amount_a, pool.reward_duration).unwrap();
let b = calculate_reward_rate(funding_amount_b, pool.reward_duration).unwrap();
Ok((a, b))
} else {
let remaining_seconds = reward_period_end.checked_sub(current_time).unwrap();
let leftover_a: u64 = (remaining_seconds as u128)
.checked_mul(pool.reward_a_rate.into())
.checked_mul(pool.get_reward_a_rate())
.unwrap()
.checked_div(PRECISION)
.unwrap()
.try_into()
.unwrap(); //back to u64
let leftover_b: u64 = (remaining_seconds as u128)
.checked_mul(pool.reward_b_rate.into())
.checked_mul(pool.get_reward_b_rate())
.unwrap()
.checked_div(PRECISION)
.unwrap()
Expand All @@ -95,11 +93,10 @@ pub fn rate_after_funding(
let total_a = leftover_a.checked_add(funding_amount_a).unwrap();
let total_b = leftover_b.checked_add(funding_amount_b).unwrap();

a = calculate_reward_rate(total_a, pool.reward_duration).unwrap();
b = calculate_reward_rate(total_b, pool.reward_duration).unwrap();
let a = calculate_reward_rate(total_a, pool.reward_duration).unwrap();
let b = calculate_reward_rate(total_b, pool.reward_duration).unwrap();
Ok((a, b))
}

Ok((a, b))
}

/// Calculate earned reward amount of staking user
Expand Down Expand Up @@ -134,3 +131,17 @@ pub fn user_earned_amount(pool: &Account<Pool>, user: &Account<User>) -> (u64, u

(a, b)
}

#[cfg(test)]
mod overflow_test {
use super::*;
#[test]
fn test_overflow() {
let reward_duration = 1u64;
let funding_amount = u64::MAX;
println!(
"reward rate {}",
calculate_reward_rate(funding_amount, reward_duration).unwrap()
);
}
}
Loading

0 comments on commit c934153

Please sign in to comment.