diff --git a/Cargo.lock b/Cargo.lock index 11819e31..396d4910 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1357,6 +1357,10 @@ dependencies = [ "flat_fee_interface", "sanctum-onchain-utils", "solana-program", + "solana-program-test", + "solana-sdk", + "test-utils", + "tokio", ] [[package]] diff --git a/generated/pricing-programs/flat_fee_interface/src/errors.rs b/generated/pricing-programs/flat_fee_interface/src/errors.rs index b033ca18..6e352393 100644 --- a/generated/pricing-programs/flat_fee_interface/src/errors.rs +++ b/generated/pricing-programs/flat_fee_interface/src/errors.rs @@ -8,10 +8,14 @@ use thiserror::Error; pub enum FlatFeeError { #[error("Invalid program state data")] InvalidProgramStateData = 0, + #[error("Incorrect program state account")] + IncorrectProgramState = 1, #[error("FeeAccount is not initialized for the given LST mint")] - UnsupportedLstMint = 1, + UnsupportedLstMint = 2, + #[error("Given fee value is out of bound")] + SignedFeeOutOfBound = 3, #[error("Math error")] - MathError = 2, + MathError = 4, } impl From for ProgramError { fn from(e: FlatFeeError) -> Self { diff --git a/idl/pricing-programs/flat_fee.json b/idl/pricing-programs/flat_fee.json index 4cec4218..fb75d777 100644 --- a/idl/pricing-programs/flat_fee.json +++ b/idl/pricing-programs/flat_fee.json @@ -410,11 +410,21 @@ }, { "code": 1, + "name": "IncorrectProgramState", + "msg": "Incorrect program state account" + }, + { + "code": 2, "name": "UnsupportedLstMint", "msg": "FeeAccount is not initialized for the given LST mint" }, { - "code": 2, + "code": 3, + "name": "SignedFeeOutOfBound", + "msg": "Given fee value is out of bound" + }, + { + "code": 4, "name": "MathError", "msg": "Math error" } diff --git a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/add_lst.rs b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/add_lst.rs index 3bd4112d..5247c67b 100644 --- a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/add_lst.rs +++ b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/add_lst.rs @@ -2,31 +2,49 @@ use flat_fee_interface::{AddLstKeys, FlatFeeError, ProgramState}; use solana_program::{pubkey::Pubkey, system_program}; use solana_readonly_account::{KeyedAccount, ReadonlyAccountData}; -use crate::{pda::FeeAccountFindPdaArgs, program, utils::try_program_state}; +use crate::{ + pda::{FeeAccountCreatePdaArgs, FeeAccountFindPdaArgs}, + program::STATE_ID, + utils::try_program_state, +}; pub struct AddLstFreeArgs { pub payer: Pubkey, - pub state: S, + pub state_acc: S, pub lst_mint: Pubkey, } impl AddLstFreeArgs { - pub fn resolve(&self) -> Result { - let bytes = &self.state.data(); + pub fn resolve(self) -> Result<(AddLstKeys, FeeAccountCreatePdaArgs), FlatFeeError> { + let AddLstFreeArgs { + payer, + state_acc, + lst_mint, + } = self; + + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; - let find_pda_args = FeeAccountFindPdaArgs { - lst_mint: self.lst_mint, - }; - let (fee_acc, _bump) = find_pda_args.get_fee_account_address_and_bump_seed(); + let find_pda_args = FeeAccountFindPdaArgs { lst_mint }; + let (fee_acc, bump) = find_pda_args.get_fee_account_address_and_bump_seed(); - Ok(AddLstKeys { - manager: state.manager, - payer: self.payer, - fee_acc, - lst_mint: self.lst_mint, - state: program::STATE_ID, - system_program: system_program::ID, - }) + Ok(( + AddLstKeys { + manager: state.manager, + payer, + fee_acc, + lst_mint, + state: STATE_ID, + system_program: system_program::ID, + }, + FeeAccountCreatePdaArgs { + find_pda_args, + bump: [bump], + }, + )) } } diff --git a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/remove_lst.rs b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/remove_lst.rs index 2dda9446..25691eaf 100644 --- a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/remove_lst.rs +++ b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/remove_lst.rs @@ -4,31 +4,41 @@ use solana_readonly_account::{KeyedAccount, ReadonlyAccountData}; use crate::{ pda::{FeeAccountCreatePdaArgs, FeeAccountFindPdaArgs}, - program, + program::STATE_ID, utils::try_program_state, }; -pub struct RemoveLstWithMintFreeArgs { +pub struct RemoveLstByMintFreeArgs { pub refund_rent_to: Pubkey, pub lst_mint: Pubkey, - pub state: S, + pub state_acc: S, } -impl RemoveLstWithMintFreeArgs { - fn resolve_with_fee_acc(&self, fee_acc: Pubkey) -> Result { - let bytes = &self.state.data(); +impl RemoveLstByMintFreeArgs { + fn resolve_with_fee_acc(self, fee_acc: Pubkey) -> Result { + let RemoveLstByMintFreeArgs { + refund_rent_to, + lst_mint: _, + state_acc, + } = self; + + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; Ok(RemoveLstKeys { manager: state.manager, - refund_rent_to: self.refund_rent_to, + refund_rent_to, fee_acc, - state: program::STATE_ID, + state: STATE_ID, system_program: system_program::ID, }) } - pub fn resolve(&self) -> Result { + pub fn resolve(self) -> Result { let find_pda_args = FeeAccountFindPdaArgs { lst_mint: self.lst_mint, }; @@ -37,7 +47,7 @@ impl RemoveLstWithMintFreeArgs { self.resolve_with_fee_acc(fee_acc) } - pub fn resolve_with_fee_acc_bump(&self, bump: u8) -> Result { + pub fn resolve_with_fee_acc_bump(self, bump: u8) -> Result { let create_pda_args = FeeAccountCreatePdaArgs { find_pda_args: FeeAccountFindPdaArgs { lst_mint: self.lst_mint, @@ -55,19 +65,28 @@ impl RemoveLstWithMintFreeArgs { pub struct RemoveLstFreeArgs { pub refund_rent_to: Pubkey, pub fee_acc: Pubkey, - pub state: S, + pub state_acc: S, } impl RemoveLstFreeArgs { - pub fn resolve(&self) -> Result { - let bytes = &self.state.data(); + pub fn resolve(self) -> Result { + let RemoveLstFreeArgs { + refund_rent_to, + fee_acc, + state_acc, + } = self; + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; Ok(RemoveLstKeys { manager: state.manager, - refund_rent_to: self.refund_rent_to, - fee_acc: self.fee_acc, - state: program::STATE_ID, + refund_rent_to, + fee_acc, + state: STATE_ID, system_program: system_program::ID, }) } diff --git a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lp_withdrawal_fee.rs b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lp_withdrawal_fee.rs index 8c6b6f75..5451b7d9 100644 --- a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lp_withdrawal_fee.rs +++ b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lp_withdrawal_fee.rs @@ -1,7 +1,7 @@ use flat_fee_interface::SetLpWithdrawalFeeKeys; use solana_program::pubkey::Pubkey; -use crate::program; +use crate::program::STATE_ID; pub struct SetLpWithdrawalFeeFreeArgs { pub manager: Pubkey, @@ -11,7 +11,7 @@ impl SetLpWithdrawalFeeFreeArgs { pub fn resolve(self) -> SetLpWithdrawalFeeKeys { SetLpWithdrawalFeeKeys { manager: self.manager, - state: program::STATE_ID, + state: STATE_ID, } } } diff --git a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lst_fee.rs b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lst_fee.rs index 3ed39eed..d1e19b8a 100644 --- a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lst_fee.rs +++ b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_lst_fee.rs @@ -4,28 +4,37 @@ use solana_readonly_account::{KeyedAccount, ReadonlyAccountData}; use crate::{ pda::{FeeAccountCreatePdaArgs, FeeAccountFindPdaArgs}, - program, + program::STATE_ID, utils::try_program_state, }; -pub struct SetLstFeeWithMintFreeArgs { +pub struct SetLstFeeByMintFreeArgs { pub lst_mint: Pubkey, - pub state: S, + pub state_acc: S, } -impl SetLstFeeWithMintFreeArgs { - fn resolve_with_fee_acc(&self, fee_acc: Pubkey) -> Result { - let bytes = &self.state.data(); +impl SetLstFeeByMintFreeArgs { + fn resolve_with_fee_acc(self, fee_acc: Pubkey) -> Result { + let SetLstFeeByMintFreeArgs { + lst_mint: _, + state_acc, + } = self; + + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; Ok(SetLstFeeKeys { manager: state.manager, fee_acc, - state: program::STATE_ID, + state: STATE_ID, }) } - pub fn resolve(&self) -> Result { + pub fn resolve(self) -> Result { let find_pda_args = FeeAccountFindPdaArgs { lst_mint: self.lst_mint, }; @@ -34,7 +43,7 @@ impl SetLstFeeWithMintFreeArgs { self.resolve_with_fee_acc(fee_acc) } - pub fn resolve_with_fee_acc_bump(&self, bump: u8) -> Result { + pub fn resolve_with_fee_acc_bump(self, bump: u8) -> Result { let create_pda_args = FeeAccountCreatePdaArgs { find_pda_args: FeeAccountFindPdaArgs { lst_mint: self.lst_mint, @@ -51,18 +60,27 @@ impl SetLstFeeWithMintFreeArgs { pub struct SetLstFeeFreeArgs { pub fee_acc: Pubkey, - pub state: S, + pub state_acc: S, } impl SetLstFeeFreeArgs { - pub fn resolve(&self) -> Result { - let bytes = &self.state.data(); + pub fn resolve(self) -> Result { + let SetLstFeeFreeArgs { + fee_acc: _, + state_acc, + } = self; + + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; Ok(SetLstFeeKeys { manager: state.manager, fee_acc: self.fee_acc, - state: program::STATE_ID, + state: STATE_ID, }) } } diff --git a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_manager.rs b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_manager.rs index 29f19f8f..e7ae6556 100644 --- a/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_manager.rs +++ b/libs/pricing-programs/flat-fee-lib/src/account_resolvers/set_manager.rs @@ -2,22 +2,31 @@ use flat_fee_interface::{FlatFeeError, ProgramState, SetManagerKeys}; use solana_program::pubkey::Pubkey; use solana_readonly_account::{KeyedAccount, ReadonlyAccountData}; -use crate::{program, utils::try_program_state}; +use crate::{program::STATE_ID, utils::try_program_state}; pub struct SetManagerFreeArgs { pub new_manager: Pubkey, - pub state: S, + pub state_acc: S, } impl SetManagerFreeArgs { pub fn resolve(self) -> Result { - let bytes = &self.state.data(); + let SetManagerFreeArgs { + new_manager, + state_acc, + } = self; + + if *state_acc.key() != STATE_ID { + return Err(FlatFeeError::IncorrectProgramState); + } + + let bytes = &state_acc.data(); let state: &ProgramState = try_program_state(bytes)?; Ok(SetManagerKeys { current_manager: state.manager, - new_manager: self.new_manager, - state: program::STATE_ID, + new_manager, + state: STATE_ID, }) } } diff --git a/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_in.rs b/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_in.rs index a925875a..079d2c18 100644 --- a/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_in.rs +++ b/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_in.rs @@ -3,10 +3,19 @@ use sanctum_token_ratio::{U64RatioFloor, BPS_DENOMINATOR}; use super::BPS_DENOMINATOR_I16; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CalculatePriceExactInArgs { + pub input_fee_bps: i16, + pub output_fee_bps: i16, + pub sol_value: u64, +} + pub fn calculate_price_exact_in( - input_fee_bps: i16, - output_fee_bps: i16, - sol_value: u64, + CalculatePriceExactInArgs { + input_fee_bps, + output_fee_bps, + sol_value, + }: CalculatePriceExactInArgs, ) -> Result { let fee_bps = input_fee_bps .checked_add(output_fee_bps) diff --git a/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_out.rs b/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_out.rs index 88e1ee36..9442cc7f 100644 --- a/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_out.rs +++ b/libs/pricing-programs/flat-fee-lib/src/calc/price_exact_out.rs @@ -3,10 +3,18 @@ use sanctum_token_ratio::{U64RatioFloor, BPS_DENOMINATOR}; use super::BPS_DENOMINATOR_I16; +pub struct CalculatePriceExactOut { + pub input_fee_bps: i16, + pub output_fee_bps: i16, + pub sol_value: u64, +} + pub fn calculate_price_exact_out( - input_fee_bps: i16, - output_fee_bps: i16, - sol_value: u64, + CalculatePriceExactOut { + input_fee_bps, + output_fee_bps, + sol_value, + }: CalculatePriceExactOut, ) -> Result { let fee_bps = input_fee_bps .checked_add(output_fee_bps) diff --git a/libs/pricing-programs/flat-fee-lib/src/fee_bound.rs b/libs/pricing-programs/flat-fee-lib/src/fee_bound.rs new file mode 100644 index 00000000..3f96b767 --- /dev/null +++ b/libs/pricing-programs/flat-fee-lib/src/fee_bound.rs @@ -0,0 +1,10 @@ +use flat_fee_interface::FlatFeeError; + +const MAX_FEE_BPS: i16 = 10_000; + +pub fn verify_signed_fee_bps_bound(fee_bps_i16: i16) -> Result<(), FlatFeeError> { + if MAX_FEE_BPS < fee_bps_i16 { + return Err(FlatFeeError::MathError); + } + Ok(()) +} diff --git a/libs/pricing-programs/flat-fee-lib/src/lib.rs b/libs/pricing-programs/flat-fee-lib/src/lib.rs index 224445da..52cf29ea 100644 --- a/libs/pricing-programs/flat-fee-lib/src/lib.rs +++ b/libs/pricing-programs/flat-fee-lib/src/lib.rs @@ -1,5 +1,6 @@ pub mod account_resolvers; pub mod calc; +pub mod fee_bound; pub mod pda; pub mod utils; diff --git a/libs/pricing-programs/flat-fee-lib/src/pda.rs b/libs/pricing-programs/flat-fee-lib/src/pda.rs index 2f5c3587..7f86c1b3 100644 --- a/libs/pricing-programs/flat-fee-lib/src/pda.rs +++ b/libs/pricing-programs/flat-fee-lib/src/pda.rs @@ -18,17 +18,6 @@ impl FeeAccountFindPdaArgs { } } -impl From for FeeAccountCreatePdaArgs { - fn from(find_pda_args: FeeAccountFindPdaArgs) -> Self { - let (_, bump) = find_pda_args.get_fee_account_address_and_bump_seed(); - - Self { - find_pda_args, - bump: [bump], - } - } -} - pub struct FeeAccountCreatePdaArgs { pub find_pda_args: FeeAccountFindPdaArgs, pub bump: [u8; 1], diff --git a/libs/pricing-programs/flat-fee-lib/src/utils.rs b/libs/pricing-programs/flat-fee-lib/src/utils.rs index d860d188..d89124ce 100644 --- a/libs/pricing-programs/flat-fee-lib/src/utils.rs +++ b/libs/pricing-programs/flat-fee-lib/src/utils.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] // DELETEME use bytemuck::{try_from_bytes, try_from_bytes_mut}; use flat_fee_interface::{FeeAccount, FlatFeeError, ProgramState}; @@ -14,10 +13,9 @@ pub fn try_program_state_mut( } pub fn try_fee_account(fee_acc_data: &[u8]) -> Result<&FeeAccount, FlatFeeError> { - try_from_bytes(fee_acc_data).map_err(|_e| FlatFeeError::UnsupportedLstMint) // TODO: should this be InvalidFeeAccountData? + try_from_bytes(fee_acc_data).map_err(|_e| FlatFeeError::UnsupportedLstMint) } pub fn try_fee_account_mut(fee_acc_data: &mut [u8]) -> Result<&mut FeeAccount, FlatFeeError> { try_from_bytes_mut(fee_acc_data).map_err(|_e| FlatFeeError::UnsupportedLstMint) - // TODO: should this be InvalidFeeAccountData? } diff --git a/programs/pricing-programs/flat-fee/Cargo.toml b/programs/pricing-programs/flat-fee/Cargo.toml index e8f61597..2c37db10 100644 --- a/programs/pricing-programs/flat-fee/Cargo.toml +++ b/programs/pricing-programs/flat-fee/Cargo.toml @@ -17,3 +17,9 @@ flat_fee_interface = { path = "../../../generated/pricing-programs/flat_fee_inte flat-fee-lib = { path = "../../../libs/pricing-programs/flat-fee-lib" } sanctum-onchain-utils = { path = "../../../libs/sanctum-onchain-utils" } solana-program = { workspace = true } + +[dev-dependencies] +solana-program-test = { workspace = true } +solana-sdk = { workspace = true } +test-utils = { path = "../../../test-utils"} +tokio = { workspace = true } diff --git a/programs/pricing-programs/flat-fee/src/processor/add_lst.rs b/programs/pricing-programs/flat-fee/src/processor/add_lst.rs index 925f1191..9e36814c 100644 --- a/programs/pricing-programs/flat-fee/src/processor/add_lst.rs +++ b/programs/pricing-programs/flat-fee/src/processor/add_lst.rs @@ -3,9 +3,7 @@ use flat_fee_interface::{ AddLstKeys, }; use flat_fee_lib::{ - account_resolvers::AddLstFreeArgs, - pda::{FeeAccountCreatePdaArgs, FeeAccountFindPdaArgs}, - program, + account_resolvers::AddLstFreeArgs, pda::FeeAccountCreatePdaArgs, program, utils::try_fee_account_mut, }; use sanctum_onchain_utils::{ @@ -23,17 +21,8 @@ pub fn process_add_lst( output_fee_bps, }: AddLstIxArgs, ) -> ProgramResult { - let AddLstAccounts { - payer, - fee_acc, - lst_mint, - .. - } = verify_add_lst(accounts)?; + let (AddLstAccounts { payer, fee_acc, .. }, create_pda_args) = verify_add_lst(accounts)?; - let create_pda_args: FeeAccountCreatePdaArgs = FeeAccountFindPdaArgs { - lst_mint: *lst_mint.key, - } - .into(); create_pda( CreateAccountAccounts { from: payer, @@ -60,18 +49,19 @@ pub fn process_add_lst( fn verify_add_lst<'me, 'info>( accounts: &'me [AccountInfo<'info>], -) -> Result, ProgramError> { +) -> Result<(AddLstAccounts<'me, 'info>, FeeAccountCreatePdaArgs), ProgramError> { let actual: AddLstAccounts = load_accounts(accounts)?; let free_args = AddLstFreeArgs { payer: *actual.payer.key, - state: actual.state, + state_acc: actual.state, lst_mint: *actual.lst_mint.key, }; - let expected: AddLstKeys = free_args.resolve()?; + let (expected, fee_account_create_pda_args): (AddLstKeys, FeeAccountCreatePdaArgs) = + free_args.resolve()?; add_lst_verify_account_keys(&actual, &expected).map_err(log_and_return_wrong_acc_err)?; add_lst_verify_account_privileges(&actual).map_err(log_and_return_acc_privilege_err)?; - Ok(actual) + Ok((actual, fee_account_create_pda_args)) } diff --git a/programs/pricing-programs/flat-fee/src/processor/initialize.rs b/programs/pricing-programs/flat-fee/src/processor/initialize.rs index 1dd9f7b3..4a9957e0 100644 --- a/programs/pricing-programs/flat-fee/src/processor/initialize.rs +++ b/programs/pricing-programs/flat-fee/src/processor/initialize.rs @@ -16,11 +16,7 @@ use solana_program::program_error::ProgramError; use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; pub fn process_initialize(accounts: &[AccountInfo]) -> ProgramResult { - let InitializeAccounts { - payer, - state, - system_program: _, - } = verify_initialize(accounts)?; + let InitializeAccounts { payer, state, .. } = verify_initialize(accounts)?; create_pda( CreateAccountAccounts { diff --git a/programs/pricing-programs/flat-fee/src/processor/price_exact_in.rs b/programs/pricing-programs/flat-fee/src/processor/price_exact_in.rs index 10d953d2..4c80e8fa 100644 --- a/programs/pricing-programs/flat-fee/src/processor/price_exact_in.rs +++ b/programs/pricing-programs/flat-fee/src/processor/price_exact_in.rs @@ -4,7 +4,7 @@ use flat_fee_interface::{ }; use flat_fee_lib::{ account_resolvers::{PriceExactInFreeArgs, PriceExactInWithBumpFreeArgs}, - calc::calculate_price_exact_in, + calc::{calculate_price_exact_in, CalculatePriceExactInArgs}, utils::try_fee_account, }; use sanctum_onchain_utils::utils::{ @@ -17,16 +17,12 @@ use solana_program::{ pub fn process_price_exact_in( accounts: &[AccountInfo], - PriceExactInIxArgs { - amount: _, - sol_value, - }: PriceExactInIxArgs, + PriceExactInIxArgs { sol_value, .. }: PriceExactInIxArgs, ) -> ProgramResult { let PriceExactInAccounts { - input_lst_mint: _, - output_lst_mint: _, input_fee_acc, output_fee_acc, + .. } = verify_price_exact_in(accounts)?; let input_fee_acc_bytes = input_fee_acc.try_borrow_data()?; @@ -34,11 +30,11 @@ pub fn process_price_exact_in( let output_fee_acc_bytes = output_fee_acc.try_borrow_data()?; let output_fee_acc = try_fee_account(&output_fee_acc_bytes)?; - let result = calculate_price_exact_in( - input_fee_acc.input_fee_bps, - output_fee_acc.output_fee_bps, + let result = calculate_price_exact_in(CalculatePriceExactInArgs { + input_fee_bps: input_fee_acc.input_fee_bps, + output_fee_bps: output_fee_acc.output_fee_bps, sol_value, - )?; + })?; let result_le = result.to_le_bytes(); set_return_data(&result_le); diff --git a/programs/pricing-programs/flat-fee/src/processor/price_exact_out.rs b/programs/pricing-programs/flat-fee/src/processor/price_exact_out.rs index f0235011..505f2ccd 100644 --- a/programs/pricing-programs/flat-fee/src/processor/price_exact_out.rs +++ b/programs/pricing-programs/flat-fee/src/processor/price_exact_out.rs @@ -4,7 +4,7 @@ use flat_fee_interface::{ }; use flat_fee_lib::{ account_resolvers::{PriceExactOutFreeArgs, PriceExactOutWithBumpFreeArgs}, - calc::calculate_price_exact_out, + calc::{calculate_price_exact_out, CalculatePriceExactOut}, utils::try_fee_account, }; use sanctum_onchain_utils::utils::{ @@ -17,16 +17,12 @@ use solana_program::{ pub fn process_price_exact_out( accounts: &[AccountInfo], - PriceExactOutIxArgs { - amount: _, - sol_value, - }: PriceExactOutIxArgs, + PriceExactOutIxArgs { sol_value, .. }: PriceExactOutIxArgs, ) -> ProgramResult { let PriceExactOutAccounts { - input_lst_mint: _, - output_lst_mint: _, input_fee_acc, output_fee_acc, + .. } = verify_price_exact_out(accounts)?; let input_fee_acc_bytes = input_fee_acc.try_borrow_data()?; @@ -34,11 +30,11 @@ pub fn process_price_exact_out( let output_fee_acc_bytes = output_fee_acc.try_borrow_data()?; let output_fee_acc = try_fee_account(&output_fee_acc_bytes)?; - let result = calculate_price_exact_out( - input_fee_acc.input_fee_bps, - output_fee_acc.output_fee_bps, + let result = calculate_price_exact_out(CalculatePriceExactOut { + input_fee_bps: input_fee_acc.input_fee_bps, + output_fee_bps: output_fee_acc.output_fee_bps, sol_value, - )?; + })?; let result_le = result.to_le_bytes(); set_return_data(&result_le); diff --git a/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_mint.rs b/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_mint.rs index 203e204e..4d056710 100644 --- a/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_mint.rs +++ b/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_mint.rs @@ -15,13 +15,9 @@ use solana_program::{ pub fn process_price_lp_tokens_to_mint( accounts: &[AccountInfo], - PriceLpTokensToMintIxArgs { - amount: _, - sol_value, - }: PriceLpTokensToMintIxArgs, + PriceLpTokensToMintIxArgs { sol_value, .. }: PriceLpTokensToMintIxArgs, ) -> ProgramResult { - let PriceLpTokensToMintAccounts { input_lst_mint: _ } = - verify_price_lp_tokens_to_mint(accounts)?; + verify_price_lp_tokens_to_mint(accounts)?; let result = calculate_price_lp_tokens_to_mint(sol_value)?; let result_le = result.to_le_bytes(); diff --git a/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_redeem.rs b/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_redeem.rs index 02a92c10..495ba2c2 100644 --- a/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_redeem.rs +++ b/programs/pricing-programs/flat-fee/src/processor/price_lp_tokens_to_redeem.rs @@ -17,15 +17,9 @@ use solana_program::{ pub fn process_price_lp_tokens_to_redeem( accounts: &[AccountInfo], - PriceLpTokensToRedeemIxArgs { - amount: _, - sol_value, - }: PriceLpTokensToRedeemIxArgs, + PriceLpTokensToRedeemIxArgs { sol_value, .. }: PriceLpTokensToRedeemIxArgs, ) -> ProgramResult { - let PriceLpTokensToRedeemAccounts { - output_lst_mint: _, - state, - } = verify_price_lp_tokens_to_redeem(accounts)?; + let PriceLpTokensToRedeemAccounts { state, .. } = verify_price_lp_tokens_to_redeem(accounts)?; let bytes = state.try_borrow_data()?; let state = try_program_state(&bytes)?; diff --git a/programs/pricing-programs/flat-fee/src/processor/remove_lst.rs b/programs/pricing-programs/flat-fee/src/processor/remove_lst.rs index ebeff11f..99cb62c0 100644 --- a/programs/pricing-programs/flat-fee/src/processor/remove_lst.rs +++ b/programs/pricing-programs/flat-fee/src/processor/remove_lst.rs @@ -13,11 +13,9 @@ use solana_program::{ pub fn process_remove_lst(accounts: &[AccountInfo]) -> ProgramResult { let RemoveLstAccounts { - manager: _, fee_acc, - state: _, - system_program: _, refund_rent_to, + .. } = verify_remove_lst(accounts)?; close_account(CloseAccountAccounts { @@ -35,7 +33,7 @@ fn verify_remove_lst<'me, 'info>( let free_args = RemoveLstFreeArgs { refund_rent_to: *actual.refund_rent_to.key, - state: actual.state, + state_acc: actual.state, fee_acc: *actual.fee_acc.key, }; let expected: RemoveLstKeys = free_args.resolve()?; diff --git a/programs/pricing-programs/flat-fee/src/processor/set_lp_withdrawal_fee.rs b/programs/pricing-programs/flat-fee/src/processor/set_lp_withdrawal_fee.rs index 23cdd3ad..19732c0c 100644 --- a/programs/pricing-programs/flat-fee/src/processor/set_lp_withdrawal_fee.rs +++ b/programs/pricing-programs/flat-fee/src/processor/set_lp_withdrawal_fee.rs @@ -16,7 +16,7 @@ pub fn process_set_lp_withdrawal_fee( lp_withdrawal_fee_bps, }: SetLpWithdrawalFeeIxArgs, ) -> ProgramResult { - let SetLpWithdrawalFeeAccounts { manager: _, state } = verify_set_lp_withdrawal_fee(accounts)?; + let SetLpWithdrawalFeeAccounts { state, .. } = verify_set_lp_withdrawal_fee(accounts)?; let mut bytes = state.try_borrow_mut_data()?; let state = try_program_state_mut(&mut bytes)?; diff --git a/programs/pricing-programs/flat-fee/src/processor/set_lst_fee.rs b/programs/pricing-programs/flat-fee/src/processor/set_lst_fee.rs index ed0b5a50..c39e97cc 100644 --- a/programs/pricing-programs/flat-fee/src/processor/set_lst_fee.rs +++ b/programs/pricing-programs/flat-fee/src/processor/set_lst_fee.rs @@ -2,7 +2,10 @@ use flat_fee_interface::{ set_lst_fee_verify_account_keys, set_lst_fee_verify_account_privileges, SetLstFeeAccounts, SetLstFeeIxArgs, SetLstFeeKeys, }; -use flat_fee_lib::{account_resolvers::SetLstFeeFreeArgs, utils::try_fee_account_mut}; +use flat_fee_lib::{ + account_resolvers::SetLstFeeFreeArgs, fee_bound::verify_signed_fee_bps_bound, + utils::try_fee_account_mut, +}; use sanctum_onchain_utils::utils::{ load_accounts, log_and_return_acc_privilege_err, log_and_return_wrong_acc_err, }; @@ -10,18 +13,12 @@ use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, }; -pub fn process_set_lst_fee( - accounts: &[AccountInfo], - SetLstFeeIxArgs { +pub fn process_set_lst_fee(accounts: &[AccountInfo], args: SetLstFeeIxArgs) -> ProgramResult { + let SetLstFeeAccounts { fee_acc, .. } = verify_set_lst_fee(accounts, &args)?; + let SetLstFeeIxArgs { input_fee_bps, output_fee_bps, - }: SetLstFeeIxArgs, -) -> ProgramResult { - let SetLstFeeAccounts { - manager: _, - fee_acc, - state: _, - } = verify_set_lst_fee(accounts)?; + } = args; let mut bytes = fee_acc.try_borrow_mut_data()?; let fee_acc = try_fee_account_mut(&mut bytes)?; @@ -34,11 +31,12 @@ pub fn process_set_lst_fee( fn verify_set_lst_fee<'me, 'info>( accounts: &'me [AccountInfo<'info>], + args: &SetLstFeeIxArgs, ) -> Result, ProgramError> { let actual: SetLstFeeAccounts = load_accounts(accounts)?; let free_args = SetLstFeeFreeArgs { - state: actual.state, + state_acc: actual.state, fee_acc: *actual.fee_acc.key, }; let expected: SetLstFeeKeys = free_args.resolve()?; @@ -46,5 +44,8 @@ fn verify_set_lst_fee<'me, 'info>( set_lst_fee_verify_account_keys(&actual, &expected).map_err(log_and_return_wrong_acc_err)?; set_lst_fee_verify_account_privileges(&actual).map_err(log_and_return_acc_privilege_err)?; + verify_signed_fee_bps_bound(args.input_fee_bps)?; + verify_signed_fee_bps_bound(args.output_fee_bps)?; + Ok(actual) } diff --git a/programs/pricing-programs/flat-fee/src/processor/set_manager.rs b/programs/pricing-programs/flat-fee/src/processor/set_manager.rs index 625710fe..c8fc8376 100644 --- a/programs/pricing-programs/flat-fee/src/processor/set_manager.rs +++ b/programs/pricing-programs/flat-fee/src/processor/set_manager.rs @@ -12,9 +12,7 @@ use solana_program::{ pub fn process_set_manager(accounts: &[AccountInfo]) -> ProgramResult { let SetManagerAccounts { - current_manager: _, - new_manager, - state, + new_manager, state, .. } = verify_set_manager(accounts)?; let mut bytes = state.try_borrow_mut_data()?; @@ -32,7 +30,7 @@ fn verify_set_manager<'me, 'info>( let free_args = SetManagerFreeArgs { new_manager: *actual.new_manager.key, - state: actual.state, + state_acc: actual.state, }; let expected: SetManagerKeys = free_args.resolve()?; diff --git a/programs/pricing-programs/flat-fee/tests/common/mod.rs b/programs/pricing-programs/flat-fee/tests/common/mod.rs new file mode 100644 index 00000000..06b8a47a --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/common/mod.rs @@ -0,0 +1,3 @@ +mod state; + +pub use state::*; diff --git a/programs/pricing-programs/flat-fee/tests/common/state.rs b/programs/pricing-programs/flat-fee/tests/common/state.rs new file mode 100644 index 00000000..e3090444 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/common/state.rs @@ -0,0 +1,39 @@ +use flat_fee_interface::ProgramState; +use flat_fee_lib::{ + initial_constants::{initial_manager, INITIAL_LP_WITHDRAWAL_FEE_BPS}, + program::STATE_SIZE, + utils::try_program_state_mut, +}; +use solana_sdk::account::Account; +use test_utils::est_rent_exempt_lamports; + +pub const DEFAULT_PROGRAM_STATE: ProgramState = ProgramState { + manager: initial_manager::ID, + lp_withdrawal_fee_bps: INITIAL_LP_WITHDRAWAL_FEE_BPS, +}; +// total_sol_value: 0, +// trading_protocol_fee_bps: 0, +// lp_protocol_fee_bps: 0, +// version: 0, +// is_disabled: 0, +// is_rebalancing: 0, +// padding: [0u8; 1], +// admin: initial_authority::ID, +// rebalance_authority: initial_authority::ID, +// protocol_fee_beneficiary: initial_authority::ID, +// pricing_program: DEFAULT_PRICING_PROGRAM, +// lp_token_mint: Pubkey::new_from_array([0u8; 32]), +// }; + +pub fn program_state_to_account(state: ProgramState) -> Account { + let mut data = vec![0u8; STATE_SIZE]; + let dst = try_program_state_mut(&mut data).unwrap(); + *dst = state; + Account { + lamports: est_rent_exempt_lamports(STATE_SIZE), + data, + owner: flat_fee_lib::program::ID, + executable: false, + rent_epoch: u64::MAX, + } +} diff --git a/programs/pricing-programs/flat-fee/tests/mod.rs b/programs/pricing-programs/flat-fee/tests/mod.rs new file mode 100644 index 00000000..908799a7 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/mod.rs @@ -0,0 +1,2 @@ +mod common; +mod tests; diff --git a/programs/pricing-programs/flat-fee/tests/tests/add_lst.rs b/programs/pricing-programs/flat-fee/tests/tests/add_lst.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/add_lst.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/initialize.rs b/programs/pricing-programs/flat-fee/tests/tests/initialize.rs new file mode 100644 index 00000000..49b4f3af --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/initialize.rs @@ -0,0 +1,24 @@ +use solana_program_test::{processor, ProgramTest}; + +use crate::common::*; + +#[tokio::test] +async fn basic() { + let mut program_test = ProgramTest::default(); + program_test.add_program( + "flat_fee", + flat_fee_lib::program::ID, + processor!(flat_fee::entrypoint::process_instruction), + ); + + let program_state_account = program_state_to_account(DEFAULT_PROGRAM_STATE); + program_test.add_account( + flat_fee_lib::program::STATE_ID, + program_state_account.clone(), + ); + + let (mut banks_client, payer, last_blockhash) = program_test.start().await; + + // TODO: write test + {} +} diff --git a/programs/pricing-programs/flat-fee/tests/tests/mod.rs b/programs/pricing-programs/flat-fee/tests/tests/mod.rs new file mode 100644 index 00000000..9f4b030f --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/mod.rs @@ -0,0 +1,10 @@ +mod add_lst; +mod initialize; +mod price_exact_in; +mod price_exact_out; +mod price_lp_tokens_to_mint; +mod price_lp_tokens_to_redeem; +mod remove_lst; +mod set_lp_withdrawal_fee; +mod set_lst_fee; +mod set_manager; diff --git a/programs/pricing-programs/flat-fee/tests/tests/price_exact_in.rs b/programs/pricing-programs/flat-fee/tests/tests/price_exact_in.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/price_exact_in.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/price_exact_out.rs b/programs/pricing-programs/flat-fee/tests/tests/price_exact_out.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/price_exact_out.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_mint.rs b/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_mint.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_mint.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_redeem.rs b/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_redeem.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/price_lp_tokens_to_redeem.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/remove_lst.rs b/programs/pricing-programs/flat-fee/tests/tests/remove_lst.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/remove_lst.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/set_lp_withdrawal_fee.rs b/programs/pricing-programs/flat-fee/tests/tests/set_lp_withdrawal_fee.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/set_lp_withdrawal_fee.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/set_lst_fee.rs b/programs/pricing-programs/flat-fee/tests/tests/set_lst_fee.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/set_lst_fee.rs @@ -0,0 +1 @@ + diff --git a/programs/pricing-programs/flat-fee/tests/tests/set_manager.rs b/programs/pricing-programs/flat-fee/tests/tests/set_manager.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/programs/pricing-programs/flat-fee/tests/tests/set_manager.rs @@ -0,0 +1 @@ +