diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs new file mode 100644 index 000000000..b7ed50207 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -0,0 +1,12 @@ +use {crate::TOKEN_COUNT, anchor_lang::prelude::*, two_pool::BorshDecimal}; + +pub trait Fees { + fn calculate_fees_in_lamports(&self) -> Result; + fn convert_fees_to_swim_usd_atomic( + &self, + fee_in_lamports: u64, + marginal_prices: [BorshDecimal; TOKEN_COUNT], + max_staleness: i64, + ) -> Result; + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()>; +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/create_owner_token_accounts.rs b/packages/solana-contracts/programs/propeller/src/instructions/create_owner_token_accounts.rs index 554c547dc..0dc5d19ec 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/create_owner_token_accounts.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/create_owner_token_accounts.rs @@ -2,9 +2,9 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_ use { crate::{ constants::LAMPORTS_PER_SOL_DECIMAL, - convert_fees_to_swim_usd_atomic, deserialize_message_payload, + convert_fees_to_swim_usd_atomic, convert_fees_to_swim_usd_atomic_2, deserialize_message_payload, error::*, - get_lamports_intermediate_token_price, get_marginal_price_decimal, get_marginal_prices, get_message_data, + get_lamports_intermediate_token_price, get_marginal_price_decimal, get_message_data, get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, @@ -160,8 +160,11 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { seeds::program = two_pool_program.key() )] pub marginal_price_pool: Box>, + #[account(address = marginal_price_pool.token_keys[0])] pub marginal_price_pool_token_0_account: Box>, + #[account(address = marginal_price_pool.token_keys[1])] pub marginal_price_pool_token_1_account: Box>, + #[account(address = marginal_price_pool.lp_mint_key)] pub marginal_price_pool_lp_mint: Box>, pub two_pool_program: Program<'info, two_pool::program::TwoPool>, @@ -175,27 +178,14 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { require_keys_eq!(ctx.accounts.user.key(), ctx.accounts.swim_payload_message.owner); require_keys_eq!(ctx.accounts.pool.key(), ctx.accounts.token_id_map.pool); let propeller = &ctx.accounts.propeller; - validate_marginal_prices_pool_accounts( + validate_marginal_prices_pool_accounts_2( &propeller, - &ctx.accounts.marginal_price_pool.key(), - &[ - ctx.accounts.marginal_price_pool_token_0_account.mint, - ctx.accounts.marginal_price_pool_token_1_account.mint, - ], + &ctx.accounts.marginal_price_pool, + &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], )?; msg!("Passed PropellerCreateOwnerTokenAccounts::accounts() check"); Ok(()) } - pub fn validate(&self) -> Result<()> { - require_keys_eq!(self.user.key(), self.swim_payload_message.owner); - let expected_user_token_0_ata = get_associated_token_address(&self.user.key(), &self.pool_token_0_mint.key()); - require_keys_eq!(expected_user_token_0_ata, self.user_pool_token_0_account.key()); - let expected_user_token_1_ata = get_associated_token_address(&self.user.key(), &self.pool_token_1_mint.key()); - require_keys_eq!(expected_user_token_1_ata, self.user_pool_token_1_account.key()); - let expected_user_lp_ata = get_associated_token_address(&self.user.key(), &self.pool_lp_mint.key()); - require_keys_eq!(expected_user_lp_ata, self.user_lp_token_account.key()); - Ok(()) - } fn into_marginal_prices(&self) -> CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>> { let program = self.two_pool_program.to_account_info(); @@ -208,6 +198,61 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { CpiContext::new(program, accounts) } + fn calculate_fees_in_lamports(&self) -> Result { + let mut create_owner_token_account_total_fees_in_lamports = 0u64; + + let init_ata_fee = self.propeller.init_ata_fee; + let token_program = self.token_program.to_account_info(); + let payer = self.payer.to_account_info(); + let user = self.user.to_account_info(); + let system_program = self.system_program.to_account_info(); + let init_token_account_0_fees = initialize_user_ata_and_get_fees( + self.user_pool_token_0_account.to_account_info().clone(), + payer.clone(), + user.clone(), + self.pool_token_0_mint.to_account_info().clone(), + system_program.clone(), + token_program.clone(), + init_ata_fee, + )?; + let init_token_account_1_fees = initialize_user_ata_and_get_fees( + self.user_pool_token_1_account.to_account_info().clone(), + payer.clone(), + user.clone(), + self.pool_token_1_mint.to_account_info().clone(), + system_program.clone(), + token_program.clone(), + init_ata_fee, + )?; + let init_lp_token_account_fees = initialize_user_ata_and_get_fees( + self.user_lp_token_account.to_account_info().clone(), + payer.clone(), + user.clone(), + self.pool_lp_mint.to_account_info().clone(), + system_program.clone(), + token_program.clone(), + init_ata_fee, + )?; + create_owner_token_account_total_fees_in_lamports = init_token_account_0_fees + .checked_add(init_token_account_1_fees) + .and_then(|f| f.checked_add(init_lp_token_account_fees)) + .ok_or(PropellerError::IntegerOverflow)?; + + msg!( + " + {}(init_token_account_0_fees) + + {}(init_token_account_1_fees) + + {}(init_lp_token_account_fees) + = {}(create_owner_token_account_total_fees_in_lamports) + ", + init_token_account_0_fees, + init_token_account_1_fees, + init_lp_token_account_fees, + create_owner_token_account_total_fees_in_lamports + ); + Ok(create_owner_token_account_total_fees_in_lamports) + } + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { let fee_tracker = &mut self.fee_tracker; let updated_fees_owed = @@ -245,9 +290,9 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { /// we penalize the engine by not reimbursing them anything in that situation so that they are incentivized to /// check if any of the require token accounts don't exist. pub fn handle_propeller_create_owner_token_accounts(ctx: Context) -> Result<()> { - let mut create_owner_token_account_total_fees_in_lamports = 0u64; //TODO: enforce that this step can only be done after CompleteNativeWithPayload is done? - // + // -> no way to have a `swim_payload_message` if not done yet. + // let claim_data = ClaimData::try_from_slice(&mut ctx.accounts.claim.data.borrow()) // .map_err(|_| error!(PropellerError::InvalidClaimData))?; // require!(claim_data.claimed, PropellerError::ClaimNotClaimed); @@ -272,56 +317,7 @@ pub fn handle_propeller_create_owner_token_accounts(ctx: Context( } } -fn get_fees_in_swim_usd(fee_in_lamports: u64, ctx: &Context) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - - let propeller = &ctx.accounts.propeller; - let lp_mint_key = ctx.accounts.marginal_price_pool_lp_mint.key(); - - let swim_usd_mint_key = propeller.swim_usd_mint; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::MarginalPrices { - pool: ctx.accounts.marginal_price_pool.to_account_info(), - pool_token_account_0: ctx.accounts.marginal_price_pool_token_0_account.to_account_info(), - pool_token_account_1: ctx.accounts.marginal_price_pool_token_1_account.to_account_info(), - lp_mint: ctx.accounts.marginal_price_pool_lp_mint.to_account_info(), - }, - ); - let result = two_pool::cpi::marginal_prices(cpi_ctx)?; - // let marginal_prices = result.get().marginal_prices; - let marginal_prices = result.get(); - - msg!("marginal_prices: {:?}", marginal_prices); - - let marginal_price: Decimal = get_marginal_price_decimal( - &ctx.accounts.marginal_price_pool, - &marginal_prices, - &propeller, - // propeller.marginal_price_pool_token_index as usize, - &ctx.accounts.marginal_price_pool_lp_mint.key(), - // &token_bridge_mint_key, - )?; - msg!("marginal_price: {}", marginal_price); - - //swimUSD is lp token of marginal price pool - let mut res = 0u64; - let feed = &ctx.accounts.aggregator.load()?; - - // get result - // note - for tests this is currently hardcoded to 100 - // this val is SOL/USD price - // 100 => 1 SOL/100 USD (usdc) - // let v2 = feed.get_result()?.try_into()?; - let sol_usd_price: Decimal = feed.get_result()?.try_into()?; - let name = feed.name; - - let lamports_usd_price = - sol_usd_price.checked_div(LAMPORTS_PER_SOL_DECIMAL).ok_or(PropellerError::IntegerOverflow)?; - msg!("sol_usd_price:{},lamports_usd_price: {}", sol_usd_price, lamports_usd_price); - // check whether the feed has been updated in the last 300 seconds - feed.check_staleness( - Clock::get().unwrap().unix_timestamp, - // 300 - i64::MAX, - ) - .map_err(|_| error!(PropellerError::StaleFeed))?; - // check feed does not exceed max_confidence_interval - // if let Some(max_confidence_interval) = params.max_confidence_interval { - // feed.check_confidence_interval(SwitchboardDecimal::from_f64(max_confidence_interval)) - // .map_err(|_| error!(PropellerError::ConfidenceIntervalExceeded))?; - // } - - let fee_in_lamports_decimal = Decimal::from_u64(fee_in_lamports).ok_or(PropellerError::ConversionError)?; - msg!("fee_in_lamports(u64): {:?} fee_in_lamports_decimal: {:?}", fee_in_lamports, fee_in_lamports_decimal); - let fee_in_swim_usd_decimal = marginal_price - .checked_mul(lamports_usd_price) - .and_then(|v| v.checked_mul(fee_in_lamports_decimal)) - .ok_or(PropellerError::IntegerOverflow)?; - // .checked_mul(Decimal::from_u64(fee_in_lamports).ok_or(PropellerError::IntegerOverflow)?) - // .ok_or(PropellerError::IntegerOverflow)?; - let swim_usd_mint_decimals = get_swim_usd_mint_decimals( - &swim_usd_mint_key, - &ctx.accounts.marginal_price_pool, - &ctx.accounts.marginal_price_pool_lp_mint, - )?; - msg!("swim_usd_mint_decimals: {:?}", swim_usd_mint_decimals); - - let ten_pow_decimals = - Decimal::from_u64(10u64.pow(swim_usd_mint_decimals as u32)).ok_or(PropellerError::IntegerOverflow)?; - let fee_in_swim_usd_atomic = fee_in_swim_usd_decimal - .checked_mul(ten_pow_decimals) - .and_then(|v| v.to_u64()) - .ok_or(PropellerError::ConversionError)?; - - msg!("fee_in_swim_usd_decimal: {:?} fee_in_swim_usd_atomic: {:?}", fee_in_swim_usd_decimal, fee_in_swim_usd_atomic); - res = fee_in_swim_usd_atomic; - Ok(res) -} - #[derive(Accounts)] pub struct PropellerCreateOwnerSwimUsdAta<'info> { #[account( @@ -567,6 +486,15 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { )] pub swim_payload_message: Box>, + #[account( + seeds = [ + b"propeller".as_ref(), + b"token_id".as_ref(), + propeller.key().as_ref(), + &swim_payload_message.target_token_id.to_le_bytes() + ], + bump, + )] /// CHECK: Unchecked b/c if target_token_id is invalid then this account should not exist/be able to be /// deserialized as a `TokenIdMap`. if it does exist, then engine should have called /// propeller_create_owner_token_accounts instead @@ -625,17 +553,22 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { pub fn accounts(ctx: &Context) -> Result<()> { require_keys_eq!(ctx.accounts.owner.key(), ctx.accounts.swim_payload_message.owner); - let (expected_token_id_map_address, _bump) = Pubkey::find_program_address( - &[ - b"propeller".as_ref(), - b"token_id".as_ref(), - ctx.accounts.propeller.key().as_ref(), - ctx.accounts.swim_payload_message.target_token_id.to_le_bytes().as_ref(), - ], - ctx.program_id, - ); - //Note: the address should at least be valid even though it doesn't exist. - require_keys_eq!(expected_token_id_map_address, ctx.accounts.token_id_map.key()); + // let (expected_token_id_map_address, _bump) = Pubkey::find_program_address( + // &[ + // b"propeller".as_ref(), + // b"token_id".as_ref(), + // ctx.accounts.propeller.key().as_ref(), + // ctx.accounts.swim_payload_message.target_token_id.to_le_bytes().as_ref(), + // ], + // ctx.program_id, + // ); + // //Note: the address should at least be valid even though it doesn't exist. + // require_keys_eq!(expected_token_id_map_address, ctx.accounts.token_id_map.key()); + TokenIdMap::assert_is_invalid(&ctx.accounts.token_id_map.to_account_info())?; + // let token_id_map = &ctx.accounts.token_id_map; + // if let Ok(_) = TokenIdMap::try_deserialize(&mut &**token_id_map.try_borrow_mut_data()?) { + // return err!(PropellerError::TokenIdMapExists); + // } let propeller = &ctx.accounts.propeller; validate_marginal_prices_pool_accounts( &propeller, @@ -660,53 +593,12 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { CpiContext::new(program, accounts) } - pub fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - let propeller = &self.propeller; - - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - - let swim_usd_mint_key = propeller.swim_usd_mint; - let marginal_prices = get_marginal_prices(self.into_marginal_prices())?; - - let intermediate_token_price_decimal: Decimal = get_marginal_price_decimal( - &self.marginal_price_pool, - &marginal_prices, - &propeller, - &marginal_price_pool_lp_mint.key(), - )?; - - msg!("intermediate_token_price_decimal: {:?}", intermediate_token_price_decimal); - - let fee_in_lamports_decimal = Decimal::from_u64(fee_in_lamports).ok_or(PropellerError::ConversionError)?; - msg!("fee_in_lamports(u64): {:?} fee_in_lamports_decimal: {:?}", fee_in_lamports, fee_in_lamports_decimal); - - let mut res = 0u64; - - let lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.aggregator, i64::MAX)?; - let fee_in_swim_usd_decimal = lamports_intermediate_token_price - .checked_mul(fee_in_lamports_decimal) - .and_then(|x| x.checked_div(intermediate_token_price_decimal)) + fn calculate_fees_in_lamports(&self) -> Result { + let fees_in_lamports = Rent::get()? + .minimum_balance(TokenAccount::LEN) + .checked_add(self.propeller.init_ata_fee) .ok_or(PropellerError::IntegerOverflow)?; - - let swim_usd_decimals = - get_swim_usd_mint_decimals(&swim_usd_mint_key, &self.marginal_price_pool, &marginal_price_pool_lp_mint)?; - msg!("swim_usd_decimals: {:?}", swim_usd_decimals); - - let ten_pow_decimals = - Decimal::from_u64(10u64.pow(swim_usd_decimals as u32)).ok_or(PropellerError::IntegerOverflow)?; - let fee_in_swim_usd_atomic = fee_in_swim_usd_decimal - .checked_mul(ten_pow_decimals) - .and_then(|v| v.to_u64()) - .ok_or(PropellerError::ConversionError)?; - - msg!( - "fee_in_swim_usd_decimal: {:?} fee_in_swim_usd_atomic: {:?}", - fee_in_swim_usd_decimal, - fee_in_swim_usd_atomic - ); - res = fee_in_swim_usd_atomic; - Ok(res) + Ok(fees_in_lamports) } pub fn handle_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { @@ -732,22 +624,19 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { } pub fn handle_propeller_create_owner_swim_usd_ata(ctx: Context) -> Result<()> { - let token_id_map = &ctx.accounts.token_id_map; - if let Ok(_) = TokenIdMap::try_deserialize(&mut &**token_id_map.try_borrow_mut_data()?) { - return err!(PropellerError::TokenIdMapExists); - } - - let fees_in_lamports = Rent::get()? - .minimum_balance(TokenAccount::LEN) - .checked_add(ctx.accounts.propeller.init_ata_fee) - .ok_or(PropellerError::IntegerOverflow)?; + let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + // let fees_in_lamports = Rent::get()? + // .minimum_balance(TokenAccount::LEN) + // .checked_add(ctx.accounts.propeller.init_ata_fee) + // .ok_or(PropellerError::IntegerOverflow)?; // let init_token_bridge_ata_total_fee_in_token_bridge_mint = // ctx.accounts.convert_fees_to_swim_usd_atomic(fee_in_lamports)?; - let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic( + let marginal_prices = two_pool::cpi::marginal_prices(ctx.accounts.into_marginal_prices())?; + let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic_2( fees_in_lamports, &ctx.accounts.propeller, &ctx.accounts.marginal_price_pool_lp_mint, - ctx.accounts.into_marginal_prices(), + marginal_prices.get(), &ctx.accounts.marginal_price_pool, &ctx.accounts.aggregator, i64::MAX, diff --git a/packages/solana-contracts/programs/propeller/src/instructions/process_swim_payload.rs b/packages/solana-contracts/programs/propeller/src/instructions/process_swim_payload.rs index 895443a83..f38ba9e90 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/process_swim_payload.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/process_swim_payload.rs @@ -37,6 +37,10 @@ use { std::convert::TryInto, two_pool::state::TwoPool, }; +use { + crate::{convert_fees_to_swim_usd_atomic_2, get_lamports_intermediate_token_price, Fees}, + two_pool::BorshDecimal, +}; pub const SWIM_USD_TO_TOKEN_NUMBER: u16 = 0; @@ -473,7 +477,27 @@ impl<'info> PropellerProcessSwimPayload<'info> { /// Calculates, transfer and tracks fees /// returns fees_in_token_bridge_mint fn handle_fees(&mut self) -> Result { - let fees_in_swim_usd_atomic = self.calculate_fees()?; + let fees_in_lamports = self.calculate_fees_in_lamports()?; + let marginal_prices = two_pool::cpi::marginal_prices(CpiContext::new( + self.process_swim_payload.two_pool_program.to_account_info(), + two_pool::cpi::accounts::MarginalPrices { + pool: self.marginal_price_pool.to_account_info(), + pool_token_account_0: self.marginal_price_pool_token_0_account.to_account_info(), + pool_token_account_1: self.marginal_price_pool_token_1_account.to_account_info(), + lp_mint: self.marginal_price_pool_lp_mint.to_account_info(), + }, + ))?; + let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic_2( + fees_in_lamports, + &self.process_swim_payload.propeller, + &self.marginal_price_pool_lp_mint, + marginal_prices.get(), + &self.marginal_price_pool, + &self.aggregator, + i64::MAX, + )?; + // let fees_in_swim_usd_atomic = + // let fees_in_swim_usd_atomic = self.calculate_fees()?; let propeller = &self.process_swim_payload.propeller; let token_program = &self.process_swim_payload.token_program; msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); @@ -496,7 +520,7 @@ impl<'info> PropellerProcessSwimPayload<'info> { Ok(fees_in_swim_usd_atomic) } - fn calculate_fees(&self) -> Result { + fn calculate_fees_in_lamports(&self) -> Result { //TODO: this is in lamports/SOL. need in swimUSD. // for (secp + verify) & postVAA, need to implement a fee tracking mechanism since there's no way to // credit the payer during that step. must be some type of "deferred" fees @@ -506,12 +530,6 @@ impl<'info> PropellerProcessSwimPayload<'info> { let swim_payload_message = &self.process_swim_payload.swim_payload_message; let propeller_process_swim_payload_fees = propeller.process_swim_payload_fee; - let two_pool_program = &self.process_swim_payload.two_pool_program; - let marginal_price_pool = &self.marginal_price_pool; - let marginal_price_pool_token_0_account = &self.marginal_price_pool_token_0_account; - let marginal_price_pool_token_1_account = &self.marginal_price_pool_token_1_account; - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - let swim_claim_rent_exempt_fees = rent.minimum_balance(8 + SwimClaim::LEN); let gas_kickstart_amount = if swim_payload_message.gas_kickstart { propeller.gas_kickstart_amount } else { 0 }; let fee_in_lamports = swim_claim_rent_exempt_fees @@ -531,23 +549,28 @@ impl<'info> PropellerProcessSwimPayload<'info> { gas_kickstart_amount, fee_in_lamports ); + Ok(fee_in_lamports) + } - let cpi_ctx = CpiContext::new( - two_pool_program.to_account_info(), + fn calculate_fees(&self) -> Result { + let fee_in_lamports = self.calculate_fees_in_lamports()?; + + let marginal_prices = two_pool::cpi::marginal_prices(CpiContext::new( + self.process_swim_payload.two_pool_program.to_account_info(), two_pool::cpi::accounts::MarginalPrices { - pool: marginal_price_pool.to_account_info(), - pool_token_account_0: marginal_price_pool_token_0_account.to_account_info(), - pool_token_account_1: marginal_price_pool_token_1_account.to_account_info(), - lp_mint: marginal_price_pool_lp_mint.to_account_info(), + pool: self.marginal_price_pool.to_account_info(), + pool_token_account_0: self.marginal_price_pool_token_0_account.to_account_info(), + pool_token_account_1: self.marginal_price_pool_token_1_account.to_account_info(), + lp_mint: self.marginal_price_pool_lp_mint.to_account_info(), }, - ); - let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic( + ))?; + + let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic_2( fee_in_lamports, - &propeller, - &marginal_price_pool_lp_mint, - // ctx.accounts.into_marginal_prices(), - cpi_ctx, - &marginal_price_pool, + &self.process_swim_payload.propeller, + &self.marginal_price_pool_lp_mint, + marginal_prices.get(), + &self.marginal_price_pool, &self.aggregator, i64::MAX, )?; @@ -802,17 +825,14 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { impl<'info> PropellerProcessSwimPayloadFallback<'info> { pub fn accounts(ctx: &Context) -> Result<()> { require_keys_eq!(ctx.accounts.owner.key(), ctx.accounts.swim_payload_message.owner); - let (expected_token_id_map_address, _bump) = Pubkey::find_program_address( + validate_marginal_prices_pool_accounts( + &ctx.accounts.propeller, + &ctx.accounts.marginal_price_pool.key(), &[ - b"propeller".as_ref(), - b"token_id".as_ref(), - ctx.accounts.propeller.key().as_ref(), - ctx.accounts.swim_payload_message.target_token_id.to_le_bytes().as_ref(), + ctx.accounts.marginal_price_pool_token_0_account.mint, + ctx.accounts.marginal_price_pool_token_1_account.mint, ], - ctx.program_id, - ); - //Note: the address should at least be valid even though it doesn't exist. - require_keys_eq!(expected_token_id_map_address, ctx.accounts.token_id_map.key()); + )?; msg!("Passed PropellerProcessSwimPayloadFallback::accounts() check"); Ok(()) } @@ -1022,6 +1042,116 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { } } +/* +impl Fees for PropellerProcessSwimPayloadFallback { + fn calculate_fees_in_lamports(&self) -> Result { + let rent = Rent::get()?; + + let propeller = &self.propeller; + let swim_payload_message = &self.swim_payload_message; + let propeller_process_swim_payload_fees = propeller.process_swim_payload_fee; + + let two_pool_program = &self.two_pool_program; + let marginal_price_pool = &self.marginal_price_pool; + let marginal_price_pool_token_0_account = &self.marginal_price_pool_token_0_account; + let marginal_price_pool_token_1_account = &self.marginal_price_pool_token_1_account; + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + + let swim_claim_rent_exempt_fees = rent.minimum_balance(8 + SwimClaim::LEN); + let gas_kickstart_amount = if swim_payload_message.gas_kickstart { propeller.gas_kickstart_amount } else { 0 }; + let fee_in_lamports = swim_claim_rent_exempt_fees + .checked_add(propeller_process_swim_payload_fees) + .and_then(|x| x.checked_add(gas_kickstart_amount)) + .ok_or(PropellerError::IntegerOverflow)?; + + msg!( + " + {}(swim_claim_rent_exempt_fees) + + {}(propeller_process_swim_payload_fees) + + {}(gas_kickstart_amount) + = {}(fee_in_lamports) + ", + swim_claim_rent_exempt_fees, + propeller_process_swim_payload_fees, + gas_kickstart_amount, + fee_in_lamports + ); + Ok(fee_in_lamports) + } + + fn convert_fees_to_swim_usd_atomic( + &self, + fee_in_lamports: u64, + marginal_prices: [BorshDecimal; TOKEN_COUNT], + max_staleness: i64, + ) -> Result { + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + + let swim_usd_mint_key = self.propeller.swim_usd_mint; + // let marginal_prices = get_marginal_prices(cpi_ctx)?; + + let intermediate_token_price_decimal: Decimal = get_marginal_price_decimal( + &self.marginal_price_pool, + &marginal_prices, + &self.propeller, + &marginal_price_pool_lp_mint.key(), + )?; + + msg!("intermediate_token_price_decimal: {:?}", intermediate_token_price_decimal); + + let fee_in_lamports_decimal = Decimal::from_u64(fee_in_lamports).ok_or(PropellerError::ConversionError)?; + msg!("fee_in_lamports(u64): {:?} fee_in_lamports_decimal: {:?}", fee_in_lamports, fee_in_lamports_decimal); + + let mut res = 0u64; + + let lamports_intermediate_token_price = get_lamports_intermediate_token_price(&aggregator, max_staleness)?; + let fee_in_swim_usd_decimal = lamports_intermediate_token_price + .checked_mul(fee_in_lamports_decimal) + .and_then(|x| x.checked_div(intermediate_token_price_decimal)) + .ok_or(PropellerError::IntegerOverflow)?; + + let swim_usd_decimals = + get_swim_usd_mint_decimals(&swim_usd_mint_key, &marginal_price_pool, &marginal_price_pool_lp_mint)?; + msg!("swim_usd_decimals: {:?}", swim_usd_decimals); + + let ten_pow_decimals = + Decimal::from_u64(10u64.pow(swim_usd_decimals as u32)).ok_or(PropellerError::IntegerOverflow)?; + let fee_in_swim_usd_atomic = fee_in_swim_usd_decimal + .checked_mul(ten_pow_decimals) + .and_then(|v| v.to_u64()) + .ok_or(PropellerError::ConversionError)?; + + msg!( + "fee_in_swim_usd_decimal: {:?} fee_in_swim_usd_atomic: {:?}", + fee_in_swim_usd_decimal, + fee_in_swim_usd_atomic + ); + res = fee_in_swim_usd_atomic; + Ok(res) + } + + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { + let fee_tracker = &mut self.fee_tracker; + fee_tracker.fees_owed = + fee_tracker.fees_owed.checked_add(fees_in_swim_usd).ok_or(PropellerError::IntegerOverflow)?; + + token::transfer( + CpiContext::new_with_signer( + self.token_program.to_account_info(), + Transfer { + from: self.redeemer_escrow.to_account_info(), + to: self.fee_vault.to_account_info(), + authority: self.redeemer.to_account_info(), + }, + &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + ), + fees_in_swim_usd, + ) + } +} + */ + pub fn handle_propeller_process_swim_payload_fallback( ctx: Context, ) -> Result { diff --git a/packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs index 616419581..2cf358ea2 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs @@ -64,6 +64,13 @@ pub struct TokenIdMap { impl TokenIdMap { pub const LEN: usize = 2 + 32 + 1 + 32 + 1 + 1 + 1; + + pub fn assert_is_invalid(token_id_map: &AccountInfo) -> Result<()> { + if let Ok(_) = TokenIdMap::try_deserialize(&mut &**token_id_map.try_borrow_mut_data()?) { + return err!(PropellerError::TokenIdMapExists); + } + Ok(()) + } } #[derive(AnchorSerialize, AnchorDeserialize, Copy, Clone, Debug)] diff --git a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs index 8650ba6da..cdaef24f0 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs @@ -19,6 +19,7 @@ pub fn convert_fees_to_swim_usd_atomic<'info>( fee_in_lamports: u64, propeller: &Propeller, marginal_price_pool_lp_mint: &Account<'info, Mint>, + //TODO: just take marginal_prices as input here. cpi_ctx: CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>>, marginal_price_pool: &TwoPool, aggregator: &AccountLoader, @@ -68,6 +69,59 @@ pub fn convert_fees_to_swim_usd_atomic<'info>( Ok(res) } +pub fn convert_fees_to_swim_usd_atomic_2<'info>( + fee_in_lamports: u64, + propeller: &Propeller, + marginal_price_pool_lp_mint: &Account<'info, Mint>, + marginal_prices: [BorshDecimal; TOKEN_COUNT], + marginal_price_pool: &TwoPool, + aggregator: &AccountLoader, + max_staleness: i64, +) -> Result { + // let propeller = &self.propeller; + + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &marginal_price_pool_lp_mint; + + let swim_usd_mint_key = propeller.swim_usd_mint; + // let marginal_prices = get_marginal_prices(cpi_ctx)?; + + let intermediate_token_price_decimal: Decimal = get_marginal_price_decimal( + &marginal_price_pool, + &marginal_prices, + &propeller, + &marginal_price_pool_lp_mint.key(), + )?; + + msg!("intermediate_token_price_decimal: {:?}", intermediate_token_price_decimal); + + let fee_in_lamports_decimal = Decimal::from_u64(fee_in_lamports).ok_or(PropellerError::ConversionError)?; + msg!("fee_in_lamports(u64): {:?} fee_in_lamports_decimal: {:?}", fee_in_lamports, fee_in_lamports_decimal); + + let mut res = 0u64; + + let lamports_intermediate_token_price = get_lamports_intermediate_token_price(&aggregator, max_staleness)?; + let fee_in_swim_usd_decimal = lamports_intermediate_token_price + .checked_mul(fee_in_lamports_decimal) + .and_then(|x| x.checked_div(intermediate_token_price_decimal)) + .ok_or(PropellerError::IntegerOverflow)?; + + let swim_usd_decimals = + get_swim_usd_mint_decimals(&swim_usd_mint_key, &marginal_price_pool, &marginal_price_pool_lp_mint)?; + msg!("swim_usd_decimals: {:?}", swim_usd_decimals); + + let ten_pow_decimals = + Decimal::from_u64(10u64.pow(swim_usd_decimals as u32)).ok_or(PropellerError::IntegerOverflow)?; + let fee_in_swim_usd_atomic = fee_in_swim_usd_decimal + .checked_mul(ten_pow_decimals) + .and_then(|v| v.to_u64()) + .ok_or(PropellerError::ConversionError)?; + + msg!("fee_in_swim_usd_decimal: {:?} fee_in_swim_usd_atomic: {:?}", fee_in_swim_usd_decimal, fee_in_swim_usd_atomic); + res = fee_in_swim_usd_atomic; + Ok(res) +} + pub fn get_swim_usd_mint_decimals( swim_usd_mint: &Pubkey, marginal_price_pool: &TwoPool, diff --git a/packages/solana-contracts/programs/propeller/src/instructions/wormhole/complete_native_with_payload.rs b/packages/solana-contracts/programs/propeller/src/instructions/wormhole/complete_native_with_payload.rs index a665d791d..c996c5135 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/wormhole/complete_native_with_payload.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/wormhole/complete_native_with_payload.rs @@ -18,7 +18,7 @@ use { }, byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, num_traits::{FromPrimitive, ToPrimitive}, - primitive_types::U256, + // primitive_types::U256, rust_decimal::Decimal, solana_program::program::invoke, switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, @@ -306,8 +306,6 @@ pub fn handle_complete_native_with_payload(ctx: Context 8 { transfer_amount *= 10u64.pow(ctx.accounts.swim_usd_mint.decimals as u32); @@ -316,12 +314,6 @@ pub fn handle_complete_native_with_payload(ctx: Context (pool, pool_token_index) - // // need to know when to do remove_exact_burn & when to do swap_exact_input - // let memo_ix = spl_memo::build_memo(memo.as_slice(), &[]); - // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - Ok(()) } @@ -347,7 +339,7 @@ pub struct PropellerCompleteNativeWithPayload<'info> { *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount )] pub aggregator: AccountLoader<'info, AggregatorAccountData>, - // pub two_pool_program: Program<'info, two_pool::program::TwoPool>, + #[account( mut, seeds = [ @@ -360,8 +352,17 @@ pub struct PropellerCompleteNativeWithPayload<'info> { seeds::program = two_pool_program.key() )] pub marginal_price_pool: Box>, + #[account( + address = marginal_price_pool.token_keys[0], + )] pub marginal_price_pool_token_0_account: Box>, + #[account( + address = marginal_price_pool.token_keys[1], + )] pub marginal_price_pool_token_1_account: Box>, + #[account( + address = marginal_price_pool.lp_mint_key, + )] pub marginal_price_pool_lp_mint: Box>, pub two_pool_program: Program<'info, two_pool::program::TwoPool>, #[account(executable, address = spl_memo::id())] diff --git a/packages/solana-contracts/programs/propeller/src/instructions/wormhole/transfer_native_with_payload.rs b/packages/solana-contracts/programs/propeller/src/instructions/wormhole/transfer_native_with_payload.rs index c32f97835..0912ecbf7 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/wormhole/transfer_native_with_payload.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/wormhole/transfer_native_with_payload.rs @@ -15,11 +15,10 @@ use { }, }, anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, + associated_token::get_associated_token_address, + token::{self, Mint, Token, TokenAccount}, }, byteorder::{BigEndian, WriteBytesExt}, - primitive_types::U256, std::{io::Write, str}, }; @@ -47,8 +46,7 @@ pub struct TransferNativeWithPayload<'info> { #[account( mut, - associated_token::mint = swim_usd_mint, - associated_token::authority = payer + address = get_associated_token_address(&payer.key(), &swim_usd_mint.key()), )] pub user_swim_usd_ata: Box>, diff --git a/packages/solana-contracts/programs/propeller/src/lib.rs b/packages/solana-contracts/programs/propeller/src/lib.rs index a30a11dab..7c2c6c9e8 100644 --- a/packages/solana-contracts/programs/propeller/src/lib.rs +++ b/packages/solana-contracts/programs/propeller/src/lib.rs @@ -19,6 +19,7 @@ use { *, }, constants::TOKEN_COUNT, + fees::*, // error::PropellerError, // instructions::*, solana_program::clock::Epoch, @@ -30,6 +31,7 @@ use { mod constants; mod error; +mod fees; mod instructions; mod state; mod token_bridge; diff --git a/packages/solana-contracts/programs/propeller/src/state/propeller.rs b/packages/solana-contracts/programs/propeller/src/state/propeller.rs index ec6a50c4d..ee6c764d0 100644 --- a/packages/solana-contracts/programs/propeller/src/state/propeller.rs +++ b/packages/solana-contracts/programs/propeller/src/state/propeller.rs @@ -7,6 +7,7 @@ use { io::{Cursor, ErrorKind, Read, Write}, str::FromStr, }, + two_pool::state::TwoPool, }; // Do i need this to hold configs & state? @@ -295,18 +296,40 @@ impl AnchorSerialize for RawSwimPayload { } } -pub fn validate_marginal_prices_pool_accounts( +pub fn validate_marginal_prices_pool_accounts<'info>( propeller: &Propeller, - marginal_price_pool: &Pubkey, + marginal_price_pool_key: &Pubkey, marginal_price_pool_token_account_mints: &[Pubkey; TOKEN_COUNT], ) -> Result<()> { - require_keys_eq!(*marginal_price_pool, propeller.marginal_price_pool); + require_keys_eq!(*marginal_price_pool_key, propeller.marginal_price_pool); let pool_token_index = propeller.marginal_price_pool_token_index as usize; require_gt!(TOKEN_COUNT, pool_token_index, PropellerError::InvalidMarginalPricePoolAccounts); require_keys_eq!( marginal_price_pool_token_account_mints[pool_token_index], propeller.marginal_price_pool_token_mint, ); + // match pool_token_index { + // 0 => require_keys_eq!(marginal_price_pool_token_account_mints[1], propeller.token_mint), + // } + // require_keys_eq!(marginal_price_pool_key.token_keys[pool_token_index], propeller); + Ok(()) +} + +pub fn validate_marginal_prices_pool_accounts_2<'info>( + propeller: &Propeller, + marginal_price_pool: &Account<'info, TwoPool>, + marginal_price_pool_token_accounts: &[&Account<'info, TokenAccount>; TOKEN_COUNT], +) -> Result<()> { + let marginal_price_pool_key = &marginal_price_pool.key(); + require_keys_eq!(*marginal_price_pool_key, propeller.marginal_price_pool); + let pool_token_index = propeller.marginal_price_pool_token_index as usize; + require_gt!(TOKEN_COUNT, pool_token_index, PropellerError::InvalidMarginalPricePoolAccounts); + let pool_token_account = marginal_price_pool_token_accounts[pool_token_index]; + require_keys_eq!(pool_token_account.mint, propeller.marginal_price_pool_token_mint,); + // match pool_token_index { + // 0 => require_keys_eq!(marginal_price_pool_token_accounts[1], propeller.token_mint), + // } + require_keys_eq!(pool_token_account.key(), marginal_price_pool_token_accounts[pool_token_index].key()); Ok(()) } diff --git a/packages/solana-contracts/programs/two-pool/src/decimal.rs b/packages/solana-contracts/programs/two-pool/src/decimal.rs index 7a8b7bd50..02b94825b 100644 --- a/packages/solana-contracts/programs/two-pool/src/decimal.rs +++ b/packages/solana-contracts/programs/two-pool/src/decimal.rs @@ -13,7 +13,7 @@ use { crate::PoolError, - borsh::{BorshSchema}, + borsh::BorshSchema, std::{ cmp, cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs index e02aaa550..dba350348 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -18,7 +18,7 @@ pub struct Add<'info> { pool_token_account_1.mint.as_ref(), lp_mint.key().as_ref(), ], - bump = pool.bump + bump = pool.bump, )] pub pool: Box>, // /// TODO: could be removed if initialized with pool_v2 @@ -26,25 +26,23 @@ pub struct Add<'info> { // pub pool_auth: UncheckedAccount<'info>, #[account( mut, - address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), - constraint = pool_token_account_0.key() == pool.token_keys[0], + address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, )] pub pool_token_account_0: Box>, #[account( mut, - address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[1]), - constraint = pool_token_account_1.key() == pool.token_keys[1], + address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, )] pub pool_token_account_1: Box>, #[account( mut, - address = pool.lp_mint_key, + address = pool.lp_mint_key @ PoolError::InvalidMintAccount, )] pub lp_mint: Box>, #[account( mut, token::mint = lp_mint, - address = pool.governance_fee_key, + address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, )] pub governance_fee: Box>, ///CHECK: checked in CPI @@ -66,11 +64,6 @@ pub struct Add<'info> { )] pub user_lp_token_account: Box>, - //TODO: vanilla solana we didn't pass/ask for this account - // w/ user_transfer_authority it's not explicitly needed. - // is there any type of checks that we HAVE to do related to payer? - // #[account(mut)] - // pub payer: Signer<'info>, pub token_program: Program<'info, Token>, } @@ -84,28 +77,6 @@ impl<'info> Add<'info> { pub fn accounts(ctx: &Context) -> Result<()> { let pool_state = &ctx.accounts.pool; require!(!pool_state.is_paused, PoolError::PoolIsPaused); - require_keys_eq!( - ctx.accounts.pool_token_account_0.key(), - pool_state.token_keys[0], - PoolError::PoolTokenAccountExpected - ); - require_keys_eq!( - ctx.accounts.pool_token_account_1.key(), - pool_state.token_keys[1], - PoolError::PoolTokenAccountExpected - ); - require_keys_eq!(ctx.accounts.lp_mint.key(), pool_state.lp_mint_key, PoolError::InvalidMintAccount); - require_keys_eq!( - ctx.accounts.governance_fee.key(), - pool_state.governance_fee_key, - PoolError::InvalidGovernanceFeeAccount - ); - - // let pool_state_acct = &ctx.accounts.pool_state; - // let pool: two_pool::state::PoolState<{two_pool::TOKEN_COUNT}> = two_pool::state::PoolState::try_from_slice(&pool_state_acct.data.borrow())?; - // constraint = lp_mint.key() == propeller.token_bridge_mint @ PropellerError::InvalidMint - msg!("finished accounts context check"); - // let Ok(()) } } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs index b9f21168d..75def334b 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs @@ -1,8 +1,5 @@ use { - crate::{ - error::*, gen_pool_signer_seeds, - DecimalU64, TwoPool, TOKEN_COUNT, - }, + crate::{error::*, gen_pool_signer_seeds, DecimalU64, TwoPool, TOKEN_COUNT}, anchor_lang::prelude::*, anchor_spl::{ token, @@ -19,6 +16,8 @@ pub struct RemoveUniformParams { #[derive(Accounts)] pub struct RemoveUniform<'info> { + /// Note: RemoveUniform is the only ix that is allowed even if the pool is paused + /// which is why we don't check the is_paused value here. #[account( mut, seeds = [ @@ -29,24 +28,26 @@ pub struct RemoveUniform<'info> { ], bump = pool.bump )] - pub pool: Account<'info, TwoPool>, + pub pool: Box>, #[account( mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, + address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, )] pub pool_token_account_0: Box>, #[account( mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, + address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, )] pub pool_token_account_1: Box>, - #[account(mut)] + #[account( + mut, + address = pool.lp_mint_key @ PoolError::InvalidMintAccount, + )] pub lp_mint: Box>, #[account( mut, - token::mint = lp_mint + token::mint = lp_mint, + address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, )] pub governance_fee: Box>, @@ -70,44 +71,9 @@ pub struct RemoveUniform<'info> { )] pub user_lp_token_account: Box>, - // //TODO: probably need a user_transfer_auth account since either the user or propeller could be payer for txn. - // // payer could be the same as user_auth if user manually completing the txn but still need - // // to have a separate field to account for it - // #[account(mut)] - // pub payer: Signer<'info>, pub token_program: Program<'info, Token>, } -impl<'info> RemoveUniform<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - let pool_state = &ctx.accounts.pool; - require!(!pool_state.is_paused, PoolError::PoolIsPaused); - require_keys_eq!( - ctx.accounts.pool_token_account_0.key(), - pool_state.token_keys[0], - PoolError::PoolTokenAccountExpected - ); - require_keys_eq!( - ctx.accounts.pool_token_account_1.key(), - pool_state.token_keys[1], - PoolError::PoolTokenAccountExpected - ); - require_keys_eq!(ctx.accounts.lp_mint.key(), pool_state.lp_mint_key, PoolError::InvalidMintAccount); - require_keys_eq!( - ctx.accounts.governance_fee.key(), - pool_state.governance_fee_key, - PoolError::InvalidGovernanceFeeAccount - ); - - // let pool_state_acct = &ctx.accounts.pool_state; - // let pool: two_pool::state::PoolState<{two_pool::TOKEN_COUNT}> = two_pool::state::PoolState::try_from_slice(&pool_state_acct.data.borrow())?; - // constraint = lp_mint.key() == propeller.token_bridge_mint @ PropellerError::InvalidMint - msg!("finished accounts context check"); - // let - Ok(()) - } -} - pub fn handle_remove_uniform( ctx: Context, remove_uniform_params: RemoveUniformParams, diff --git a/packages/solana-contracts/programs/two-pool/src/invariant.rs b/packages/solana-contracts/programs/two-pool/src/invariant.rs index 12c3e01e3..59909699e 100644 --- a/packages/solana-contracts/programs/two-pool/src/invariant.rs +++ b/packages/solana-contracts/programs/two-pool/src/invariant.rs @@ -623,7 +623,7 @@ impl Invariant { fn calculate_unknown_balance( // this should have type &[AmountT; TOKEN_COUNT-1] but Rust currently does not support const operations // on const generics and hence TOKEN_COUNT-1 is illegal and so it has to be a Vec instead... - known_balances: &Vec, + known_balances: &[AmountT], depth: Decimal, amp_factor: AmpT, initial_guess: AmountT, diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index 3c54dfa42..05e6e433b 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -120,7 +120,6 @@ pub mod two_pool { handle_swap_exact_output(ctx, params) } - #[access_control(RemoveUniform::accounts(&ctx))] pub fn remove_uniform( ctx: Context, exact_burn_amount: u64, diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index 66272b0c3..01a8b13e5 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -3407,7 +3407,33 @@ "docs": [ "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" - ] + ], + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "SwimPayloadMessage", + "path": "swim_payload_message.target_token_id" + } + ] + } }, { "name": "swimUsdMint", diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index b45ba56c4..068abe656 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -3407,7 +3407,33 @@ export type Propeller = { "docs": [ "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" - ] + ], + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "SwimPayloadMessage", + "path": "swim_payload_message.target_token_id" + } + ] + } }, { "name": "swimUsdMint", @@ -8195,7 +8221,33 @@ export const IDL: Propeller = { "docs": [ "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" - ] + ], + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "SwimPayloadMessage", + "path": "swim_payload_message.target_token_id" + } + ] + } }, { "name": "swimUsdMint", diff --git a/packages/solana-contracts/src/artifacts/two_pool.json b/packages/solana-contracts/src/artifacts/two_pool.json index bbef5d41c..8b217d768 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.json +++ b/packages/solana-contracts/src/artifacts/two_pool.json @@ -425,6 +425,10 @@ "name": "pool", "isMut": true, "isSigner": false, + "docs": [ + "Note: RemoveUniform is the only ix that is allowed even if the pool is paused", + "which is why we don't check the is_paused value here." + ], "pda": { "seeds": [ { diff --git a/packages/solana-contracts/src/artifacts/two_pool.ts b/packages/solana-contracts/src/artifacts/two_pool.ts index ff02cacb8..0994bdcc8 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.ts +++ b/packages/solana-contracts/src/artifacts/two_pool.ts @@ -425,6 +425,10 @@ export type TwoPool = { "name": "pool", "isMut": true, "isSigner": false, + "docs": [ + "Note: RemoveUniform is the only ix that is allowed even if the pool is paused", + "which is why we don't check the is_paused value here." + ], "pda": { "seeds": [ { @@ -2611,6 +2615,10 @@ export const IDL: TwoPool = { "name": "pool", "isMut": true, "isSigner": false, + "docs": [ + "Note: RemoveUniform is the only ix that is allowed even if the pool is paused", + "which is why we don't check the is_paused value here." + ], "pda": { "seeds": [ {