From 81699e392bcf82a5e79e4a05d2fd1eafdb302144 Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 4 Oct 2022 13:31:36 -0400 Subject: [PATCH 01/17] refactor(solana-contracts): import cleanup, typo fixes --- .../create_owner_token_accounts.rs | 151 ++++-------------- .../src/instructions/process_swim_payload.rs | 24 +-- .../wormhole/transfer_native_with_payload.rs | 1 - .../src/artifacts/propeller.json | 2 +- .../src/artifacts/propeller.ts | 4 +- 5 files changed, 47 insertions(+), 135 deletions(-) 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 65442a0d6..075a5a22e 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 @@ -1,44 +1,27 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, convert_fees_to_swim_usd_atomic, get_lamports_intermediate_token_price, - get_marginal_price_decimal, get_marginal_prices, get_swim_usd_mint_decimals, FeeTracker, - }, - anchor_spl::{ - associated_token::{get_associated_token_address, AssociatedToken}, - token::Transfer, - }, - num_traits::{FromPrimitive, ToPrimitive}, - rust_decimal::Decimal, - solana_program::{instruction::Instruction, program::invoke_signed}, - two_pool::BorshDecimal, -}; -use { - crate::{ - deserialize_message_payload, - // env::*, + constants::LAMPORTS_PER_SOL_DECIMAL, + convert_fees_to_swim_usd_atomic, deserialize_message_payload, error::*, - get_message_data, - get_transfer_with_payload_from_message_account, - hash_vaa, + get_lamports_intermediate_token_price, get_marginal_price_decimal, get_marginal_prices, get_message_data, + get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, token_id_map::{PoolInstruction, TokenIdMap}, - ClaimData, - PayloadTransferWithPayload, - PostVAAData, - PostedVAAData, - Propeller, - RawSwimPayload, + ClaimData, FeeTracker, PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, RawSwimPayload, TOKEN_COUNT, }, anchor_lang::{prelude::*, solana_program::program::invoke}, anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, + associated_token::{get_associated_token_address, AssociatedToken}, + token::{self, Mint, Token, TokenAccount, Transfer}, }, + num_traits::{FromPrimitive, ToPrimitive}, + rust_decimal::Decimal, + solana_program::{instruction::Instruction, program::invoke_signed}, std::convert::TryInto, - two_pool::state::TwoPool, + two_pool::{state::TwoPool, BorshDecimal}, }; #[derive(Accounts)] @@ -63,14 +46,12 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { pub redeemer: SystemAccount<'info>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = redeemer, + address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = propeller, + address = get_associated_token_address(&propeller.key(), &propeller.swim_usd_mint) )] pub fee_vault: Box>, @@ -138,13 +119,22 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { #[account(address = swim_payload_message.owner)] pub user: SystemAccount<'info>, - #[account(mut)] + #[account( + mut, + address = get_associated_token_address(&user.key(), &pool_token_0_mint.key()), + )] /// CHECK: may possibly need to initialize pub user_pool_token_0_account: UncheckedAccount<'info>, - #[account(mut)] + #[account( + mut, + address = get_associated_token_address(&user.key(), &pool_token_1_mint.key()), + )] /// CHECK: may possibly need to initialize pub user_pool_token_1_account: UncheckedAccount<'info>, - #[account(mut)] + #[account( + mut, + address = get_associated_token_address(&user.key(), &pool_lp_mint.key()), + )] /// CHECK: may possibly need to initialize pub user_lp_token_account: UncheckedAccount<'info>, pub associated_token_program: Program<'info, AssociatedToken>, @@ -193,15 +183,6 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { ctx.accounts.marginal_price_pool_token_1_account.mint, ], )?; - let expected_user_token_0_ata = - get_associated_token_address(&ctx.accounts.user.key(), &ctx.accounts.pool_token_0_mint.key()); - require_keys_eq!(expected_user_token_0_ata, ctx.accounts.user_pool_token_0_account.key()); - let expected_user_token_1_ata = - get_associated_token_address(&ctx.accounts.user.key(), &ctx.accounts.pool_token_1_mint.key()); - require_keys_eq!(expected_user_token_1_ata, ctx.accounts.user_pool_token_1_account.key()); - let expected_user_lp_ata = - get_associated_token_address(&ctx.accounts.user.key(), &ctx.accounts.pool_lp_mint.key()); - require_keys_eq!(expected_user_lp_ata, ctx.accounts.user_lp_token_account.key()); msg!("Passed PropellerCreateOwnerTokenAccounts::accounts() check"); Ok(()) } @@ -227,58 +208,6 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'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 token_bridge_mint_key = propeller.token_bridge_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)) - // .ok_or(PropellerError::IntegerOverflow)?; - // - // let swim_usd_decimals = get_token_bridge_mint_decimals( - // &token_bridge_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) - // } - fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { let fee_tracker = &mut self.fee_tracker; let updated_fees_owed = @@ -595,14 +524,12 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { pub redeemer: SystemAccount<'info>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = redeemer, + address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = propeller, + address = get_associated_token_address(&propeller.key(), &propeller.swim_usd_mint) )] pub fee_vault: Box>, @@ -641,17 +568,8 @@ 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 - /// deseraizlied as a `TokenIdMap`. if it does exist, then engine should have called + /// deserialized as a `TokenIdMap`. if it does exist, then engine should have called /// propeller_create_owner_token_accounts instead pub token_id_map: UncheckedAccount<'info>, pub swim_usd_mint: Box>, @@ -690,8 +608,11 @@ pub struct PropellerCreateOwnerSwimUsdAta<'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())] @@ -809,16 +730,6 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { fees_in_swim_usd, ) } - // 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(()) - // } } pub fn handle_propeller_create_owner_swim_usd_ata(ctx: Context) -> Result<()> { 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 2f04b16bf..4ebbc50da 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 @@ -4,12 +4,6 @@ use { constants::LAMPORTS_PER_SOL_DECIMAL, convert_fees_to_swim_usd_atomic, get_marginal_price_decimal, get_swim_usd_mint_decimals, FeeTracker, }, - anchor_lang::system_program, - anchor_spl::{associated_token::AssociatedToken, token::Transfer}, - num_traits::{FromPrimitive, ToPrimitive}, - rust_decimal::Decimal, -}; -use { crate::{ deserialize_message_payload, // env::*, @@ -28,11 +22,18 @@ use { RawSwimPayload, TOKEN_COUNT, }, + anchor_lang::system_program, anchor_lang::{prelude::*, solana_program::program::invoke}, + anchor_spl::{ + associated_token::{get_associated_token_address, AssociatedToken}, + token::Transfer, + }, anchor_spl::{ token, token::{Mint, Token, TokenAccount}, }, + num_traits::{FromPrimitive, ToPrimitive}, + rust_decimal::Decimal, std::convert::TryInto, two_pool::state::TwoPool, }; @@ -103,8 +104,7 @@ pub struct ProcessSwimPayload<'info> { pub redeemer: SystemAccount<'info>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = redeemer, + address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, @@ -770,8 +770,7 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { pub redeemer: SystemAccount<'info>, #[account( mut, - token::mint = propeller.swim_usd_mint, - token::authority = redeemer, + address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, @@ -783,7 +782,10 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { // needs to be a signer since its a "keypair" account pub user_transfer_authority: Signer<'info>, - #[account(mut, associated_token::mint = propeller.swim_usd_mint, associated_token::authority = owner)] + #[account( + mut, + address = get_associated_token_address(&owner.key(), &propeller.swim_usd_mint) + )] pub user_swim_usd_ata: Box>, pub token_program: Program<'info, Token>, 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 17f425fe4..c32f97835 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 @@ -418,7 +418,6 @@ pub fn handle_propeller_transfer_native_with_payload( let target_address = ctx.accounts.target_chain_map.target_address.clone(); let transfer_with_payload_data = TransferWithPayloadData { - //TODO: update this. nonce: ctx.accounts.propeller.nonce, amount, target_address, diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index 1a897df40..aa0fc01f5 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -3414,7 +3414,7 @@ "isMut": false, "isSigner": false, "docs": [ - "deseraizlied as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ] }, diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 24795a3ee..46a9ff7e0 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -3414,7 +3414,7 @@ export type Propeller = { "isMut": false, "isSigner": false, "docs": [ - "deseraizlied as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ] }, @@ -8190,7 +8190,7 @@ export const IDL: Propeller = { "isMut": false, "isSigner": false, "docs": [ - "deseraizlied as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ] }, From ef8c0d18c7988d19889babfc6200802945184356 Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 4 Oct 2022 16:47:08 -0400 Subject: [PATCH 02/17] feat(solana-contracts): remove unused userTsferAuth from processSwimPayload ixs --- .../src/instructions/process_swim_payload.rs | 162 +++--------------- .../src/__tests__/propeller/engine.test.ts | 33 +--- .../src/__tests__/propeller/propeller.test.ts | 23 +-- .../src/__tests__/propeller/propellerUtils.ts | 7 +- .../src/artifacts/propeller.json | 46 +++-- .../src/artifacts/propeller.ts | 92 ++++++---- 6 files changed, 124 insertions(+), 239 deletions(-) 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 4ebbc50da..5dbb5b513 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 @@ -150,25 +150,32 @@ pub struct ProcessSwimPayload<'info> { pub lp_mint: Box>, #[account( mut, - token::mint = lp_mint + address = pool.governance_fee_key, )] pub governance_fee: Box>, - // needs to be a signer since its a "keypair" account - pub user_transfer_authority: Signer<'info>, - - #[account(mut, token::mint = pool_token_account_0.mint, token::authority = swim_payload_message.owner)] + #[account( + mut, + address = get_associated_token_address(&swim_payload_message.owner, &pool_token_account_0.mint) + )] pub user_token_account_0: Box>, - #[account(mut, token::mint = pool_token_account_1.mint, token::authority = swim_payload_message.owner)] + #[account( + mut, + address = get_associated_token_address(&swim_payload_message.owner, &pool_token_account_1.mint) + )] pub user_token_account_1: Box>, - #[account(mut, token::mint = pool.lp_mint_key, token::authority = swim_payload_message.owner)] + #[account( + mut, + address = get_associated_token_address(&swim_payload_message.owner, &pool.lp_mint_key) + )] pub user_lp_token_account: Box>, pub token_program: Program<'info, Token>, pub two_pool_program: Program<'info, two_pool::program::TwoPool>, + pub system_program: Program<'info, System>, } @@ -182,7 +189,6 @@ impl<'info> ProcessSwimPayload<'info> { ctx.accounts.token_id_map.pool, PropellerError::InvalidTokenIdMapPool ); - Ok(()) } @@ -218,62 +224,6 @@ impl<'info> ProcessSwimPayload<'info> { &self.redeemer.to_account_info(), &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], ) - // self.transfer_with_user_auth( - // transfer_amount, - // min_output_amount, - // output_token_index, - // pool_ix, - // pool_token_index, - // pool_token_mint, - // &self.user_transfer_authority.to_account_info(), - // ) - } - - fn transfer_with_user_auth( - &self, - transfer_amount: u64, - min_output_amount: u64, - output_token_index: u16, - pool_ix: &PoolInstruction, - pool_token_index: u8, - pool_token_mint: &Pubkey, - user_transfer_authority: &AccountInfo<'info>, - ) -> Result { - token::approve( - CpiContext::new_with_signer( - self.token_program.to_account_info(), - token::Approve { - // source - to: self.redeemer_escrow.to_account_info(), - delegate: self.user_transfer_authority.to_account_info(), - authority: self.redeemer.to_account_info(), - }, - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - ), - transfer_amount, - )?; - require_gt!(TOKEN_COUNT, pool_token_index as usize); - // let user_transfer_authority = &self.user_transfer_authority.to_account_info(); - let output_amount_res = self.execute_transfer_or_pool_ix( - transfer_amount, - min_output_amount, - output_token_index, - pool_ix, - pool_token_index, - pool_token_mint, - user_transfer_authority, - &[], - ); - token::revoke(CpiContext::new_with_signer( - self.token_program.to_account_info(), - token::Revoke { - // source - source: self.redeemer_escrow.to_account_info(), - authority: self.redeemer.to_account_info(), - }, - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - ))?; - output_amount_res } fn execute_transfer_or_pool_ix( @@ -423,8 +373,7 @@ pub struct PropellerProcessSwimPayload<'info> { #[account( mut, - token::mint = process_swim_payload.propeller.swim_usd_mint, - token::authority = process_swim_payload.propeller, + address = get_associated_token_address(&process_swim_payload.propeller.key(), &process_swim_payload.propeller.swim_usd_mint) )] /// this is "to_fees" /// recipient of fees for executing complete transfer (e.g. relayer) @@ -473,6 +422,7 @@ pub struct PropellerProcessSwimPayload<'info> { #[account(address = marginal_price_pool.lp_mint_key)] pub marginal_price_pool_lp_mint: Box>, /// This is for transferring lamports for kickstart + /// TODO: force this to be system account? #[account(mut, address = process_swim_payload.swim_payload_message.owner)] pub owner: SystemAccount<'info>, #[account(executable, address = spl_memo::id())] @@ -774,14 +724,20 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { )] pub redeemer_escrow: 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 pub token_id_map: UncheckedAccount<'info>, - // needs to be a signer since its a "keypair" account - pub user_transfer_authority: Signer<'info>, - #[account( mut, address = get_associated_token_address(&owner.key(), &propeller.swim_usd_mint) @@ -1025,81 +981,13 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { } pub fn transfer_tokens(&self, transfer_amount: u64) -> Result { - //TODO: decide if using user_transfer_auth - // remove user_transfer_authority account if not. self.transfer_swim_usd_tokens( transfer_amount, &self.redeemer.to_account_info(), &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], ) - // self.execute_transfer_or_pool_ix( - // transfer_amount, - // min_output_amount, - // output_token_index, - // pool_ix, - // pool_token_index, - // pool_token_mint, - // &self.redeemer.to_account_info(), - // &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - // ) - // self.transfer_with_user_auth( - // transfer_amount, - // min_output_amount, - // output_token_index, - // pool_ix, - // pool_token_index, - // pool_token_mint, - // &self.user_transfer_authority.to_account_info(), - // ) } - // fn transfer_with_user_auth( - // &self, - // transfer_amount: u64, - // min_output_amount: u64, - // output_token_index: u16, - // pool_ix: &PoolInstruction, - // pool_token_index: u8, - // pool_token_mint: &Pubkey, - // user_transfer_authority: &AccountInfo<'info>, - // ) -> Result { - // token::approve( - // CpiContext::new_with_signer( - // self.token_program.to_account_info(), - // token::Approve { - // // source - // to: self.redeemer_escrow.to_account_info(), - // delegate: self.user_transfer_authority.to_account_info(), - // authority: self.redeemer.to_account_info(), - // }, - // &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - // ), - // transfer_amount, - // )?; - // require_gt!(TOKEN_COUNT, pool_token_index as usize); - // // let user_transfer_authority = &self.user_transfer_authority.to_account_info(); - // let output_amount_res = self.execute_transfer_or_pool_ix( - // transfer_amount, - // min_output_amount, - // output_token_index, - // pool_ix, - // pool_token_index, - // pool_token_mint, - // user_transfer_authority, - // &[], - // ); - // token::revoke(CpiContext::new_with_signer( - // self.token_program.to_account_info(), - // token::Revoke { - // // source - // source: self.redeemer_escrow.to_account_info(), - // authority: self.redeemer.to_account_info(), - // }, - // &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - // ))?; - // output_amount_res - // } - fn transfer_swim_usd_tokens( &self, transfer_amount: u64, diff --git a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts index 51f62b3a5..5f0a0cd80 100644 --- a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts @@ -1322,7 +1322,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -1351,7 +1350,7 @@ describe("propeller", () => { memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) - .signers([userTransferAuthority, propellerEngineKeypair]); + .signers([propellerEngineKeypair]); const propellerProcessSwimPayloadPubkeys = await propellerProcessSwimPayloadIxs.pubkeys(); @@ -2055,15 +2054,10 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0, - userTokenAccount1, - userLpTokenAccount, tokenProgram: splToken.programId, - twoPoolProgram: twoPoolProgram.programId, systemProgram: web3.SystemProgram.programId, }) @@ -2120,7 +2114,7 @@ describe("propeller", () => { memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) - .signers([userTransferAuthority, propellerEngineKeypair]); + .signers([propellerEngineKeypair]); const propellerProcessSwimPayloadPubkeys = await propellerProcessSwimPayloadIxs.pubkeys(); @@ -2739,7 +2733,6 @@ describe("propeller", () => { ) ).feesOwed; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -2768,7 +2761,6 @@ describe("propeller", () => { redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, tokenIdMap: invalidTokenIdMapAddr, - userTransferAuthority: userTransferAuthority.publicKey, userSwimUsdAta: ownerSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, @@ -2784,7 +2776,7 @@ describe("propeller", () => { owner, }) .preInstructions([setComputeUnitLimitIx]) - .signers([userTransferAuthority, propellerEngineKeypair]); + .signers([propellerEngineKeypair]); const propellerProcessSwimPayloadPubkeys = await propellerProcessSwimPayloadIxs.pubkeys(); @@ -4305,15 +4297,10 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0, - userTokenAccount1, - userLpTokenAccount, tokenProgram: splToken.programId, - twoPoolProgram: twoPoolProgram.programId, systemProgram: web3.SystemProgram.programId, }) @@ -4339,7 +4326,7 @@ describe("propeller", () => { memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) - .signers([userTransferAuthority, propellerEngineKeypair]); + .signers([propellerEngineKeypair]); const propellerProcessSwimPayloadPubkeys = await propellerProcessSwimPayloadIxs.pubkeys(); @@ -4608,7 +4595,6 @@ describe("propeller", () => { let txns: readonly web3.Transaction[] = []; let txnIdx = 0; let propellerRedeemerEscrowAccountBefore: BN; - const userTransferAuthority = web3.Keypair.generate(); beforeAll(async () => { tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( @@ -4663,7 +4649,6 @@ describe("propeller", () => { twoPoolProgram, splToken, aggregator, - userTransferAuthority, ); console.info(`txns: ${JSON.stringify(txns)}`); }); @@ -5027,7 +5012,6 @@ describe("propeller", () => { const processSwimPayloadTxnSig = await propellerEngineAnchorProvider.sendAndConfirm( processSwimPayloadTxn, - [userTransferAuthority], ); console.info(`processSwimPayloadTxnSig: ${processSwimPayloadTxnSig}`); @@ -5168,7 +5152,6 @@ describe("propeller", () => { let txns: readonly web3.Transaction[] = []; let txnIdx = 0; let propellerRedeemerEscrowAccountBefore: BN; - const userTransferAuthority = web3.Keypair.generate(); beforeAll(async () => { tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( @@ -5223,7 +5206,6 @@ describe("propeller", () => { twoPoolProgram, splToken, aggregator, - userTransferAuthority, ); console.info(`txns: ${JSON.stringify(txns)}`); }); @@ -5574,7 +5556,6 @@ describe("propeller", () => { const processSwimPayloadTxnSig = await propellerEngineAnchorProvider.sendAndConfirm( processSwimPayloadTxn, - [userTransferAuthority], ); console.info(`processSwimPayloadTxnSig: ${processSwimPayloadTxnSig}`); @@ -6199,12 +6180,8 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0, - userTokenAccount1, - userLpTokenAccount, tokenProgram: splToken.programId, twoPoolProgram: twoPoolProgram.programId, @@ -6232,7 +6209,7 @@ describe("propeller", () => { memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) - .signers([userTransferAuthority, propellerEngineKeypair]); + .signers([propellerEngineKeypair]); const propellerProcessSwimPayloadPubkeys = await propellerProcessSwimPayloadIxs.pubkeys(); diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index 2e7e467a0..fd443c54f 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -1,5 +1,3 @@ -import crypto from "crypto"; - import { CHAIN_ID_ETH, CHAIN_ID_SOLANA, @@ -2408,7 +2406,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -2417,8 +2414,7 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) - .signers([userTransferAuthority]); + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); const processSwimPayloadPubkeys = await processSwimPayloadIxs.pubkeys(); @@ -2789,7 +2785,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -2798,8 +2793,7 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) - .signers([userTransferAuthority]); + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); @@ -3168,7 +3162,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -3177,9 +3170,7 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) - - .signers([userTransferAuthority]); + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); @@ -3573,7 +3564,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -3582,8 +3572,7 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) - .signers([userTransferAuthority]); + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); const processSwimPayloadPubkeys = await processSwimPayloadIxs.pubkeys(); @@ -3988,7 +3977,6 @@ describe("propeller", () => { poolTokenAccount1, lpMint, governanceFee: governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0, userTokenAccount1, userLpTokenAccount, @@ -3997,8 +3985,7 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) - .signers([userTransferAuthority]); + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); diff --git a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts index 3de28449e..75c577b1f 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts @@ -542,7 +542,6 @@ export const generatePropellerEngineTxns = async ( twoPoolProgram: Program, splToken: Program, aggregator: web3.PublicKey, - userTransferAuthority: web3.Keypair, ): Promise => { let txns: readonly web3.Transaction[] = []; const { @@ -786,7 +785,6 @@ export const generatePropellerEngineTxns = async ( redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, tokenIdMap: tokenIdMapAddr, - userTransferAuthority: userTransferAuthority.publicKey, userSwimUsdAta: userSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, @@ -802,7 +800,7 @@ export const generatePropellerEngineTxns = async ( owner, }) .preInstructions([requestUnitsIx]) - .signers([userTransferAuthority, payer]) + .signers([payer]) .transaction(); txns = [...txns, propellerProcessSwimPayloadFallbackTxn]; } else { @@ -895,7 +893,6 @@ export const generatePropellerEngineTxns = async ( poolTokenAccount1: tokenIdMapPoolInfo.tokenAccounts[1], lpMint: tokenIdMapPoolInfo.lpMint, governanceFee: tokenIdMapPoolInfo.governanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0: ownerAtaAddrs[0], userTokenAccount1: ownerAtaAddrs[1], userLpTokenAccount: ownerAtaAddrs[2], @@ -948,7 +945,7 @@ export const generatePropellerEngineTxns = async ( memo: MEMO_PROGRAM_ID, }) .preInstructions([requestUnitsIx]) - .signers([userTransferAuthority, payer]) + .signers([payer]) .transaction(); txns = [...txns, propellerProcessSwimPayloadTxn]; } diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index aa0fc01f5..66272b0c3 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -2169,11 +2169,6 @@ "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -3089,11 +3084,6 @@ "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -3236,7 +3226,8 @@ "isMut": true, "isSigner": false, "docs": [ - "This is for transferring lamports for kickstart" + "This is for transferring lamports for kickstart", + "TODO: force this to be system account?" ] }, { @@ -3683,12 +3674,33 @@ "docs": [ "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" - ] - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true + ], + "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": "userSwimUsdAta", diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 46a9ff7e0..b45ba56c4 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -2169,11 +2169,6 @@ export type Propeller = { "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -3089,11 +3084,6 @@ export type Propeller = { "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -3236,7 +3226,8 @@ export type Propeller = { "isMut": true, "isSigner": false, "docs": [ - "This is for transferring lamports for kickstart" + "This is for transferring lamports for kickstart", + "TODO: force this to be system account?" ] }, { @@ -3683,12 +3674,33 @@ export type Propeller = { "docs": [ "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" - ] - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true + ], + "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": "userSwimUsdAta", @@ -6945,11 +6957,6 @@ export const IDL: Propeller = { "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -7865,11 +7872,6 @@ export const IDL: Propeller = { "isMut": true, "isSigner": false }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, { "name": "userTokenAccount0", "isMut": true, @@ -8012,7 +8014,8 @@ export const IDL: Propeller = { "isMut": true, "isSigner": false, "docs": [ - "This is for transferring lamports for kickstart" + "This is for transferring lamports for kickstart", + "TODO: force this to be system account?" ] }, { @@ -8459,12 +8462,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" - ] - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true + ], + "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": "userSwimUsdAta", From 948337e865a6bc88b78e57e9508dd039291d3d95 Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 5 Oct 2022 06:32:22 -0400 Subject: [PATCH 03/17] refactor(solana-contracts): remove unused test variables --- .../src/__tests__/propeller/engine.test.ts | 8 +------- .../src/__tests__/propeller/propeller.test.ts | 5 ----- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts index 5f0a0cd80..c191c8702 100644 --- a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts @@ -970,8 +970,7 @@ describe("propeller", () => { twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) - .preInstructions([setComputeUnitLimitIx]) - .signers([propellerEngineKeypair]); + .preInstructions([setComputeUnitLimitIx]); const completeNativeWithPayloadPubkeys = await completeNativeWithPayloadIxs.pubkeys(); @@ -1271,8 +1270,6 @@ describe("propeller", () => { ) ).feesOwed; - const userTransferAuthority = web3.Keypair.generate(); - const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -1989,7 +1986,6 @@ describe("propeller", () => { ) ).feesOwed; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -4260,7 +4256,6 @@ describe("propeller", () => { ) ).feesOwed; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -6143,7 +6138,6 @@ describe("propeller", () => { ) ).feesOwed; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index fd443c54f..5e31d4b1f 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -2373,7 +2373,6 @@ describe("propeller", () => { const userTokenAccount1 = userUsdtAtaAddr; const userLpTokenAccount = userSwimUsdAtaAddr; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -2749,7 +2748,6 @@ describe("propeller", () => { const userTokenAccount1 = userUsdtAtaAddr; const userLpTokenAccount = userSwimUsdAtaAddr; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -3126,7 +3124,6 @@ describe("propeller", () => { // user's lp token account. should be unchanged. const userLpTokenAccount = userMetapoolLpTokenAccount; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -3529,7 +3526,6 @@ describe("propeller", () => { const userTokenAccount1 = userUsdtAtaAddr; const userLpTokenAccount = userSwimUsdAtaAddr; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, @@ -3941,7 +3937,6 @@ describe("propeller", () => { const userTokenAccount1 = userUsdtAtaAddr; const userLpTokenAccount = userSwimUsdAtaAddr; - const userTransferAuthority = web3.Keypair.generate(); const swimPayloadMessageAccount = await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, From 16bb539f9e49390334c11e7c52b02487eb727e3b Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 5 Oct 2022 07:36:08 -0400 Subject: [PATCH 04/17] style(solana-contracts): run clippy --fix --- .../programs/two-pool/src/amp_factor.rs | 2 -- .../programs/two-pool/src/decimal.rs | 6 ++-- .../programs/two-pool/src/instructions/add.rs | 8 ----- .../governance/adjust_amp_factor.rs | 3 +- .../change_governance_fee_account.rs | 3 +- .../governance/create_lp_metadata.rs | 3 +- .../governance/enact_fee_change.rs | 3 +- .../governance/enact_governance_transition.rs | 3 +- .../src/instructions/governance/mpl.rs | 6 ++-- .../prepare_governance_transition.rs | 3 +- .../src/instructions/governance/set_paused.rs | 4 +-- .../governance/update_lp_metadata.rs | 6 ++-- .../two-pool/src/instructions/initialize.rs | 2 +- .../src/instructions/marginal_prices.rs | 9 ++--- .../src/instructions/remove_exact_burn.rs | 6 ++-- .../src/instructions/remove_exact_output.rs | 4 +-- .../src/instructions/remove_uniform.rs | 2 +- .../src/instructions/swap_exact_input.rs | 4 +-- .../src/instructions/swap_exact_output.rs | 12 ++----- .../programs/two-pool/src/invariant.rs | 34 +++++++++---------- .../programs/two-pool/src/lib.rs | 1 - .../programs/two-pool/src/state.rs | 6 ++-- 22 files changed, 50 insertions(+), 80 deletions(-) diff --git a/packages/solana-contracts/programs/two-pool/src/amp_factor.rs b/packages/solana-contracts/programs/two-pool/src/amp_factor.rs index ba2cc6222..d8fa85776 100644 --- a/packages/solana-contracts/programs/two-pool/src/amp_factor.rs +++ b/packages/solana-contracts/programs/two-pool/src/amp_factor.rs @@ -1,8 +1,6 @@ use { crate::{decimal::DecimalU64, error::PoolError, DecimalU64Anchor}, anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}, - rust_decimal::prelude::*, - rust_decimal_macros::dec, std::ops::{Add, Sub}, }; diff --git a/packages/solana-contracts/programs/two-pool/src/decimal.rs b/packages/solana-contracts/programs/two-pool/src/decimal.rs index 8f2942096..7a8b7bd50 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::{BorshDeserialize, BorshSchema, BorshSerialize}, + borsh::{BorshSchema}, std::{ cmp, cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, @@ -63,7 +63,7 @@ const U128_MAX_DECIMALS: usize = 39; const TEN_TO_THE: [u128; U128_MAX_DECIMALS] = create_ten_to_the(); const fn create_ten_to_the() -> [u128; U128_MAX_DECIMALS] { - let mut ttt = [1 as u128; U128_MAX_DECIMALS]; + let mut ttt = [1_u128; U128_MAX_DECIMALS]; let mut i = 1; loop { //const functions can't use for loops @@ -118,7 +118,7 @@ pub const BIT_TO_DEC_ARRAY: [u8; BIT_TO_DEC_SIZE] = create_bit_to_dec_array(); const fn create_bit_to_dec_array() -> [u8; BIT_TO_DEC_SIZE] { let mut btd = [0; BIT_TO_DEC_SIZE]; let mut pot: u128 = 10; - let mut i = 1 as usize; //we start with the second iteration + let mut i = 1_usize; //we start with the second iteration loop { //const functions can't use for loops let jump = ((1 << i as u128) / pot) as u8; 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 0d6562ae6..ddba3ae10 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -2,14 +2,6 @@ use { crate::{decimal::U128, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, anchor_lang::{ prelude::*, - solana_program::{ - borsh::try_from_slice_unchecked, - instruction::Instruction, - program::{get_return_data, invoke, invoke_signed}, - program_option::COption, - system_instruction::transfer, - sysvar::SysvarId, - }, }, anchor_spl::{ associated_token::get_associated_token_address, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs index e8f60bb5f..16a2c25c8 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs @@ -1,7 +1,6 @@ use { crate::{ - common_governance::*, error::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, - UnixTimestamp, + common_governance::*, get_current_ts, DecimalU64Anchor, }, anchor_lang::prelude::*, }; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs index 901283f97..212b91ee8 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs @@ -1,7 +1,6 @@ use { crate::{ - common_governance::*, error::*, get_current_ts, state::TwoPool, DecimalU64, DecimalU64Anchor, PoolFee, - UnixTimestamp, + common_governance::*, error::*, }, anchor_lang::prelude::*, anchor_spl::token::TokenAccount, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs index 08c4ba604..1e0eb3771 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs @@ -1,11 +1,10 @@ use { - crate::{common_governance::*, error::*, gen_pool_signer_seeds, AnchorDataV2, TwoPool}, + crate::{common_governance::*, error::*, gen_pool_signer_seeds, AnchorDataV2}, anchor_lang::prelude::*, anchor_spl::{ metadata::{create_metadata_accounts_v2, CreateMetadataAccountsV2, Metadata}, token::Mint, }, - mpl_token_metadata::state::{DataV2, PREFIX}, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs index 7edca329e..f2237e2bf 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs @@ -1,7 +1,6 @@ use { crate::{ - common_governance::*, error::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, PoolFee, - UnixTimestamp, + common_governance::*, error::*, get_current_ts, PoolFee, }, anchor_lang::prelude::*, }; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs index 718f12410..d00a7621b 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs @@ -1,7 +1,6 @@ use { crate::{ - common_governance::*, error::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, PoolFee, - UnixTimestamp, + common_governance::*, error::*, get_current_ts, }, anchor_lang::prelude::*, }; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs index 26f906676..fbca2aa41 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs @@ -37,7 +37,7 @@ impl From for DataV2 { } } -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Debug, Clone, Copy)] +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] pub struct AnchorCreator { pub address: Pubkey, pub verified: bool, @@ -51,7 +51,7 @@ impl From for Creator { } } -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Debug, Clone, Copy)] +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] pub enum AnchorUseMethod { Burn, Multiple, @@ -81,7 +81,7 @@ impl From for UseMethod { } } -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Debug, Clone, Copy)] +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] pub struct AnchorCollection { pub verified: bool, pub key: Pubkey, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs index b2e32982d..42beba854 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs @@ -1,7 +1,6 @@ use { crate::{ - common_governance::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, PoolFee, - UnixTimestamp, + common_governance::*, get_current_ts, governance::ENACT_DELAY, }, anchor_lang::prelude::*, }; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs index e8c13ec66..2954883ad 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs @@ -1,7 +1,7 @@ use { crate::{ - common_governance::*, error::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, PoolFee, - TwoPool, UnixTimestamp, + error::*, + TwoPool, }, anchor_lang::prelude::*, }; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs index ac93b57bc..7648192b6 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs @@ -1,14 +1,12 @@ use { - crate::{common_governance::*, error::*, gen_pool_signer_seeds, AnchorDataV2, TwoPool}, + crate::{common_governance::*, gen_pool_signer_seeds, AnchorDataV2}, anchor_lang::prelude::*, anchor_spl::{ metadata::{ - create_metadata_accounts_v2, update_metadata_accounts_v2, CreateMetadataAccountsV2, Metadata, + update_metadata_accounts_v2, Metadata, UpdateMetadataAccountsV2, }, - token::Mint, }, - mpl_token_metadata::state::{DataV2, PREFIX}, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs index 3f72464ae..92e18a700 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs @@ -1,5 +1,5 @@ use { - crate::{decimal::DecimalU64, error::PoolError::*, AmpFactor, DecimalU64Anchor, PoolError, PoolFee, TwoPool}, + crate::{decimal::DecimalU64, AmpFactor, DecimalU64Anchor, PoolError, PoolFee, TwoPool}, anchor_lang::prelude::*, anchor_spl::{ associated_token::{get_associated_token_address, AssociatedToken}, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs b/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs index f87977783..f9fcbbfb3 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs @@ -1,15 +1,12 @@ use { crate::{ - array_equalize, common::create_array, decimal::U128, error::*, invariant::Invariant, to_equalized, AmpFactor, - BorshDecimal, DecimalU64Anchor, TwoPool, TOKEN_COUNT, + array_equalize, common::create_array, error::*, invariant::Invariant, to_equalized, + BorshDecimal, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, + token::{Mint, TokenAccount}, }, - rust_decimal::Decimal, - std::iter::zip, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs index c5c51c8d9..b5d951623 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs @@ -123,8 +123,8 @@ pub fn handle_remove_exact_burn( let pool_token_account_0 = &ctx.accounts.pool_token_account_0; let pool_token_account_1 = &ctx.accounts.pool_token_account_1; let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let lp_mint = &ctx.accounts.lp_mint; - let governance_fee = &ctx.accounts.governance_fee; + let _lp_mint = &ctx.accounts.lp_mint; + let _governance_fee = &ctx.accounts.governance_fee; // let user_transfer_auth = &ctx.accounts.user_transfer_authority; let user_token_account_0 = &ctx.accounts.user_token_account_0; let user_token_account_1 = &ctx.accounts.user_token_account_1; @@ -154,7 +154,7 @@ pub fn handle_remove_exact_burn( let minimum_output_amount = remove_exact_burn_params.minimum_output_amount; require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); token::burn( CpiContext::new( ctx.accounts.token_program.to_account_info(), diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs index b3f1dd1ab..2971b92b8 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs @@ -127,8 +127,8 @@ pub fn handle_remove_exact_output( let pool = &ctx.accounts.pool; let pool_token_account_0 = &ctx.accounts.pool_token_account_0; let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let lp_mint = &ctx.accounts.lp_mint; - let governance_fee = &ctx.accounts.governance_fee; + let _lp_mint = &ctx.accounts.lp_mint; + let _governance_fee = &ctx.accounts.governance_fee; // let user_transfer_auth = &ctx.accounts.user_transfer_authority; let user_token_account_0 = &ctx.accounts.user_token_account_0; let user_token_account_1 = &ctx.accounts.user_token_account_1; 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 a92a612fa..b9f21168d 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,6 +1,6 @@ use { crate::{ - array_equalize, error::*, gen_pool_signer_seeds, invariant::Invariant, result_from_equalized, to_equalized, + error::*, gen_pool_signer_seeds, DecimalU64, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs index 48aa48b49..8d0974758 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs @@ -137,8 +137,8 @@ pub fn handle_swap_exact_input( let pool_token_account_0 = &ctx.accounts.pool_token_account_0; let pool_token_account_1 = &ctx.accounts.pool_token_account_1; let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let lp_mint = &ctx.accounts.lp_mint; - let governance_fee = &ctx.accounts.governance_fee; + let _lp_mint = &ctx.accounts.lp_mint; + let _governance_fee = &ctx.accounts.governance_fee; // let user_transfer_auth = &ctx.accounts.user_transfer_authority; let user_token_account_0 = &ctx.accounts.user_token_account_0; let user_token_account_1 = &ctx.accounts.user_token_account_1; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs index 549c6152b..f6fe1da94 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs @@ -5,14 +5,6 @@ use { }, anchor_lang::{ prelude::*, - solana_program::{ - borsh::try_from_slice_unchecked, - instruction::Instruction, - program::{get_return_data, invoke, invoke_signed}, - program_option::COption, - system_instruction::transfer, - sysvar::SysvarId, - }, }, anchor_spl::{ token, @@ -148,8 +140,8 @@ pub fn handle_swap_exact_output( let pool_token_account_0 = &ctx.accounts.pool_token_account_0; let pool_token_account_1 = &ctx.accounts.pool_token_account_1; let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let lp_mint = &ctx.accounts.lp_mint; - let governance_fee = &ctx.accounts.governance_fee; + let _lp_mint = &ctx.accounts.lp_mint; + let _governance_fee = &ctx.accounts.governance_fee; // let user_transfer_auth = &ctx.accounts.user_transfer_authority; let user_token_account_0 = &ctx.accounts.user_token_account_0; let user_token_account_1 = &ctx.accounts.user_token_account_1; diff --git a/packages/solana-contracts/programs/two-pool/src/invariant.rs b/packages/solana-contracts/programs/two-pool/src/invariant.rs index 6aabc1e50..40568f6ee 100644 --- a/packages/solana-contracts/programs/two-pool/src/invariant.rs +++ b/packages/solana-contracts/programs/two-pool/src/invariant.rs @@ -63,7 +63,7 @@ impl From for DecT { let d = min(value.scale() as u8, unused_decimals_lower_bound); (value * Decimal::from(decimal::ten_to_the(d)), d) }; - Self::new(v.to_u64().unwrap(), d.into()).unwrap() + Self::new(v.to_u64().unwrap(), d).unwrap() } } @@ -159,7 +159,7 @@ impl Invariant { ) -> InvariantResult<(AmountT, AmountT, AmountT)> { let amp_factor: Decimal = amp_factor.into(); if lp_total_supply.is_zero() { - let depth = fast_round(Self::calculate_depth(&input_amounts, amp_factor, previous_depth.into())?); + let depth = fast_round(Self::calculate_depth(input_amounts, amp_factor, previous_depth.into())?); Ok((depth, 0.into(), depth)) } else { let lp_fee: FeeT = lp_fee.into(); @@ -167,8 +167,8 @@ impl Invariant { let total_fee = lp_fee + governance_fee; Self::add_remove( true, - &input_amounts, - &pool_balances, + input_amounts, + pool_balances, amp_factor, total_fee, governance_fee, @@ -194,9 +194,9 @@ impl Invariant { let total_fee = lp_fee + governance_fee; Self::swap( true, - &input_amounts, + input_amounts, output_index, - &pool_balances, + pool_balances, amp_factor, total_fee, governance_fee, @@ -221,9 +221,9 @@ impl Invariant { let total_fee = lp_fee + governance_fee; Self::swap( false, - &output_amounts, + output_amounts, input_index, - &pool_balances, + pool_balances, amp_factor, total_fee, governance_fee, @@ -249,7 +249,7 @@ impl Invariant { Self::remove_exact_burn_impl( burn_amount, output_index, - &pool_balances, + pool_balances, amp_factor, total_fee, governance_fee, @@ -273,8 +273,8 @@ impl Invariant { let total_fee = lp_fee + governance_fee; Self::add_remove( false, - &output_amounts, - &pool_balances, + output_amounts, + pool_balances, amp_factor, total_fee, governance_fee, @@ -323,7 +323,7 @@ impl Invariant { let initial_depth = Self::calculate_depth(pool_balances, amp_factor, previous_depth.into())?; // println!("SWAP initial_depth: {}", initial_depth); let mut updated_balances = - binary_op_balances(if is_exact_input { AmountT::add } else { AmountT::sub }, &pool_balances, &amounts); + binary_op_balances(if is_exact_input { AmountT::add } else { AmountT::sub }, pool_balances, amounts); // println!("SWAP updated_balances: {:?}", updated_balances); let swap_base_balances = &(if is_exact_input && !total_fee.is_zero() { let input_fee_amounts = unary_op_balances(|v| fast_round(total_fee * Decimal::from(v)), amounts); @@ -387,7 +387,7 @@ impl Invariant { ) -> InvariantResult<(AmountT, AmountT, AmountT)> { let initial_depth = Self::calculate_depth(pool_balances, amp_factor, previous_depth.into())?; let updated_balances = - binary_op_balances(if is_add { AmountT::add } else { AmountT::sub }, &pool_balances, &amounts); + binary_op_balances(if is_add { AmountT::add } else { AmountT::sub }, pool_balances, amounts); let sum_updated_balances = sum_balances(&updated_balances); let sum_pool_balances = sum_balances(pool_balances); let updated_depth = Self::calculate_depth( @@ -481,17 +481,17 @@ impl Invariant { previous_depth: AmountT, ) -> InvariantResult<(AmountT, AmountT, AmountT)> { debug_assert!(burn_amount > AmountT::zero()); - let initial_depth = Self::calculate_depth(&pool_balances, amp_factor, previous_depth.into())?; + let initial_depth = Self::calculate_depth(pool_balances, amp_factor, previous_depth.into())?; let updated_depth = initial_depth * (Decimal::from(lp_total_supply - burn_amount) / Decimal::from(lp_total_supply)); debug_assert!(initial_depth > updated_depth); - let known_balances = exclude_index(output_index, &pool_balances); + let known_balances = exclude_index(output_index, pool_balances); //we can pass the original pool balance as an initial guess because we know that the unknown balance has to be smaller let unknown_balance = Self::calculate_unknown_balance(&known_balances, updated_depth, amp_factor, pool_balances[output_index])?; let base_amount = pool_balances[output_index] - unknown_balance; let (output_amount, governance_mint_amount) = if !total_fee.is_zero() { - let sum_pool_balances = sum_balances(&pool_balances); + let sum_pool_balances = sum_balances(pool_balances); let taxable_percentage = Decimal::from(sum_pool_balances - pool_balances[output_index]) / Decimal::from(sum_pool_balances); let fee = Decimal::one() / (Decimal::one() - total_fee) - Decimal::one(); @@ -530,7 +530,7 @@ impl Invariant { } let pool_balances_times_n: [_; TOKEN_COUNT] = - create_array(|i| U128::from(pool_balances[i]) * AmountT::from(TOKEN_COUNT)); + create_array(|i| pool_balances[i] * AmountT::from(TOKEN_COUNT)); let pool_balances_sum = sum_balances(pool_balances); // use f64 to calculate either the exact result (if there's sufficient precision) or an updated initial guess diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index 08e49942d..6b6caba73 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -10,7 +10,6 @@ use { state::TwoPool, }, anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}, - anchor_spl::token::*, }; pub mod amp_factor; diff --git a/packages/solana-contracts/programs/two-pool/src/state.rs b/packages/solana-contracts/programs/two-pool/src/state.rs index 6f05e8d2a..771200e38 100644 --- a/packages/solana-contracts/programs/two-pool/src/state.rs +++ b/packages/solana-contracts/programs/two-pool/src/state.rs @@ -1,6 +1,6 @@ use { - crate::{amp_factor::AmpFactor, error::*, pool_fee::PoolFee, TOKEN_COUNT}, - anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}, + crate::{amp_factor::AmpFactor, pool_fee::PoolFee, TOKEN_COUNT}, + anchor_lang::{prelude::*}, }; // use pool_lib::amp_factor::AmpFactor; @@ -63,7 +63,7 @@ impl TwoPool { // token_mint_keys 32 * TOKEN_COUNT + // token_decimal_equalizers - 1 * TOKEN_COUNT + + TOKEN_COUNT + // token_keys 32 * TOKEN_COUNT + // pause_key From 9b30e2ebc7fa3c40fec782e79a0d19c68a1c4250 Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 5 Oct 2022 08:16:06 -0400 Subject: [PATCH 05/17] refactor(solana-contracts): refactor equalize related fns into common --- .../programs/two-pool/src/common.rs | 58 ++++- .../programs/two-pool/src/instructions/add.rs | 223 ++---------------- .../src/instructions/marginal_prices.rs | 8 +- .../src/instructions/remove_exact_burn.rs | 5 +- .../src/instructions/remove_exact_output.rs | 7 +- .../src/instructions/swap_exact_input.rs | 5 +- .../src/instructions/swap_exact_output.rs | 9 +- .../programs/two-pool/src/invariant.rs | 8 +- .../programs/two-pool/src/lib.rs | 4 +- 9 files changed, 102 insertions(+), 225 deletions(-) diff --git a/packages/solana-contracts/programs/two-pool/src/common.rs b/packages/solana-contracts/programs/two-pool/src/common.rs index a77692b66..c43d1bb82 100644 --- a/packages/solana-contracts/programs/two-pool/src/common.rs +++ b/packages/solana-contracts/programs/two-pool/src/common.rs @@ -1,4 +1,8 @@ -use {arrayvec::ArrayVec, std::fmt::Debug}; +use { + crate::{decimal::U128, TOKEN_COUNT}, + arrayvec::ArrayVec, + std::fmt::Debug, +}; //final unwraps are safe because we know that there is enough capacity @@ -11,3 +15,55 @@ pub fn create_result_array( ) -> Result<[T; SIZE], E> { Ok((0..SIZE).into_iter().map(closure).collect::, _>>()?.into_inner().unwrap()) } + +pub fn to_equalized(value: u64, equalizer: u8) -> U128 { + if equalizer > 0 { + U128::from(value) * U128::ten_to_the(equalizer) + } else { + U128::from(value) + } +} + +pub fn from_equalized(value: U128, equalizer: u8) -> u64 { + if equalizer > 0 { + ((value + U128::ten_to_the(equalizer - 1) * 5u64) / U128::ten_to_the(equalizer)).as_u64() + } else { + value.as_u64() + } +} + +pub fn array_equalize(amounts: [u64; TOKEN_COUNT], equalizers: [u8; TOKEN_COUNT]) -> [U128; TOKEN_COUNT] { + amounts + .iter() + .zip(equalizers.iter()) + .map(|(&amount, &equalizer)| to_equalized(amount, equalizer)) + .collect::>() + .as_slice() + .try_into() + .unwrap() +} + +/// `result_from_equalized` takes in a user's amount, the user's equalizer, the governance mint amount, +/// the lp decimal equalizer, and the latest depth, and returns the user's amount, the governance mint +/// amount, and the latest depth +/// +/// Arguments: +/// +/// * `user_amount`: The amount of tokens the user is staking +/// * `user_equalizer`: The equalizer of the user's token. +/// * `governance_mint_amount`: The amount of governance tokens that will be minted to the user. +/// * `lp_decimal_equalizer`: The equalizer for the LP token. should always be pool_state.lp_decimal_equalizer +/// * `latest_depth`: The amount of liquidity in the pool. +pub fn result_from_equalized( + user_amount: U128, + user_equalizer: u8, + governance_mint_amount: U128, + lp_decimal_equalizer: u8, + latest_depth: U128, +) -> (u64, u64, u128) { + ( + from_equalized(user_amount, user_equalizer), + from_equalized(governance_mint_amount, lp_decimal_equalizer), + latest_depth.as_u128(), + ) +} 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 ddba3ae10..aa5dd7d1f 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -1,8 +1,6 @@ use { - crate::{decimal::U128, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, - anchor_lang::{ - prelude::*, - }, + crate::{common, decimal::U128, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, + anchor_lang::prelude::*, anchor_spl::{ associated_token::get_associated_token_address, token::{self, Mint, Token, TokenAccount}, @@ -125,33 +123,25 @@ pub fn handle_add( let lp_total_supply = ctx.accounts.lp_mint.supply; //initial add to pool must add all tokens if lp_total_supply == 0 { - for i in 0..TOKEN_COUNT { - require_gt!(input_amounts[i], 0u64, PoolError::InitialAddRequiresAllTokens); - } + require!(input_amounts.iter().all(|&x| x > 0), PoolError::InitialAddRequiresAllTokens); } let pool = &ctx.accounts.pool; let user_token_accounts = [&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; let pool_token_accounts = [&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; - // let pool_balances = pool_token_accounts - // .iter() - // .map(|account| account.amount) - // .collect::>() - // .as_slice() - // .try_into().unwrap(); let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; let current_ts = Clock::get()?.unix_timestamp; require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); let (user_amount, governance_mint_amount, latest_depth) = Invariant::::add( - &array_equalize(input_amounts, pool.token_decimal_equalizers), - &array_equalize(pool_balances, pool.token_decimal_equalizers), + &common::array_equalize(input_amounts, pool.token_decimal_equalizers), + &common::array_equalize(pool_balances, pool.token_decimal_equalizers), pool.amp_factor.get(current_ts), pool.lp_fee.get(), pool.governance_fee.get(), - to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + common::to_equalized(lp_total_supply, pool.lp_decimal_equalizer), pool.previous_depth.into(), )?; - let (mint_amount, governance_mint_amount, latest_depth) = result_from_equalized( + let (mint_amount, governance_mint_amount, latest_depth) = common::result_from_equalized( user_amount, pool.lp_decimal_equalizer, governance_mint_amount, @@ -160,20 +150,22 @@ pub fn handle_add( ); require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - for i in 0..TOKEN_COUNT { + for input_amount in input_amounts.iter().take(TOKEN_COUNT) { let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if input_amounts[i] > 0 { + if *input_amount > 0u64 { + let pool_token_account = pool_token_account.to_account_info(); + let user_token_account = user_token_account.to_account_info(); + let user_transfer_authority = ctx.accounts.user_transfer_authority.to_account_info(); token::transfer( CpiContext::new( ctx.accounts.token_program.to_account_info(), token::Transfer { - // source - from: user_token_account.to_account_info(), - to: pool_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), + from: user_token_account.clone(), + to: pool_token_account.clone(), + authority: user_transfer_authority.clone(), }, ), - input_amounts[i], + *input_amount, )?; } } @@ -211,187 +203,4 @@ pub fn handle_add( let pool_state = &mut ctx.accounts.pool; pool_state.previous_depth = latest_depth; Ok(mint_amount) - // msg!("add_and_wormhole_transfer"); - // handle_approve(&ctx, &pool_add_params)?; - // - // let mint_amount = handle_add_liquidity(&ctx, pool_add_params)?; - // msg!("finished add_liquidity. mint_amount: {}", mint_amount); - // - // revoke(&ctx) - // - // // Ok(mint_amount) -} - -pub fn to_equalized(value: u64, equalizer: u8) -> U128 { - if equalizer > 0 { - U128::from(value) * U128::ten_to_the(equalizer) - } else { - U128::from(value) - } } - -pub fn from_equalized(value: U128, equalizer: u8) -> u64 { - if equalizer > 0 { - ((value + U128::ten_to_the(equalizer - 1) * 5u64) / U128::ten_to_the(equalizer)).as_u64() - } else { - value.as_u64() - } -} - -pub fn array_equalize(amounts: [u64; TOKEN_COUNT], equalizers: [u8; TOKEN_COUNT]) -> [U128; TOKEN_COUNT] { - amounts - .iter() - .zip(equalizers.iter()) - .map(|(&amount, &equalizer)| to_equalized(amount, equalizer)) - .collect::>() - .as_slice() - .try_into() - .unwrap() -} - -/// `result_from_equalized` takes in a user's amount, the user's equalizer, the governance mint amount, -/// the lp decimal equalizer, and the latest depth, and returns the user's amount, the governance mint -/// amount, and the latest depth -/// -/// Arguments: -/// -/// * `user_amount`: The amount of tokens the user is staking -/// * `user_equalizer`: The equalizer of the user's token. -/// * `governance_mint_amount`: The amount of governance tokens that will be minted to the user. -/// * `lp_decimal_equalizer`: The equalizer for the LP token. should always be pool_state.lp_decimal_equalizer -/// * `latest_depth`: The amount of liquidity in the pool. -pub fn result_from_equalized( - user_amount: U128, - user_equalizer: u8, - governance_mint_amount: U128, - lp_decimal_equalizer: u8, - latest_depth: U128, -) -> (u64, u64, u128) { - ( - from_equalized(user_amount, user_equalizer), - from_equalized(governance_mint_amount, lp_decimal_equalizer), - latest_depth.as_u128(), - ) -} -// -// pub fn handle_approve( -// ctx: &Context, -// pool_add_params: &AddParams, -// ) -> Result<()> { -// msg!("[handle_approve]: approve"); -// token::approve( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Approve { -// // source -// to: ctx.accounts.user_token_account_0.to_account_info(), -// delegate: ctx.accounts.pool_auth.to_account_info(), -// authority: ctx.accounts.payer.to_account_info(), -// }, -// ), -// pool_add_params.input_amounts[0], -// )?; -// -// token::approve( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Approve { -// // source -// to: ctx.accounts.user_token_account_1.to_account_info(), -// delegate: ctx.accounts.pool_auth.to_account_info(), -// authority: ctx.accounts.payer.to_account_info(), -// }, -// ), -// pool_add_params.input_amounts[1], -// )?; -// msg!("[handle_approve]: finished approves"); -// Ok(()) -// } -// -// pub fn handle_add_liquidity( -// ctx: &Context, -// pool_add_params: AddParams -// ) -> Result { -// let pool_program = &ctx.accounts.pool_program; -// let pool = &ctx.accounts.pool_state; -// let pool_auth = &ctx.accounts.pool_auth; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let lp_mint = &ctx.accounts.lp_mint; -// let governance_fee = &ctx.accounts.governance_fee; -// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_lp_token_account = &ctx.accounts.user_lp_token_account; -// // let token_program = &self.token_program; -// -// let add_defi_ix = two_pool::instruction::DeFiInstruction::Add{ -// input_amounts: pool_add_params.input_amounts, -// minimum_mint_amount: pool_add_params.minimum_mint_amount -// }; -// let add_ix = two_pool::instruction::create_defi_ix( -// add_defi_ix, -// &pool_program.key(), -// &pool.key(), -// &pool_auth.key(), -// &[ -// pool_token_account_0.key(), -// pool_token_account_1.key() -// ], -// &lp_mint.key(), -// &governance_fee.key(), -// &pool_auth.key(), -// // &user_transfer_auth.key(), -// &[ -// user_token_account_0.key(), -// user_token_account_1.key() -// ], -// Some(&user_lp_token_account.key()), -// )?; -// invoke( -// &add_ix, -// &ctx.accounts.to_account_infos(), -// )?; -// let (program_id, data) = get_return_data().unwrap(); -// //.unwrap_or_else(PropellerError::InvalidCpiReturnValue); -// require_keys_eq!(program_id, ctx.accounts.pool_program.key(), PropellerError::InvalidCpiReturnProgramId); -// Ok(u64::try_from_slice(&data).map_err(|_| PropellerError::InvalidCpiReturnValue)?) -// } -// -// pub fn revoke(ctx: &Context) -> Result<()> { -// msg!("[revoke]: revoke"); -// token::revoke( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Revoke { -// // source -// source: ctx.accounts.user_token_account_0.to_account_info(), -// authority: ctx.accounts.payer.to_account_info(), -// }, -// ) -// )?; -// token::revoke( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Revoke { -// // source -// source: ctx.accounts.user_token_account_1.to_account_info(), -// authority: ctx.accounts.payer.to_account_info(), -// }, -// ) -// )?; -// msg!("Revoked delegate authority for user_token_accounts"); -// token::revoke( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Revoke { -// // source -// source: ctx.accounts.user_lp_token_account.to_account_info(), -// authority: ctx.accounts.payer.to_account_info(), -// }, -// ) -// )?; -// msg!("Revoked delegate authority for user_lp_token_account"); -// msg!("[revoke]: finished revoke"); -// Ok(()) -// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs b/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs index f9fcbbfb3..528ce7086 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/marginal_prices.rs @@ -1,12 +1,12 @@ use { crate::{ - array_equalize, common::create_array, error::*, invariant::Invariant, to_equalized, + common::{array_equalize, create_array, to_equalized}, + error::*, + invariant::Invariant, BorshDecimal, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, - anchor_spl::{ - token::{Mint, TokenAccount}, - }, + anchor_spl::token::{Mint, TokenAccount}, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs index b5d951623..a712c5f65 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs @@ -1,6 +1,9 @@ use { crate::{ - array_equalize, error::*, gen_pool_signer_seeds, invariant::Invariant, result_from_equalized, to_equalized, + common::{array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, + invariant::Invariant, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs index 2971b92b8..4ce3e3b8a 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs @@ -1,7 +1,10 @@ use { crate::{ - array_equalize, error::*, gen_pool_signer_seeds, get_current_ts, invariant::Invariant, result_from_equalized, - to_equalized, TwoPool, TOKEN_COUNT, + common::{array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, get_current_ts, + invariant::Invariant, + TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, anchor_spl::{ diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs index 8d0974758..dff2fadd6 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs @@ -1,6 +1,9 @@ use { crate::{ - array_equalize, error::*, gen_pool_signer_seeds, invariant::Invariant, result_from_equalized, to_equalized, + common::{array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, + invariant::Invariant, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs index f6fe1da94..d749980b9 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs @@ -1,11 +1,12 @@ use { crate::{ - array_equalize, error::*, gen_pool_signer_seeds, invariant::Invariant, result_from_equalized, to_equalized, + common::{array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, + invariant::Invariant, TwoPool, TOKEN_COUNT, }, - anchor_lang::{ - prelude::*, - }, + anchor_lang::prelude::*, anchor_spl::{ token, token::{Mint, Token, TokenAccount}, diff --git a/packages/solana-contracts/programs/two-pool/src/invariant.rs b/packages/solana-contracts/programs/two-pool/src/invariant.rs index 40568f6ee..4c7c391bc 100644 --- a/packages/solana-contracts/programs/two-pool/src/invariant.rs +++ b/packages/solana-contracts/programs/two-pool/src/invariant.rs @@ -529,8 +529,7 @@ impl Invariant { return Ok(((pool_balances[0] * pool_balances[1]).integer_sqrt() * U128::from(2i32)).into()); } - let pool_balances_times_n: [_; TOKEN_COUNT] = - create_array(|i| pool_balances[i] * AmountT::from(TOKEN_COUNT)); + let pool_balances_times_n: [_; TOKEN_COUNT] = create_array(|i| pool_balances[i] * AmountT::from(TOKEN_COUNT)); let pool_balances_sum = sum_balances(pool_balances); // use f64 to calculate either the exact result (if there's sufficient precision) or an updated initial guess @@ -701,7 +700,10 @@ impl Invariant { mod tests { use { super::*, - crate::{array_equalize, decimal::DecimalU128, to_equalized}, + crate::{ + common::{array_equalize, to_equalized}, + decimal::DecimalU128, + }, }; const BASE: AmountT = ten_to_the(10); diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index 6b6caba73..3c54dfa42 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -1,4 +1,3 @@ -use rust_decimal::Decimal; use { crate::{ amp_factor::AmpFactor, @@ -9,7 +8,8 @@ use { pool_fee::PoolFee, state::TwoPool, }, - anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}, + anchor_lang::prelude::*, + rust_decimal::Decimal, }; pub mod amp_factor; From f8c7c7a591b22e9c925ab8a0558e1c39fef5ff97 Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 5 Oct 2022 08:17:49 -0400 Subject: [PATCH 06/17] style: more clippy fixes --- .../programs/two-pool/src/instructions/add.rs | 2 +- .../programs/two-pool/src/instructions/governance/mpl.rs | 4 ++-- .../solana-contracts/programs/two-pool/src/invariant.rs | 4 ++-- packages/solana-contracts/programs/two-pool/src/pool_fee.rs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) 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 aa5dd7d1f..e02aaa550 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -1,5 +1,5 @@ use { - crate::{common, decimal::U128, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, + crate::{common, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, anchor_lang::prelude::*, anchor_spl::{ associated_token::get_associated_token_address, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs index fbca2aa41..3da90dd1c 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs @@ -5,7 +5,7 @@ use { // copied from https://github.com/CalebEverett/nftfactory/blob/master/programs/nftfactory/src/lib.rs -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Debug, Clone)] +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone)] pub struct AnchorDataV2 { /// The name of the asset pub name: String, @@ -58,7 +58,7 @@ pub enum AnchorUseMethod { Single, } -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Debug, Clone, Copy)] +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] pub struct AnchorUses { pub use_method: AnchorUseMethod, pub remaining: u64, diff --git a/packages/solana-contracts/programs/two-pool/src/invariant.rs b/packages/solana-contracts/programs/two-pool/src/invariant.rs index 4c7c391bc..12c3e01e3 100644 --- a/packages/solana-contracts/programs/two-pool/src/invariant.rs +++ b/packages/solana-contracts/programs/two-pool/src/invariant.rs @@ -972,8 +972,8 @@ mod tests { amp_factor, lp_fee, governance_fee, - lp_total_supply.into(), - lp_total_supply.into(), + lp_total_supply, + lp_total_supply, ) .unwrap(); println!( diff --git a/packages/solana-contracts/programs/two-pool/src/pool_fee.rs b/packages/solana-contracts/programs/two-pool/src/pool_fee.rs index c93794ac1..e8524c773 100644 --- a/packages/solana-contracts/programs/two-pool/src/pool_fee.rs +++ b/packages/solana-contracts/programs/two-pool/src/pool_fee.rs @@ -76,7 +76,7 @@ mod tests { fn new_pool_fee2() { let swimlake_fee_value = new_u64(0, 0); let floored_fee = swimlake_fee_value.floor(DECIMALS); - let swimlake_u32 = (floored_fee.get_raw() * 10u64.pow((DECIMALS - floored_fee.get_decimals()) as u32)) as u32; + let _swimlake_u32 = (floored_fee.get_raw() * 10u64.pow((DECIMALS - floored_fee.get_decimals()) as u32)) as u32; // println!("swimlake_u32: {}", swimlake_u32); let swimlake_fee = PoolFee::new(swimlake_fee_value).unwrap(); assert_eq!(swimlake_fee_value, swimlake_fee_value.floor(DECIMALS)); @@ -85,8 +85,8 @@ mod tests { let metapool_fee_value = new_u64(300, 6); let metapool_fee_value2 = new_u64(3, 4); - let metapool_u32 = get_fee_u32(metapool_fee_value); - let metapool2_u32 = get_fee_u32(metapool_fee_value2); + let _metapool_u32 = get_fee_u32(metapool_fee_value); + let _metapool2_u32 = get_fee_u32(metapool_fee_value2); // println!("metapool_u32: {}", metapool_u32); // println!("metapool2_u32: {}", metapool2_u32); From fda77c5f29c84cf4fe6010be6f1a807cf7665311 Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 5 Oct 2022 16:29:27 -0400 Subject: [PATCH 07/17] refactor(solana-contracts): add Fees trait to unify fee handling for propeller-variant ixs --- .../programs/propeller/src/fees.rs | 12 + .../create_owner_token_accounts.rs | 343 ++++++------------ .../src/instructions/process_swim_payload.rs | 190 ++++++++-- .../src/instructions/token_id_map.rs | 7 + .../propeller/src/instructions/utils.rs | 54 +++ .../wormhole/complete_native_with_payload.rs | 21 +- .../wormhole/transfer_native_with_payload.rs | 8 +- .../programs/propeller/src/lib.rs | 2 + .../programs/propeller/src/state/propeller.rs | 29 +- .../programs/two-pool/src/decimal.rs | 2 +- .../programs/two-pool/src/instructions/add.rs | 39 +- .../src/instructions/remove_uniform.rs | 58 +-- .../programs/two-pool/src/invariant.rs | 2 +- .../programs/two-pool/src/lib.rs | 1 - .../src/artifacts/propeller.json | 28 +- .../src/artifacts/propeller.ts | 56 ++- .../src/artifacts/two_pool.json | 4 + .../src/artifacts/two_pool.ts | 8 + 18 files changed, 503 insertions(+), 361 deletions(-) create mode 100644 packages/solana-contracts/programs/propeller/src/fees.rs 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 075a5a22e..79fdee0b4 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 = @@ -246,9 +291,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); @@ -273,56 +318,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( @@ -568,6 +487,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 @@ -626,17 +554,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, @@ -661,53 +594,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<()> { @@ -733,22 +625,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 5dbb5b513..bbbbf4923 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, )?; @@ -803,17 +826,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(()) } @@ -1024,6 +1044,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 746e1a13c..cebb13a2f 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": [ { From 72b491cd51a85c4af66e7693ef93df06054f97f3 Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 11 Oct 2022 20:03:20 -0400 Subject: [PATCH 08/17] refactor(solana-contracts): rename account names in completeWithPayload --- .../programs/propeller/src/error.rs | 6 + .../programs/propeller/src/fees.rs | 11 +- .../propeller/src/instructions/fee_tracker.rs | 19 +- .../propeller/src/instructions/initialize.rs | 1 + .../src/instructions/process_swim_payload.rs | 398 ++++++------------ .../wormhole/complete_native_with_payload.rs | 159 +++---- .../programs/propeller/src/state/propeller.rs | 34 +- .../scripts/initializePropeller.ts | 3 +- .../solana-contracts/src/__tests__/consts.ts | 3 +- .../src/__tests__/propeller/engine.test.ts | 44 +- .../src/__tests__/propeller/propeller.test.ts | 139 ++---- .../src/__tests__/propeller/propellerUtils.ts | 234 +++++++++- .../src/artifacts/propeller.json | 62 ++- .../src/artifacts/propeller.ts | 124 ++++-- 14 files changed, 650 insertions(+), 587 deletions(-) diff --git a/packages/solana-contracts/programs/propeller/src/error.rs b/packages/solana-contracts/programs/propeller/src/error.rs index 9e4599a29..18b4963b6 100644 --- a/packages/solana-contracts/programs/propeller/src/error.rs +++ b/packages/solana-contracts/programs/propeller/src/error.rs @@ -108,6 +108,9 @@ pub enum PropellerError { #[msg("Invalid Gas Kickstart parameter in Swim Payload")] InvalidSwimPayloadGasKickstart, + #[msg("Invalid Marginal Price Pool")] + InvalidMarginalPricePool, + #[msg("Invalid Marginal Price Pool Accounts")] InvalidMarginalPricePoolAccounts, @@ -152,4 +155,7 @@ pub enum PropellerError { #[msg("Invalid Aggregator")] InvalidAggregator, + + #[msg("Invalid Fee Vault")] + InvalidFeeVault, } diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs index b7ed50207..6ca08b179 100644 --- a/packages/solana-contracts/programs/propeller/src/fees.rs +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -1,12 +1,9 @@ use {crate::TOKEN_COUNT, anchor_lang::prelude::*, two_pool::BorshDecimal}; -pub trait Fees { +pub trait Fees<'info> { + /// Calculating the fees, including txn and rent exmptions, in lamports. 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 get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]>; + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result; fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()>; } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs b/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs index c448fb51c..8bf0055cf 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs @@ -2,7 +2,7 @@ use { crate::{error::*, Propeller}, anchor_lang::prelude::*, anchor_spl::{ - associated_token::{create, AssociatedToken, Create}, + associated_token::{create, get_associated_token_address, AssociatedToken, Create}, token::{self, Mint, Token, TokenAccount, Transfer}, }, two_pool::state::TwoPool, @@ -50,7 +50,7 @@ impl<'info> InitializeFeeTracker<'info> { pub fn handle_initialize_fee_tracker(ctx: Context) -> Result<()> { let fee_tracker = &mut ctx.accounts.fee_tracker; fee_tracker.bump = *ctx.bumps.get("fee_tracker").unwrap(); - fee_tracker.payer = ctx.accounts.payer.key(); + fee_tracker.fees_recipient = ctx.accounts.payer.key(); fee_tracker.fees_owed = 0; fee_tracker.fees_mint = ctx.accounts.swim_usd_mint.key(); Ok(()) @@ -59,7 +59,7 @@ pub fn handle_initialize_fee_tracker(ctx: Context) -> Resu #[account] pub struct FeeTracker { pub bump: u8, - pub payer: Pubkey, + pub fees_recipient: Pubkey, pub fees_owed: u64, pub fees_mint: Pubkey, } @@ -73,13 +73,13 @@ pub struct ClaimFees<'info> { #[account( seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = fee_vault, + has_one = fee_vault @ PropellerError::InvalidFeeVault, )] pub propeller: Box>, #[account( mut, - seeds = [b"propeller".as_ref(), b"fee".as_ref(), fee_tracker.fees_mint.as_ref(), fee_tracker.payer.as_ref()], + seeds = [b"propeller".as_ref(), b"fee".as_ref(), fee_tracker.fees_mint.as_ref(), fee_tracker.fees_recipient.as_ref()], bump = fee_tracker.bump )] pub fee_tracker: Account<'info, FeeTracker>, @@ -89,16 +89,11 @@ pub struct ClaimFees<'info> { #[account( mut, - token::mint = fee_tracker.fees_mint, - token::authority = fee_tracker.payer, + address = get_associated_token_address(&fee_tracker.fees_recipient, &fee_tracker.fees_mint), )] pub fee_account: Account<'info, TokenAccount>, - #[account( - mut, - token::mint = fee_tracker.fees_mint, - token::authority = propeller, - )] + #[account(mut)] pub fee_vault: Account<'info, TokenAccount>, pub token_program: Program<'info, Token>, diff --git a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs index c4182c5e9..c985d478e 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs @@ -102,6 +102,7 @@ pub struct InitializeParams { pub marginal_price_pool: Pubkey, pub marginal_price_pool_token_index: u8, pub marginal_price_pool_token_mint: Pubkey, + pub max_staleness: i64, // pub evm_routing_contract_address: [u8; 32], } 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 bbbbf4923..efe499840 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 @@ -371,13 +371,14 @@ pub struct PropellerProcessSwimPayload<'info> { ///CHECK: account for getting gas -> USD price #[account( constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount + *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount, + address = process_swim_payload.propeller.aggregator @ PropellerError::InvalidAggregator )] pub aggregator: AccountLoader<'info, AggregatorAccountData>, #[account( mut, - address = get_associated_token_address(&process_swim_payload.propeller.key(), &process_swim_payload.propeller.swim_usd_mint) + address = process_swim_payload.propeller.fee_vault @ PropellerError::InvalidFeeVault )] /// this is "to_fees" /// recipient of fees for executing complete transfer (e.g. relayer) @@ -416,7 +417,8 @@ pub struct PropellerProcessSwimPayload<'info> { marginal_price_pool_lp_mint.key().as_ref(), ], bump = marginal_price_pool.bump, - seeds::program = process_swim_payload.two_pool_program.key() + seeds::program = process_swim_payload.two_pool_program.key(), + address = process_swim_payload.propeller.marginal_price_pool @ PropellerError::InvalidMarginalPricePool )] pub marginal_price_pool: Box>, #[account(address = marginal_price_pool.token_keys[0])] @@ -474,52 +476,44 @@ impl<'info> PropellerProcessSwimPayload<'info> { Ok(()) } - /// Calculates, transfer and tracks fees - /// returns fees_in_token_bridge_mint - fn handle_fees(&mut self) -> Result { - 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()?; + fn transfer_gas_kickstart(&self) -> Result<()> { 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); - let fee_tracker = &mut self.fee_tracker; - fee_tracker.fees_owed = - fee_tracker.fees_owed.checked_add(fees_in_swim_usd_atomic).ok_or(PropellerError::IntegerOverflow)?; - let cpi_accounts = Transfer { - from: self.process_swim_payload.redeemer_escrow.to_account_info(), - to: self.fee_vault.to_account_info(), - authority: self.process_swim_payload.redeemer.to_account_info(), - }; - token::transfer( - CpiContext::new_with_signer( - token_program.to_account_info(), - cpi_accounts, - &[&[&b"redeemer".as_ref(), &[propeller.redeemer_bump]]], + let owner_account = &self.owner.to_account_info(); + let payer = &self.process_swim_payload.payer.to_account_info(); + let owner_starting_lamports = owner_account.lamports(); + let payer_starting_lamports = payer.lamports(); + let system_program = &self.process_swim_payload.system_program; + require_gte!( + payer_starting_lamports, + propeller.gas_kickstart_amount, + PropellerError::PayerInsufficientFundsForGasKickstart + ); + system_program::transfer( + CpiContext::new( + system_program.to_account_info(), + system_program::Transfer { from: payer.clone(), to: owner_account.clone() }, ), - fees_in_swim_usd_atomic, + propeller.gas_kickstart_amount, )?; - Ok(fees_in_swim_usd_atomic) + msg!("owner_starting_lamports: {}, owner_final_lamports: {}, payer_starting_lamports: {}, payer_final_lamports: {}", + owner_starting_lamports, owner_account.lamports(), payer_starting_lamports, payer.lamports()); + Ok(()) + } + + fn log_memo(&self) -> Result<()> { + let memo = self.process_swim_payload.swim_payload_message.memo; + if memo != [0u8; 16] { + let memo_ix = + spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); + invoke(&memo_ix, &[self.memo.to_account_info()])?; + } else { + msg!("memo is empty"); + } + Ok(()) } +} +impl<'info> Fees<'info> for PropellerProcessSwimPayload<'info> { 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 @@ -552,10 +546,8 @@ impl<'info> PropellerProcessSwimPayload<'info> { Ok(fee_in_lamports) } - fn calculate_fees(&self) -> Result { - let fee_in_lamports = self.calculate_fees_in_lamports()?; - - let marginal_prices = two_pool::cpi::marginal_prices(CpiContext::new( + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = 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(), @@ -564,53 +556,72 @@ impl<'info> PropellerProcessSwimPayload<'info> { lp_mint: self.marginal_price_pool_lp_mint.to_account_info(), }, ))?; + Ok(result.get()) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + let propeller = &self.process_swim_payload.propeller; - let fees_in_swim_usd_atomic = convert_fees_to_swim_usd_atomic_2( - fee_in_lamports, - &self.process_swim_payload.propeller, - &self.marginal_price_pool_lp_mint, - marginal_prices.get(), + let max_staleness = propeller.max_staleness; + 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( &self.marginal_price_pool, - &self.aggregator, - i64::MAX, + &self.get_marginal_prices()?, + propeller, + &marginal_price_pool_lp_mint.key(), )?; - Ok(fees_in_swim_usd_atomic) - } - fn transfer_gas_kickstart(&self) -> Result<()> { - let propeller = &self.process_swim_payload.propeller; - let owner_account = &self.owner.to_account_info(); - let payer = &self.process_swim_payload.payer.to_account_info(); - let owner_starting_lamports = owner_account.lamports(); - let payer_starting_lamports = payer.lamports(); - let system_program = &self.process_swim_payload.system_program; - require_gte!( - payer_starting_lamports, - propeller.gas_kickstart_amount, - PropellerError::PayerInsufficientFundsForGasKickstart + 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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 ); - system_program::transfer( - CpiContext::new( - system_program.to_account_info(), - system_program::Transfer { from: payer.clone(), to: owner_account.clone() }, - ), - propeller.gas_kickstart_amount, - )?; - msg!("owner_starting_lamports: {}, owner_final_lamports: {}, payer_starting_lamports: {}, payer_final_lamports: {}", - owner_starting_lamports, owner_account.lamports(), payer_starting_lamports, payer.lamports()); - Ok(()) + Ok(fee_in_swim_usd_atomic) } - fn log_memo(&self) -> Result<()> { - let memo = self.process_swim_payload.swim_payload_message.memo; - if memo != [0u8; 16] { - let memo_ix = - spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); - invoke(&memo_ix, &[self.memo.to_account_info()])?; - } else { - msg!("memo is empty"); - } - Ok(()) + 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.process_swim_payload.token_program.to_account_info(), + Transfer { + from: self.process_swim_payload.redeemer_escrow.to_account_info(), + to: self.fee_vault.to_account_info(), + authority: self.process_swim_payload.redeemer.to_account_info(), + }, + &[&[&b"redeemer".as_ref(), &[self.process_swim_payload.propeller.redeemer_bump]]], + ), + fees_in_swim_usd, + ) } } @@ -652,14 +663,15 @@ pub fn handle_propeller_process_swim_payload( let token_program = &ctx.accounts.process_swim_payload.token_program; msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.process_swim_payload.payer.key() { - let fees_in_token_bridge = &ctx.accounts.handle_fees()?; - // let fees_in_token_bridge = calculate_fees2(&ctx)?; - msg!("fees_in_token_bridge: {:?}", fees_in_token_bridge); + let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; + ctx.accounts.track_and_transfer_fees(fees_in_swim_usd_atomic)?; + msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); if is_gas_kickstart { ctx.accounts.transfer_gas_kickstart()?; } transfer_amount = - transfer_amount.checked_sub(*fees_in_token_bridge).ok_or(error!(PropellerError::InsufficientFunds))?; + transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; } else { //TODO: a user should just call processSwimPayload instead to avoid passing in extra accounts. end result is same. msg!("swim_payload_owner == ctx.accounts.payer.key(). Owner bypass"); @@ -683,8 +695,9 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { #[account( seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = marginal_price_pool, - has_one = aggregator @ PropellerError::InvalidAggregator + has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, + has_one = aggregator @ PropellerError::InvalidAggregator, + has_one = fee_vault @ PropellerError::InvalidFeeVault, )] pub propeller: Box>, #[account(mut)] @@ -838,144 +851,6 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { Ok(()) } - /// Calculates, transfer and tracks fees - /// returns fees_in_swim_usd_mint - fn handle_fees(&mut self) -> Result { - let fees_in_token_bridge = self.calculate_fees()?; - let propeller = &self.propeller; - let token_program = &self.token_program; - msg!("fees_in_token_bridge: {:?}", fees_in_token_bridge); - let fee_tracker = &mut self.fee_tracker; - fee_tracker.fees_owed = - fee_tracker.fees_owed.checked_add(fees_in_token_bridge).ok_or(PropellerError::IntegerOverflow)?; - let cpi_accounts = Transfer { - from: self.redeemer_escrow.to_account_info(), - to: self.fee_vault.to_account_info(), - authority: self.redeemer.to_account_info(), - }; - token::transfer( - CpiContext::new_with_signer( - token_program.to_account_info(), - cpi_accounts, - &[&[&b"redeemer".as_ref(), &[propeller.redeemer_bump]]], - ), - fees_in_token_bridge, - )?; - Ok(fees_in_token_bridge) - } - - fn calculate_fees(&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 - 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 - ); - - let cpi_ctx = CpiContext::new( - 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(), - }, - ); - 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 mut res = 0u64; - let feed = &self.aggregator.load()?; - - 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 lp_mint_key = marginal_price_pool_lp_mint.key(); - - let swim_usd_mint_key = self.propeller.swim_usd_mint; - let marginal_price: Decimal = get_marginal_price_decimal( - &marginal_price_pool, - &marginal_prices, - &propeller, - // propeller.marginal_price_pool_token_index as usize, - &marginal_price_pool_lp_mint.key(), - // &token_bridge_mint_key, - )?; - - msg!("marginal_price: {}", marginal_price); - 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_mint_decimal = marginal_price - .checked_mul(lamports_usd_price) - .and_then(|v| v.checked_mul(fee_in_lamports_decimal)) - .ok_or(PropellerError::IntegerOverflow)?; - - let swim_usd_mint_decimals = - get_swim_usd_mint_decimals(&swim_usd_mint_key, &marginal_price_pool, &marginal_price_pool_lp_mint)?; - - msg!("swim_usd_mint_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_mint_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_mint_decimal, - fee_in_swim_usd_atomic - ); - res = fee_in_swim_usd_atomic; - Ok(res) - } - fn transfer_gas_kickstart(&self) -> Result<()> { let propeller = &self.propeller; let owner_account = &self.owner.to_account_info(); @@ -1000,14 +875,6 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { Ok(()) } - pub fn transfer_tokens(&self, transfer_amount: u64) -> Result { - self.transfer_swim_usd_tokens( - transfer_amount, - &self.redeemer.to_account_info(), - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], - ) - } - fn transfer_swim_usd_tokens( &self, transfer_amount: u64, @@ -1044,8 +911,7 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { } } -/* -impl Fees for PropellerProcessSwimPayloadFallback { +impl<'info> Fees<'info> for PropellerProcessSwimPayloadFallback<'info> { fn calculate_fees_in_lamports(&self) -> Result { let rent = Rent::get()?; @@ -1053,12 +919,6 @@ impl Fees for PropellerProcessSwimPayloadFallback { 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 @@ -1081,21 +941,30 @@ impl Fees for PropellerProcessSwimPayloadFallback { 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 { + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = two_pool::cpi::marginal_prices(CpiContext::new( + self.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(), + }, + ))?; + Ok(result.get()) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { msg!("fee_in_lamports: {:?}", fee_in_lamports); let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + let max_staleness = self.propeller.max_staleness; 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.get_marginal_prices()?, &self.propeller, &marginal_price_pool_lp_mint.key(), )?; @@ -1105,16 +974,14 @@ impl Fees for PropellerProcessSwimPayloadFallback { 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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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)?; + 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 = @@ -1129,8 +996,7 @@ impl Fees for PropellerProcessSwimPayloadFallback { fee_in_swim_usd_decimal, fee_in_swim_usd_atomic ); - res = fee_in_swim_usd_atomic; - Ok(res) + Ok(fee_in_swim_usd_atomic) } fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { @@ -1152,7 +1018,6 @@ impl Fees for PropellerProcessSwimPayloadFallback { ) } } - */ pub fn handle_propeller_process_swim_payload_fallback( ctx: Context, @@ -1174,14 +1039,15 @@ pub fn handle_propeller_process_swim_payload_fallback( let token_program = &ctx.accounts.token_program; msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.payer.key() { - let fees_in_token_bridge = &ctx.accounts.handle_fees()?; - // let fees_in_token_bridge = calculate_fees2(&ctx)?; - msg!("fees_in_token_bridge: {:?}", fees_in_token_bridge); + let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; + ctx.accounts.track_and_transfer_fees(fees_in_swim_usd_atomic)?; + msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); if is_gas_kickstart { ctx.accounts.transfer_gas_kickstart()?; } transfer_amount = - transfer_amount.checked_sub(*fees_in_token_bridge).ok_or(error!(PropellerError::InsufficientFunds))?; + transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; } else { //TODO: a user should just call processSwimPayload instead to avoid passing in extra accounts. end result is same. msg!("swim_payload_owner == ctx.accounts.payer.key(). Owner bypass"); 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 cebb13a2f..f02ec58ac 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 @@ -1,3 +1,4 @@ +use crate::Fees; use { crate::{ constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, @@ -13,6 +14,7 @@ use { solana_program::{instruction::Instruction, program::invoke_signed, system_program, sysvar::SysvarId}, }, anchor_spl::{ + associated_token::get_associated_token_address, token, token::{Mint, Token, TokenAccount, Transfer}, }, @@ -32,6 +34,7 @@ pub struct CompleteNativeWithPayload<'info> { seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref() ], bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, + has_one = fee_vault @ PropellerError::InvalidFeeVault, )] pub propeller: Box>, @@ -102,13 +105,12 @@ pub struct CompleteNativeWithPayload<'info> { /// CHECK: wormhole endpoint account. seeds = [ vaa.emitter_chain, vaa.emitter_address ] pub endpoint: UncheckedAccount<'info>, - /// owned by redeemer. "redeemerEscrow" + /// `to` account in `CompleteNativeWithPayload` #[account( mut, - token::mint = swim_usd_mint.key(), - token::authority = redeemer, + address = get_associated_token_address(&redeemer.key(), &swim_usd_mint.key()) )] - pub to: Box>, + pub redeemer_escrow: Box>, #[account( seeds = [ b"redeemer".as_ref()], @@ -123,21 +125,13 @@ pub struct CompleteNativeWithPayload<'info> { /// and that the `redeemer` account will be the PDA derived from ["redeemer"], seeds::program = propeller::id() pub redeemer: SystemAccount<'info>, - //TODO: should this just always be fee_vault? - // not actually being used unless this is a propellerEnabled ix. - // wormhole complete_native_with_payload doesn't do anything with this - // the only thing it does is check that the mint is correct. - // note: we only care that this is actually the fee_vault if it's called from propellerCompleteNativeWithPayload - // so the checks are done there. - - // TODO: rename to `fee_vault` and add has_one in propeller constraints? #[account( mut, token::mint = propeller.swim_usd_mint, )] /// this is "to_fees" /// recipient of fees for executing complete transfer (e.g. relayer) - pub fee_recipient: Box>, + pub fee_vault: Box>, // #[account(mut)] // /// this is "to_fees" // /// TODO: type as TokenAccount? @@ -195,9 +189,9 @@ impl<'info> CompleteNativeWithPayload<'info> { self.message.to_account_info().clone(), self.claim.to_account_info().clone(), self.endpoint.to_account_info().clone(), - self.to.to_account_info().clone(), + self.redeemer_escrow.to_account_info().clone(), self.redeemer.to_account_info().clone(), - self.fee_recipient.to_account_info().clone(), + self.fee_vault.to_account_info().clone(), self.custody.to_account_info().clone(), self.swim_usd_mint.to_account_info().clone(), self.custody_signer.to_account_info().clone(), @@ -215,9 +209,9 @@ impl<'info> CompleteNativeWithPayload<'info> { AccountMeta::new_readonly(self.message.key(), false), AccountMeta::new(self.claim.key(), false), AccountMeta::new_readonly(self.endpoint.key(), false), - AccountMeta::new(self.to.key(), false), + AccountMeta::new(self.redeemer_escrow.key(), false), AccountMeta::new_readonly(self.redeemer.key(), true), - AccountMeta::new(self.fee_recipient.key(), false), + AccountMeta::new(self.fee_vault.key(), false), AccountMeta::new(self.custody.key(), false), AccountMeta::new_readonly(self.swim_usd_mint.key(), false), AccountMeta::new_readonly(self.custody_signer.key(), false), @@ -381,13 +375,24 @@ impl<'info> PropellerCompleteNativeWithPayload<'info> { ctx.accounts.marginal_price_pool_token_1_account.mint, ], )?; - require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_recipient.key(), propeller.fee_vault); - require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_recipient.owner, propeller.key()); + require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.key(), propeller.fee_vault); + require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.owner, propeller.key()); require_keys_eq!(ctx.accounts.aggregator.key(), propeller.aggregator, PropellerError::InvalidAggregator); Ok(()) } - fn calculate_fees(&self) -> Result { + fn log_memo(&self, memo: [u8; 16]) -> Result<()> { + if memo != [0u8; 16] { + let memo_ix = + spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); + invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; + } + Ok(()) + } +} + +impl<'info> Fees<'info> for PropellerCompleteNativeWithPayload<'info> { + fn calculate_fees_in_lamports(&self) -> Result { let rent = Rent::get()?; let wormhole_message_rent_exempt_fees = rent.minimum_balance(self.complete_native_with_payload.message.to_account_info().data_len()); @@ -424,85 +429,86 @@ impl<'info> PropellerCompleteNativeWithPayload<'info> { complete_with_payload_fee, fee_in_lamports ); + Ok(fee_in_lamports) + } - let marginal_prices = get_marginal_prices(self.into_marginal_prices())?; + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = two_pool::cpi::marginal_prices(CpiContext::new( + self.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(), + }, + ))?; + Ok(result.get()) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + + let propeller = &self.complete_native_with_payload.propeller; + let max_staleness = propeller.max_staleness; + 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( &self.marginal_price_pool, - &marginal_prices, - &propeller, - // propeller.marginal_price_pool_token_index as usize, - &self.marginal_price_pool_lp_mint.key(), - // &token_bridge_mint_key, + &self.get_marginal_prices()?, + propeller, + &marginal_price_pool_lp_mint.key(), )?; msg!("intermediate_token_price_decimal: {:?}", intermediate_token_price_decimal); - //swimUSD is lp token of marginal price pool - let mut res = 0u64; - 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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.aggregator, i64::MAX)?; + + let lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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_mint_key = self.complete_native_with_payload.propeller.swim_usd_mint; + 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 swim_usd_mint_decimals = get_swim_usd_mint_decimals( - &swim_usd_mint_key, - &self.marginal_price_pool, - &self.marginal_price_pool_lp_mint, - )?; - //TODO: good lord forgive me for this terrible naming. i will fix later. let ten_pow_decimals = - Decimal::from_u64(10u64.pow(swim_usd_mint_decimals as u32)).ok_or(PropellerError::IntegerOverflow)?; + 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(fee_in_swim_usd_atomic) } - fn handle_fees(&mut self, fees_in_token_bridge_mint: u64) -> Result<()> { + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { let fee_tracker = &mut self.fee_tracker; - let updated_fees_owed = - fee_tracker.fees_owed.checked_add(fees_in_token_bridge_mint).ok_or(PropellerError::IntegerOverflow)?; - fee_tracker.fees_owed = updated_fees_owed; - - let cpi_accounts = Transfer { - from: self.complete_native_with_payload.to.to_account_info(), - to: self.complete_native_with_payload.fee_recipient.to_account_info(), - authority: self.complete_native_with_payload.redeemer.to_account_info(), - }; + 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.complete_native_with_payload.token_program.to_account_info(), - cpi_accounts, + Transfer { + from: self.complete_native_with_payload.redeemer_escrow.to_account_info(), + to: self.complete_native_with_payload.fee_vault.to_account_info(), + authority: self.complete_native_with_payload.redeemer.to_account_info(), + }, &[&[&b"redeemer".as_ref(), &[self.complete_native_with_payload.propeller.redeemer_bump]]], ), - fees_in_token_bridge_mint, + fees_in_swim_usd, ) } - - fn into_marginal_prices(&self) -> CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>> { - let program = self.two_pool_program.to_account_info(); - let accounts = 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(), - }; - CpiContext::new(program, accounts) - } } pub fn handle_propeller_complete_native_with_payload(ctx: Context) -> Result<()> { @@ -526,9 +532,15 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context swimUSD if the payer isn't the actual logical owner. // This is for if the propeller engine is unavailable and the user is manually calling // this ix. They should use the `CompleteNativeWithPayload` ix instead but adding this just in case.\ @@ -536,12 +548,12 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context Result { // let pubkey = Pubkey::from_str(CORE_BRIDGE_ADDRESS) diff --git a/packages/solana-contracts/scripts/initializePropeller.ts b/packages/solana-contracts/scripts/initializePropeller.ts index 8cc5eff4b..04190d7d8 100644 --- a/packages/solana-contracts/scripts/initializePropeller.ts +++ b/packages/solana-contracts/scripts/initializePropeller.ts @@ -33,7 +33,7 @@ import { TWO_POOL_PID, USDC_TO_TOKEN_NUMBER, USDT_TO_TOKEN_NUMBER, - setComputeUnitLimitIx, + setComputeUnitLimitIx, maxStaleness, } from "../src/__tests__/consts"; import { getPropellerPda, @@ -278,6 +278,7 @@ async function initializePropellerState(): Promise { ...DEFAULT_INIT_PROPELLER_PARAMS, marginalPricePool: swimUsdPoolInfo.address, marginalPricePoolTokenMint: swimUsdPoolInfo.tokenMints[0], + maxStaleness: maxStaleness, }; console.info(` propellerAddr: ${propellerAddr.toString()} diff --git a/packages/solana-contracts/src/__tests__/consts.ts b/packages/solana-contracts/src/__tests__/consts.ts index 4a0bcad4f..b46cdbe0c 100644 --- a/packages/solana-contracts/src/__tests__/consts.ts +++ b/packages/solana-contracts/src/__tests__/consts.ts @@ -9,7 +9,7 @@ import { LAMPORTS_PER_SOL } from "@solana/web3.js"; export const commitment = "confirmed" as web3.Commitment; export const rpcCommitmentConfig = { - commitment, + commitment: "confirmed", preflightCommitment: commitment, skipPreflight: true, }; @@ -74,6 +74,7 @@ export const secpVerifyFee: BN = new BN(0.00004 * LAMPORTS_PER_SOL); export const postVaaFee: BN = new BN(0.00005 * LAMPORTS_PER_SOL); export const completeWithPayloadFee: BN = new BN(0.0000055 * LAMPORTS_PER_SOL); export const processSwimPayloadFee: BN = new BN(0.00001 * LAMPORTS_PER_SOL); // const confirmedCommitment = { commitment: "confirmed" as web3.Finality }; +export const maxStaleness = new BN("9223372036854775807"); export const ampFactor = { value: new BN(300), decimals: 0 }; export const lpFee = { value: new BN(300), decimals: 6 }; //lp fee = .000300 = 0.0300% 3bps export const governanceFee = { value: new BN(100), decimals: 6 }; //gov fee = .000100 = (0.0100%) 1bps diff --git a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts index c191c8702..af1fc0178 100644 --- a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts @@ -60,6 +60,7 @@ import { initAtaFee, lpFee, marginalPricePoolTokenIndex, + maxStaleness, metapoolMint1OutputTokenIndex, metapoolMint1PoolTokenIndex, postVaaFee, @@ -84,6 +85,7 @@ import type { WormholeAddresses } from "./propellerUtils"; import { encodeSwimPayload, generatePropellerEngineTxns, + getFeeTrackerPda, getOwnerTokenAccountsForPool, getPropellerPda, getPropellerRedeemerPda, @@ -766,16 +768,11 @@ describe("propeller", () => { propellerEngineKeypair, ]); - const [expectedFeeTracker, bump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("fee"), - swimUsdMint.toBuffer(), - propellerEngineKeypair.publicKey.toBuffer(), - ], - propellerProgram.programId, - ); + const [expectedFeeTracker, bump] = await getFeeTrackerPda( + swimUsdMint, + propellerEngineKeypair.publicKey, + propellerProgram.programId, + ); if (!initializeFeeTrackersPubkeys.feeTracker) { throw new Error("feeTracker is undefined"); @@ -789,7 +786,7 @@ describe("propeller", () => { initializeFeeTrackersPubkeys.feeTracker, ); expect(feeTrackerAccount.bump).toEqual(bump); - expect(feeTrackerAccount.payer.toBase58()).toEqual( + expect(feeTrackerAccount.feesRecipient.toBase58()).toEqual( propellerEngineKeypair.publicKey.toBase58(), ); expect(feeTrackerAccount.feesMint.toBase58()).toEqual( @@ -938,9 +935,9 @@ describe("propeller", () => { claim: wormholeClaim, swimPayloadMessage: expectedSwimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, // feeRecipient: propellerRedeemerEscrowAccount, // tokenBridgeMint, custody: wormholeAddresses.custody, @@ -1627,9 +1624,9 @@ describe("propeller", () => { claim: wormholeClaim, swimPayloadMessage: expectedSwimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, // feeRecipient: propellerRedeemerEscrowAccount, // tokenBridgeMint, custody: custody, @@ -2435,9 +2432,9 @@ describe("propeller", () => { claim: wormholeClaim, swimPayloadMessage: expectedSwimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, // feeRecipient: propellerRedeemerEscrowAccount, // tokenBridgeMint, custody: custody, @@ -3029,7 +3026,7 @@ describe("propeller", () => { // message: wormholeMessage, // claim: wormholeClaim, // endpoint: ethEndpointAccount, - // to: propellerRedeemerEscrowAccount, + // redeemerEscrow: propellerRedeemerEscrowAccount, // redeemer: propellerRedeemer, // feeRecipient: userSwimUsdAtaAddr, // // feeRecipient: propellerRedeemerEscrowAccount, @@ -3445,7 +3442,7 @@ describe("propeller", () => { // message: wormholeMessage, // claim: wormholeClaim, // endpoint: ethEndpointAccount, - // to: propellerRedeemerEscrowAccount, + // redeemerEscrow: propellerRedeemerEscrowAccount, // redeemer: propellerRedeemer, // feeRecipient: userSwimUsdAtaAddr, // // feeRecipient: propellerRedeemerEscrowAccount, @@ -3895,9 +3892,9 @@ describe("propeller", () => { claim: wormholeClaim, swimPayloadMessage: expectedSwimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, // feeRecipient: propellerRedeemerEscrowAccount, // tokenBridgeMint, custody: custody, @@ -5787,9 +5784,9 @@ describe("propeller", () => { claim: wormholeClaim, swimPayloadMessage: expectedSwimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, // feeRecipient: propellerRedeemerEscrowAccount, // tokenBridgeMint, custody: custody, @@ -6897,6 +6894,7 @@ const initializePropeller = async () => { marginalPricePool, marginalPricePoolTokenIndex, marginalPricePoolTokenMint, + maxStaleness, // evmRoutingContractAddress: ethRoutingContract, // evmRoutingContractAddress: ethRoutingContractEthUint8Arr }; diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index 5e31d4b1f..58eebee77 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -40,6 +40,7 @@ import { USDC_TO_TOKEN_NUMBER, USDT_TO_TOKEN_NUMBER, ampFactor, + bscTokenBridge, commitment, completeWithPayloadFee, ethRoutingContract, @@ -52,6 +53,7 @@ import { initAtaFee, lpFee, marginalPricePoolTokenIndex, + maxStaleness, metapoolMint1OutputTokenIndex, metapoolMint1PoolTokenIndex, postVaaFee, @@ -81,7 +83,8 @@ import { getPropellerSenderPda, getSwimClaimPda, getSwimPayloadMessagePda, - parseTokenTransferWithSwimPayloadPostedMessage, + getWormholeAddressesForMint, + parseTokenTransferWithSwimPayloadPostedMessage, WormholeAddresses, } from "./propellerUtils"; import { deriveEndpointPda, @@ -193,7 +196,7 @@ let flagshipPool: web3.PublicKey; // let flagshipPoolData: SwimPoolState; // let poolAuth: web3.PublicKey; const swimUsdMint: web3.PublicKey = swimUsdKeypair.publicKey; - +let wormholeAddresses: WormholeAddresses; const metapoolMint0Keypair = swimUsdKeypair; const metapoolMint1Keypair = web3.Keypair.generate(); const metapoolMint1Authority = payer; @@ -472,76 +475,25 @@ describe("propeller", () => { } `); - // [custodyOrWrappedMeta] = await (async () => { - // const mintInfo = await getMint(program.provider.connection, swimUsdMint); - // if (mintInfo.mintAuthority! === tokenMintSigner) { - // //First derive the Wrapped Mint Key - // //[Ricky] - this call is propellerLpAta wormhole-sdk - // const nativeInfo = await getOriginalAssetSol( - // program.provider.connection, - // tokenBridge.toString(), - // swimUsdMint.toString() - // ); - // const [wrappedMintKey] = await web3.PublicKey.findProgramAddress( - // [ - // Buffer.from("wrapped"), - // // serializeuint16 as uint8array - // // ` data.token_chain.to_be_bytes().to_vec(),` - // serializeUint16(nativeInfo.chainId as number), - // swimUsdMint.toBytes() - // ], - // tokenBridge - // ); - // //Then derive the Wrapped Meta Key - // return await web3.PublicKey.findProgramAddress([Buffer.from("meta"), wrappedMintKey.toBytes()], tokenBridge); - // } else { - // // transfer native sol asset - // return await web3.PublicKey.findProgramAddress([swimUsdMint.toBytes()], tokenBridge); - // } - // })(); - - // note - there's also wasm generated helper methods to derive these addresses as well. - // assuming always sending solana native token so this will be custody. - [custody] = await (async () => { - return await web3.PublicKey.findProgramAddress( - [swimUsdMint.toBytes()], - tokenBridge, - ); - })(); - [wormholeConfig] = await web3.PublicKey.findProgramAddress( - [Buffer.from("Bridge")], - wormhole, - ); - [wormholeFeeCollector] = await web3.PublicKey.findProgramAddress( - [Buffer.from("fee_collector")], - wormhole, - ); - // wh functions return in a hex string format - // wormholeEmitter = new web3.PublicKey( - // tryHexToNativeString(await getEmitterAddressSolana(tokenBridge.toBase58()), CHAIN_ID_SOLANA) - // ); - [wormholeEmitter] = await web3.PublicKey.findProgramAddress( - [Buffer.from("emitter")], - tokenBridge, - ); - [wormholeSequence] = await web3.PublicKey.findProgramAddress( - [Buffer.from("Sequence"), wormholeEmitter.toBytes()], - wormhole, - ); - - [authoritySigner] = await web3.PublicKey.findProgramAddress( - [Buffer.from("authority_signer")], - tokenBridge, - ); - [tokenBridgeConfig] = await web3.PublicKey.findProgramAddress( - [Buffer.from("config")], - tokenBridge, - ); - [custodySigner] = await web3.PublicKey.findProgramAddress( - [Buffer.from("custody_signer")], - tokenBridge, + wormholeAddresses = await getWormholeAddressesForMint( + WORMHOLE_CORE_BRIDGE, + WORMHOLE_TOKEN_BRIDGE, + swimUsdMint, + ethTokenBridge, + bscTokenBridge, ); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + ({ + authoritySigner, + custody, + custodySigner, + tokenBridgeConfig, + wormholeConfig, + wormholeEmitter, + wormholeFeeCollector, + wormholeSequence, + } = wormholeAddresses); console.info(` custodyOrWrappedMeta: ${custody.toString()} @@ -589,6 +541,7 @@ describe("propeller", () => { marginalPricePool, marginalPricePoolTokenIndex, marginalPricePoolTokenMint, + maxStaleness, // evmRoutingContractAddress: ethRoutingContract, // evmRoutingContractAddress: ethRoutingContractEthUint8Arr }; @@ -2206,6 +2159,7 @@ describe("propeller", () => { tokenTransferWithPayloadSignedVaa, ); + const completeNativeWithPayloadIxs = propellerProgram.methods .completeNativeWithPayload() .accounts({ @@ -2216,14 +2170,9 @@ describe("propeller", () => { message: wormholeMessage, claim: wormholeClaim, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - // this is only used in propellerCompleteNativeWithPayload - // but must still be passed. - // tokenBridge.completeNativeWithPayload just checks mint is - // correct. - feeRecipient: userSwimUsdAtaAddr, - // feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, @@ -2595,14 +2544,9 @@ describe("propeller", () => { message: wormholeMessage, claim: wormholeClaim, endpoint: endpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - // this is only used in propellerCompleteNativeWithPayload - // but must still be passed. - // tokenBridge.completeNativeWithPayload just checks mint is - // correct. - feeRecipient: userSwimUsdAtaAddr, - // feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, @@ -2979,14 +2923,9 @@ describe("propeller", () => { message: wormholeMessage, claim: wormholeClaim, endpoint: endpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - // this is only used in propellerCompleteNativeWithPayload - // but must still be passed. - // tokenBridge.completeNativeWithPayload just checks mint is - // correct. - feeRecipient: userSwimUsdAtaAddr, - // feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, @@ -3372,14 +3311,9 @@ describe("propeller", () => { message: wormholeMessage, claim: wormholeClaim, endpoint: endpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - // this is only used in propellerCompleteNativeWithPayload - // but must still be passed. - // tokenBridge.completeNativeWithPayload just checks mint is - // correct. - feeRecipient: userSwimUsdAtaAddr, - // feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, @@ -3784,14 +3718,9 @@ describe("propeller", () => { message: wormholeMessage, claim: wormholeClaim, endpoint: endpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - // this is only used in propellerCompleteNativeWithPayload - // but must still be passed. - // tokenBridge.completeNativeWithPayload just checks mint is - // correct. - feeRecipient: userSwimUsdAtaAddr, - // feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, diff --git a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts index 75c577b1f..06464d03c 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts @@ -3,19 +3,22 @@ import { CHAIN_ID_BSC, CHAIN_ID_ETH, getClaimAddressSolana, + tryHexToNativeString, tryUint8ArrayToNative, } from "@certusone/wormhole-sdk"; import type { Program, SplToken } from "@project-serum/anchor"; import { BN, web3 } from "@project-serum/anchor"; -import { MEMO_PROGRAM_ID } from "@solana/spl-memo"; +import { MEMO_PROGRAM_ID, createMemoInstruction } from "@solana/spl-memo"; import { ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, getAssociatedTokenAddress, } from "@solana/spl-token"; import { BigNumber } from "ethers"; import type { Propeller } from "../../artifacts/propeller"; import type { TwoPool } from "../../artifacts/two_pool"; +import { setComputeUnitLimitIx } from "../consts"; import type { ParsedTokenTransferPostedMessage, @@ -61,6 +64,22 @@ export async function getPropellerSenderPda( )[0]; } +export const getFeeTrackerPda = async ( + swimUsdMint: web3.PublicKey, + feesRecipient: web3.PublicKey, + programId: web3.PublicKey, +): Promise => { + return await web3.PublicKey.findProgramAddress( + [ + Buffer.from("propeller"), + Buffer.from("fee"), + swimUsdMint.toBuffer(), + feesRecipient.toBuffer(), + ], + programId, + ); +}; + export async function getSwimClaimPda( wormholeClaim: web3.PublicKey, propellerProgramId: web3.PublicKey, @@ -656,9 +675,9 @@ export const generatePropellerEngineTxns = async ( claim: wormholeClaim, swimPayloadMessage: swimPayloadMessage, endpoint: ethEndpointAccount, - to: propellerRedeemerEscrowAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, redeemer: propellerRedeemer, - feeRecipient: propellerFeeVault, + feeVault: propellerFeeVault, custody: custody, swimUsdMint: swimUsdMint, custodySigner, @@ -953,6 +972,215 @@ export const generatePropellerEngineTxns = async ( return txns; }; +export const getCompleteNativeWithPayloadAccounts = async ( + tokenTransferWithPayloadSignedVaa: Buffer, + wormholeAddresses: WormholeAddresses, + propellerProgram: Program, +) => { + const { + custody, + custodySigner, + ethEndpointAccount, + tokenBridge, + tokenBridgeConfig, + wormhole, + } = wormholeAddresses; + const [wormholeMessage] = await deriveMessagePda( + tokenTransferWithPayloadSignedVaa, + wormhole, + ); + const wormholeClaim = await getClaimAddressSolana( + tokenBridge.toBase58(), + tokenTransferWithPayloadSignedVaa, + ); + const [swimPayloadMessage] = await getSwimPayloadMessagePda( + wormholeClaim, + propellerProgram.programId, + ); + const { tokenTransferVaa } = parseTokenTransferWithSwimPayloadSignedVaa( + tokenTransferWithPayloadSignedVaa, + ); + + const swimUsdMint = new web3.PublicKey( + tryUint8ArrayToNative( + tokenTransferVaa.tokenTransfer.tokenAddress, + tokenTransferVaa.tokenTransfer.tokenChain, + ), + ); + + const propeller = await getPropellerPda( + swimUsdMint, + propellerProgram.programId, + ); + + const propellerData = await propellerProgram.account.propeller.fetch( + propeller, + ); + const propellerFeeVault = propellerData.feeVault; + + const propellerRedeemer = await getPropellerRedeemerPda( + propellerProgram.programId, + ); + + const propellerRedeemerEscrowAccount = await getAssociatedTokenAddress( + swimUsdMint, + propellerRedeemer, + true, + ); + + return propellerProgram.methods.completeNativeWithPayload().accounts({ + propeller, + payer: propellerProgram.provider.publicKey, + tokenBridgeConfig, + message: wormholeMessage, + claim: wormholeClaim, + swimPayloadMessage: swimPayloadMessage, + endpoint: ethEndpointAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, + redeemer: propellerRedeemer, + feeVault: propellerFeeVault, + custody: custody, + swimUsdMint: swimUsdMint, + custodySigner, + rent: web3.SYSVAR_RENT_PUBKEY, + systemProgram: web3.SystemProgram.programId, + wormhole: wormholeAddresses.wormhole, + tokenProgram: TOKEN_PROGRAM_ID, + tokenBridge: wormholeAddresses.tokenBridge, + }); +}; +export const getCompleteNativeWithPayloadTxn = async ( + tokenTransferWithPayloadSignedVaa: Buffer, + wormholeAddresses: WormholeAddresses, + propellerEnabled: boolean, + memoStr: string | null, + propellerProgram: Program, + twoPoolProgram: Program, +): Promise => { + // const { + // custody, + // custodySigner, + // ethEndpointAccount, + // tokenBridge, + // tokenBridgeConfig, + // wormhole, + // } = wormholeAddresses; + // const [wormholeMessage] = await deriveMessagePda( + // tokenTransferWithPayloadSignedVaa, + // wormhole, + // ); + // const wormholeClaim = await getClaimAddressSolana( + // tokenBridge.toBase58(), + // tokenTransferWithPayloadSignedVaa, + // ); + // const [swimPayloadMessage] = await getSwimPayloadMessagePda( + // wormholeClaim, + // propellerProgram.programId, + // ); + const { tokenTransferVaa } = parseTokenTransferWithSwimPayloadSignedVaa( + tokenTransferWithPayloadSignedVaa, + ); + + const swimUsdMint = new web3.PublicKey( + tryUint8ArrayToNative( + tokenTransferVaa.tokenTransfer.tokenAddress, + tokenTransferVaa.tokenTransfer.tokenChain, + ), + ); + + const propeller = await getPropellerPda( + swimUsdMint, + propellerProgram.programId, + ); + + const propellerData = await propellerProgram.account.propeller.fetch( + propeller, + ); + // const propellerFeeVault = propellerData.feeVault; + // + // const propellerRedeemer = await getPropellerRedeemerPda( + // propellerProgram.programId, + // ); + // + // const propellerRedeemerEscrowAccount = await getAssociatedTokenAddress( + // swimUsdMint, + // propellerRedeemer, + // true, + // ); + + // const completeNativeWithPayload = propellerProgram.methods + // .completeNativeWithPayload() + // .accounts({ + // propeller, + // payer: propellerProgram.provider.publicKey, + // tokenBridgeConfig, + // message: wormholeMessage, + // claim: wormholeClaim, + // swimPayloadMessage: swimPayloadMessage, + // endpoint: ethEndpointAccount, + // redeemerEscrow: propellerRedeemerEscrowAccount, + // redeemer: propellerRedeemer, + // feeVault: propellerFeeVault, + // custody: custody, + // swimUsdMint: swimUsdMint, + // custodySigner, + // rent: web3.SYSVAR_RENT_PUBKEY, + // systemProgram: web3.SystemProgram.programId, + // wormhole: wormholeAddresses.wormhole, + // tokenProgram: TOKEN_PROGRAM_ID, + // tokenBridge: wormholeAddresses.tokenBridge, + // }); + + const completeNativeWithPayload = await getCompleteNativeWithPayloadAccounts( + tokenTransferWithPayloadSignedVaa, + wormholeAddresses, + propellerProgram, + ); + + if (!propellerEnabled) { + return completeNativeWithPayload + .preInstructions([setComputeUnitLimitIx]) + .postInstructions( + memoStr !== null ? [createMemoInstruction(memoStr)] : [], + ) + .transaction(); + } else { + const completeNativeWithPayloadPubkeys = + await completeNativeWithPayload.pubkeys(); + const [feeTracker] = await getFeeTrackerPda( + swimUsdMint, + propellerProgram.provider.publicKey, + propellerProgram.programId, + ); + const aggregator = propellerData.aggregator; + const marginalPricePool = propellerData.marginalPricePool; + const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( + marginalPricePool, + ); + const marginalPricePoolToken0Account = marginalPricePoolData.tokenKeys[0]; + const marginalPricePoolToken1Account = marginalPricePoolData.tokenKeys[1]; + const marginalPricePoolLpMint = marginalPricePoolData.lpMintKey; + + return propellerProgram.methods + .propellerCompleteNativeWithPayload() + .accounts({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + completeNativeWithPayload: completeNativeWithPayloadPubkeys, + feeTracker: feeTracker, + aggregator, + marginalPricePool: marginalPricePool, + marginalPricePoolToken0Account: marginalPricePoolToken0Account, + marginalPricePoolToken1Account: marginalPricePoolToken1Account, + marginalPricePoolLpMint: marginalPricePoolLpMint, + twoPoolProgram: twoPoolProgram.programId, + memo: MEMO_PROGRAM_ID, + }) + .preInstructions([setComputeUnitLimitIx]) + .transaction(); + } +}; + const getMarginalPricePoolInfo = async ( propeller: web3.PublicKey, propellerProgram: Program, diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index 01a8b13e5..e2c3ebdc4 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -580,7 +580,7 @@ "kind": "account", "type": "publicKey", "account": "FeeTracker", - "path": "fee_tracker.payer" + "path": "fee_tracker.fees_recipient" } ] } @@ -1832,11 +1832,11 @@ "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -1862,7 +1862,7 @@ } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -2294,11 +2294,11 @@ "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -2324,7 +2324,7 @@ } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -3873,7 +3873,7 @@ "type": "u8" }, { - "name": "payer", + "name": "feesRecipient", "type": "publicKey" }, { @@ -4030,6 +4030,10 @@ { "name": "aggregator", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -4174,6 +4178,10 @@ { "name": "marginalPricePoolTokenMint", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -4736,78 +4744,88 @@ }, { "code": 6035, + "name": "InvalidMarginalPricePool", + "msg": "Invalid Marginal Price Pool" + }, + { + "code": 6036, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6036, + "code": 6037, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6038, + "code": 6039, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6039, + "code": 6040, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6040, + "code": 6041, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6041, + "code": 6042, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6042, + "code": 6043, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6043, + "code": 6044, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6044, + "code": 6045, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6045, + "code": 6046, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6046, + "code": 6047, "name": "TokenIdMapExists", "msg": "TokenIdMap exists. Please use the correct instruction" }, { - "code": 6047, + "code": 6048, "name": "InvalidTokenIdMapAccountAddress", "msg": "Invalid address for TokenIdMap account" }, { - "code": 6048, + "code": 6049, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6049, + "code": 6050, "name": "InvalidAggregator", "msg": "Invalid Aggregator" + }, + { + "code": 6051, + "name": "InvalidFeeVault", + "msg": "Invalid Fee Vault" } ] } \ No newline at end of file diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 068abe656..86a32f67a 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -580,7 +580,7 @@ export type Propeller = { "kind": "account", "type": "publicKey", "account": "FeeTracker", - "path": "fee_tracker.payer" + "path": "fee_tracker.fees_recipient" } ] } @@ -1832,11 +1832,11 @@ export type Propeller = { "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -1862,7 +1862,7 @@ export type Propeller = { } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -2294,11 +2294,11 @@ export type Propeller = { "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -2324,7 +2324,7 @@ export type Propeller = { } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -3873,7 +3873,7 @@ export type Propeller = { "type": "u8" }, { - "name": "payer", + "name": "feesRecipient", "type": "publicKey" }, { @@ -4030,6 +4030,10 @@ export type Propeller = { { "name": "aggregator", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -4174,6 +4178,10 @@ export type Propeller = { { "name": "marginalPricePoolTokenMint", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -4736,78 +4744,88 @@ export type Propeller = { }, { "code": 6035, + "name": "InvalidMarginalPricePool", + "msg": "Invalid Marginal Price Pool" + }, + { + "code": 6036, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6036, + "code": 6037, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6038, + "code": 6039, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6039, + "code": 6040, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6040, + "code": 6041, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6041, + "code": 6042, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6042, + "code": 6043, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6043, + "code": 6044, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6044, + "code": 6045, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6045, + "code": 6046, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6046, + "code": 6047, "name": "TokenIdMapExists", "msg": "TokenIdMap exists. Please use the correct instruction" }, { - "code": 6047, + "code": 6048, "name": "InvalidTokenIdMapAccountAddress", "msg": "Invalid address for TokenIdMap account" }, { - "code": 6048, + "code": 6049, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6049, + "code": 6050, "name": "InvalidAggregator", "msg": "Invalid Aggregator" + }, + { + "code": 6051, + "name": "InvalidFeeVault", + "msg": "Invalid Fee Vault" } ] }; @@ -5394,7 +5412,7 @@ export const IDL: Propeller = { "kind": "account", "type": "publicKey", "account": "FeeTracker", - "path": "fee_tracker.payer" + "path": "fee_tracker.fees_recipient" } ] } @@ -6646,11 +6664,11 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -6676,7 +6694,7 @@ export const IDL: Propeller = { } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -7108,11 +7126,11 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "to", + "name": "redeemerEscrow", "isMut": true, "isSigner": false, "docs": [ - "owned by redeemer. \"redeemerEscrow\"" + "`to` account in `CompleteNativeWithPayload`" ] }, { @@ -7138,7 +7156,7 @@ export const IDL: Propeller = { } }, { - "name": "feeRecipient", + "name": "feeVault", "isMut": true, "isSigner": false, "docs": [ @@ -8687,7 +8705,7 @@ export const IDL: Propeller = { "type": "u8" }, { - "name": "payer", + "name": "feesRecipient", "type": "publicKey" }, { @@ -8844,6 +8862,10 @@ export const IDL: Propeller = { { "name": "aggregator", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -8988,6 +9010,10 @@ export const IDL: Propeller = { { "name": "marginalPricePoolTokenMint", "type": "publicKey" + }, + { + "name": "maxStaleness", + "type": "i64" } ] } @@ -9550,78 +9576,88 @@ export const IDL: Propeller = { }, { "code": 6035, + "name": "InvalidMarginalPricePool", + "msg": "Invalid Marginal Price Pool" + }, + { + "code": 6036, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6036, + "code": 6037, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6038, + "code": 6039, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6039, + "code": 6040, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6040, + "code": 6041, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6041, + "code": 6042, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6042, + "code": 6043, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6043, + "code": 6044, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6044, + "code": 6045, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6045, + "code": 6046, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6046, + "code": 6047, "name": "TokenIdMapExists", "msg": "TokenIdMap exists. Please use the correct instruction" }, { - "code": 6047, + "code": 6048, "name": "InvalidTokenIdMapAccountAddress", "msg": "Invalid address for TokenIdMap account" }, { - "code": 6048, + "code": 6049, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6049, + "code": 6050, "name": "InvalidAggregator", "msg": "Invalid Aggregator" + }, + { + "code": 6051, + "name": "InvalidFeeVault", + "msg": "Invalid Fee Vault" } ] }; From 51dd9edb326feae937280a29a6bce7e87bbecd7b Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 19 Oct 2022 08:07:46 -0400 Subject: [PATCH 09/17] feat: refactoring, add gov ixs and some utility test methods --- packages/solana-contracts/Anchor.toml | 1 + .../programs/propeller/src/constants.rs | 47 +- .../programs/propeller/src/error.rs | 50 +- .../programs/propeller/src/fees.rs | 2 +- .../create_owner_token_accounts.rs | 531 ++--- .../src/instructions/governance/gov.rs | 23 + .../src/instructions/governance/mod.rs | 4 + .../src/instructions/governance/pause.rs | 48 + .../propeller/src/instructions/initialize.rs | 18 +- .../propeller/src/instructions/mod.rs | 7 +- .../src/instructions/process_swim_payload.rs | 148 +- .../src/instructions/target_chain_map.rs | 47 +- .../src/instructions/token_id_map.rs | 139 -- .../src/instructions/token_number_map.rs | 276 +++ .../src/instructions/two_pool_cpi/add.rs | 3 +- .../two_pool_cpi/swap_exact_input.rs | 1 + .../propeller/src/instructions/utils.rs | 118 +- .../wormhole/complete_native_with_payload.rs | 128 +- .../wormhole/transfer_native_with_payload.rs | 100 +- .../programs/propeller/src/lib.rs | 92 +- .../programs/propeller/src/state/propeller.rs | 186 +- .../programs/propeller/src/token_bridge.rs | 21 +- .../programs/propeller/src/wormhole.rs | 249 ++- .../programs/two-pool/src/instructions/add.rs | 9 +- .../governance/common_governance.rs | 4 +- .../src/instructions/governance/set_paused.rs | 9 +- .../two-pool/src/instructions/initialize.rs | 23 - .../programs/two-pool/src/state.rs | 76 +- .../scripts/initializePropeller.ts | 122 +- .../solana-contracts/scripts/parseAccount.ts | 44 + packages/solana-contracts/scripts/scratch.ts | 8 +- .../solana-contracts/src/__tests__/consts.ts | 14 +- .../src/__tests__/propeller/engine.test.ts | 467 ++-- .../src/__tests__/propeller/propeller.test.ts | 1160 ++++++---- .../src/__tests__/propeller/propellerUtils.ts | 588 +++-- .../__tests__/propeller/tokenBridgeUtils.ts | 18 +- .../src/__tests__/twoPool/poolTestUtils.ts | 102 +- .../src/artifacts/propeller.json | 784 +++++-- .../src/artifacts/propeller.ts | 1968 ++++++++++++----- 39 files changed, 5081 insertions(+), 2554 deletions(-) create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs create mode 100644 packages/solana-contracts/scripts/parseAccount.ts diff --git a/packages/solana-contracts/Anchor.toml b/packages/solana-contracts/Anchor.toml index 72cd8fa6a..c61d216e8 100644 --- a/packages/solana-contracts/Anchor.toml +++ b/packages/solana-contracts/Anchor.toml @@ -32,6 +32,7 @@ initialize_pool = "yarn run ts-node scripts/initializePool.ts" initialize_propeller = "yarn run ts-node scripts/initializePropeller.ts" scratch = "yarn run ts-node scripts/scratch.ts" add_to_pool = "yarn run ts-node scripts/addToPool.ts" +parse_account = "yarn run ts-node scripts/parseAccount.ts" [test] startup_wait = 100000 diff --git a/packages/solana-contracts/programs/propeller/src/constants.rs b/packages/solana-contracts/programs/propeller/src/constants.rs index 2b1c88f90..802141ad7 100644 --- a/packages/solana-contracts/programs/propeller/src/constants.rs +++ b/packages/solana-contracts/programs/propeller/src/constants.rs @@ -21,6 +21,15 @@ pub const PROPELLER_MINIMUM_OUTPUT_AMOUNT: u64 = 0u64; // pub const LAMPORTS_PER_SOL_DECIMAL: Decimal = Decimal::from_u64(1_000_000_000u64).unwrap(); pub const LAMPORTS_PER_SOL_DECIMAL: Decimal = Decimal::from_parts(1_000_000_000u32, 0, 0, false, 0u32); +#[cfg(all(feature = "localnet", not(feature = "devnet"), not(feature = "mainnet")))] +pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE"; + +#[cfg(all(feature = "devnet", not(feature = "localnet"), not(feature = "mainnet")))] +pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe"; + +#[cfg(all(feature = "mainnet", not(feature = "localnet"), not(feature = "devnet")))] +pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb"; + #[cfg(test)] mod test { use super::*; @@ -33,41 +42,3 @@ mod test { // println!("token_bridge_id2: {}", ID); } } -// // vaa payload types -// pub const PAYLOAD_SALE_INIT_SOLANA: u8 = 5; // 1 for everyone else -// pub const PAYLOAD_ATTEST_CONTRIBUTIONS: u8 = 2; -// pub const PAYLOAD_SALE_SEALED: u8 = 3; -// pub const PAYLOAD_SALE_ABORTED: u8 = 4; -// -// // universal -// pub const PAYLOAD_HEADER_LEN: usize = 33; // payload + sale id -// pub const INDEX_SALE_ID: usize = 1; -// -// // for sale init -// pub const INDEX_SALE_INIT_TOKEN_ADDRESS: usize = 33; -// pub const INDEX_SALE_INIT_TOKEN_CHAIN: usize = 65; -// pub const INDEX_SALE_INIT_TOKEN_DECIMALS: usize = 67; -// pub const INDEX_SALE_INIT_SALE_START: usize = 68; -// pub const INDEX_SALE_INIT_SALE_END: usize = 100; -// pub const INDEX_SALE_INIT_ACCEPTED_TOKENS_START: usize = 132; -// -// pub const ACCEPTED_TOKEN_NUM_BYTES: usize = 33; -// pub const ACCEPTED_TOKENS_MAX: usize = 8; -// pub const INDEX_ACCEPTED_TOKEN_INDEX: usize = 0; -// pub const INDEX_ACCEPTED_TOKEN_ADDRESS: usize = 1; -// pub const INDEX_ACCEPTED_TOKEN_END: usize = 33; -// -// // for attest contributions -// pub const ATTEST_CONTRIBUTIONS_ELEMENT_LEN: usize = 33; // token index + amount -// -// // for sale sealed -// pub const INDEX_SALE_SEALED_ALLOCATIONS_START: usize = 33; -// -// pub const ALLOCATION_NUM_BYTES: usize = 65; -// pub const INDEX_ALLOCATIONS_AMOUNT: usize = 1; -// pub const INDEX_ALLOCATIONS_EXCESS: usize = 33; -// pub const INDEX_ALLOCATIONS_END: usize = 65; - -// misc -// pub const PAD_U8: usize = 31; -// pub const PAD_U64: usize = 24; diff --git a/packages/solana-contracts/programs/propeller/src/error.rs b/packages/solana-contracts/programs/propeller/src/error.rs index 18b4963b6..91f9135f1 100644 --- a/packages/solana-contracts/programs/propeller/src/error.rs +++ b/packages/solana-contracts/programs/propeller/src/error.rs @@ -72,7 +72,7 @@ pub enum PropellerError { #[msg("Not a valid Switchboard account")] InvalidSwitchboardAccount, - #[msg("Switchboard feed has not been updated in 5 minutes")] + #[msg("Switchboard feed value is stale ")] StaleFeed, #[msg("Switchboard feed exceeded provided confidence interval")] @@ -81,29 +81,35 @@ pub enum PropellerError { #[msg("Insufficient Amount being transferred")] InsufficientAmount, + #[msg("Invalid Wormhole Claim Account")] + InvalidWormholeClaimAccount, + #[msg("Invalid claim data")] InvalidClaimData, #[msg("Claim Account not claimed")] ClaimNotClaimed, - #[msg("Invalid Propeller Admin")] - InvalidPropellerAdmin, + #[msg("Invalid Propeller GovernanceKey")] + InvalidPropellerGovernanceKey, + + #[msg("Invalid Propeller Pause Key")] + InvalidPropellerPauseKey, - #[msg("Invalid Pool for Token Id Map")] - InvalidTokenIdMapPool, + #[msg("Invalid Pool for Token Number Map")] + InvalidTokenNumberMapPool, #[msg("Invalid Output Token Index")] InvalidOutputTokenIndex, - #[msg("Invalid Pool Token Index for Token Id Map")] - InvalidTokenIdMapPoolTokenIndex, + #[msg("Invalid Pool Token Index for Token Number Map")] + InvalidTokenNumberMapPoolTokenIndex, - #[msg("Invalid Pool Token Mint for Token Id Map")] - InvalidTokenIdMapPoolTokenMint, + #[msg("Invalid Pool Token Mint for Token Number Map")] + InvalidTokenNumberMapPoolTokenMint, - #[msg("Invalid Pool Ix for Token Id Map")] - InvalidTokenIdMapPoolIx, + #[msg("Invalid To Token Step for Token Number Map")] + InvalidTokenNumberMapToTokenStep, #[msg("Invalid Gas Kickstart parameter in Swim Payload")] InvalidSwimPayloadGasKickstart, @@ -144,11 +150,8 @@ pub enum PropellerError { #[msg("Owner of token account != swimPayload.owner")] IncorrectOwnerForCreateTokenAccount, - #[msg("TokenIdMap exists. Please use the correct instruction")] - TokenIdMapExists, - - #[msg("Invalid address for TokenIdMap account")] - InvalidTokenIdMapAccountAddress, + #[msg("TokenNumberMap exists. Please use the correct instruction")] + TokenNumberMapExists, #[msg("Invalid Swim Payload version")] InvalidSwimPayloadVersion, @@ -158,4 +161,19 @@ pub enum PropellerError { #[msg("Invalid Fee Vault")] InvalidFeeVault, + + #[msg("Invalid Memo")] + InvalidMemo, + + #[msg("ToTokenNumber does not match SwimPayload.to_tokenNumber")] + ToTokenNumberMismatch, + + #[msg("Routing Contract is paused")] + IsPaused, + + #[msg("Target Chain is paused")] + TargetChainIsPaused, + + #[msg("Invalid SwimPayloadMessagePayer")] + InvalidSwimPayloadMessagePayer, } diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs index 6ca08b179..ae6ff024e 100644 --- a/packages/solana-contracts/programs/propeller/src/fees.rs +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -1,7 +1,7 @@ use {crate::TOKEN_COUNT, anchor_lang::prelude::*, two_pool::BorshDecimal}; pub trait Fees<'info> { - /// Calculating the fees, including txn and rent exmptions, in lamports. + /// Calculate the fees, including txn and rent exemptions, in lamports. fn calculate_fees_in_lamports(&self) -> Result; fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]>; fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: 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 79fdee0b4..52d814e12 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 @@ -1,16 +1,15 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, - convert_fees_to_swim_usd_atomic, convert_fees_to_swim_usd_atomic_2, deserialize_message_payload, + constants::{LAMPORTS_PER_SOL_DECIMAL, TOKEN_BRIDGE_PROGRAM_ID}, + convert_fees_to_swim_usd_atomic, deserialize_message_payload, error::*, - get_lamports_intermediate_token_price, get_marginal_price_decimal, get_message_data, + get_lamports_intermediate_token_price, get_marginal_price_decimal, get_memo_as_utf8, get_message_data, get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, - token_id_map::{PoolInstruction, TokenIdMap}, - ClaimData, FeeTracker, PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, RawSwimPayload, - TOKEN_COUNT, + token_number_map::{ToTokenStep, TokenNumberMap}, + ClaimData, FeeTracker, Fees, PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, TOKEN_COUNT, }, anchor_lang::{prelude::*, solana_program::program::invoke}, anchor_spl::{ @@ -20,7 +19,7 @@ use { num_traits::{FromPrimitive, ToPrimitive}, rust_decimal::Decimal, solana_program::{instruction::Instruction, program::invoke_signed}, - std::convert::TryInto, + std::{convert::TryInto, iter::zip}, two_pool::{state::TwoPool, BorshDecimal}, }; @@ -29,7 +28,9 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { #[account( seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = aggregator @ PropellerError::InvalidAggregator + has_one = aggregator @ PropellerError::InvalidAggregator, + has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, #[account(mut)] @@ -74,7 +75,7 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { swim_payload_message.vaa_sequence.to_be_bytes().as_ref(), ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge().unwrap(), )] /// CHECK: WH Claim account pub claim: UncheckedAccount<'info>, @@ -86,7 +87,8 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { b"swim_payload".as_ref(), claim.key().as_ref(), ], - bump = swim_payload_message.bump + bump = swim_payload_message.bump, + has_one = claim, )] pub swim_payload_message: Box>, @@ -97,9 +99,10 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { propeller.key().as_ref(), &swim_payload_message.target_token_id.to_le_bytes() ], - bump = token_id_map.bump, + bump = token_number_map.bump, + has_one = pool @ PropellerError::InvalidTokenNumberMapPool, )] - pub token_id_map: Box>, + pub token_number_map: Box>, #[account( mut, @@ -113,8 +116,11 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { seeds::program = two_pool_program.key() )] pub pool: Box>, + #[account(address = pool.token_mint_keys[0])] pub pool_token_0_mint: Box>, + #[account(address = pool.token_mint_keys[1])] pub pool_token_1_mint: Box>, + #[account(address = pool.lp_mint_key)] pub pool_lp_mint: Box>, #[account(address = swim_payload_message.owner)] @@ -176,9 +182,9 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { impl<'info> PropellerCreateOwnerTokenAccounts<'info> { pub fn accounts(ctx: &Context) -> Result<()> { 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); + require_keys_eq!(ctx.accounts.pool.key(), ctx.accounts.token_number_map.pool); let propeller = &ctx.accounts.propeller; - validate_marginal_prices_pool_accounts_2( + validate_marginal_prices_pool_accounts( &propeller, &ctx.accounts.marginal_price_pool, &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], @@ -187,52 +193,69 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { Ok(()) } - fn into_marginal_prices(&self) -> CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>> { - let program = self.two_pool_program.to_account_info(); - let accounts = 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(), - }; - CpiContext::new(program, accounts) + fn initialize_user_ata_and_get_fees( + &self, + user_unchecked_token_account: &UncheckedAccount<'info>, + mint: &Account<'info, Mint>, + ) -> Result { + let ata_data_len = user_unchecked_token_account.data_len(); + + let payer = &self.payer; + let user = &self.user; + let system_program = &self.system_program; + let token_program = &self.token_program; + + if ata_data_len == TokenAccount::LEN { + let token_account = + TokenAccount::try_deserialize(&mut &**user_unchecked_token_account.data.try_borrow_mut().unwrap())?; + require_keys_eq!(token_account.owner, user.key(), PropellerError::IncorrectOwnerForCreateTokenAccount); + return Ok(0u64); + } else if ata_data_len != 0 { + //TODO: spl_token_2022? + // panic!("data_len != 0 && != TokenAcount::LEN"); + return err!(PropellerError::InvalidTokenAccountDataLen); + } else { + let ix = spl_associated_token_account::instruction::create_associated_token_account( + &payer.key(), + &user.key(), + &mint.key(), + ); + invoke( + &ix, + &[ + payer.to_account_info(), + user_unchecked_token_account.to_account_info(), + user.to_account_info(), + mint.to_account_info(), + system_program.to_account_info(), + token_program.to_account_info(), + ], + )?; + let fees = Rent::get()?.minimum_balance(TokenAccount::LEN) + self.propeller.init_ata_fee; + Ok(fees) + } } + fn log_memo(&self) -> Result<()> { + let memo = self.swim_payload_message.memo; + if memo != [0u8; 16] { + let memo_ix = spl_memo::build_memo(get_memo_as_utf8(memo)?.as_ref(), &[]); + invoke(&memo_ix, &[self.memo.to_account_info()])?; + } + Ok(()) + } +} + +impl<'info> Fees<'info> for PropellerCreateOwnerTokenAccounts<'info> { 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, - )?; + let init_token_account_0_fees = + self.initialize_user_ata_and_get_fees(&self.user_pool_token_0_account, &self.pool_token_0_mint)?; + let init_token_account_1_fees = + self.initialize_user_ata_and_get_fees(&self.user_pool_token_1_account, &self.pool_token_1_mint)?; + let init_lp_token_account_fees = + self.initialize_user_ata_and_get_fees(&self.user_lp_token_account, &self.pool_lp_mint)?; 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)) @@ -253,36 +276,83 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { Ok(create_owner_token_account_total_fees_in_lamports) } + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = two_pool::cpi::marginal_prices(CpiContext::new( + self.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(), + }, + ))?; + Ok(result.get()) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + + let propeller = &self.propeller; + let max_staleness = propeller.max_staleness; + 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( + &self.marginal_price_pool, + &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 + ); + Ok(fee_in_swim_usd_atomic) + } + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { let fee_tracker = &mut self.fee_tracker; - let updated_fees_owed = + fee_tracker.fees_owed = fee_tracker.fees_owed.checked_add(fees_in_swim_usd).ok_or(PropellerError::IntegerOverflow)?; - fee_tracker.fees_owed = updated_fees_owed; - let cpi_accounts = Transfer { - from: self.redeemer_escrow.to_account_info(), - to: self.fee_vault.to_account_info(), - authority: self.redeemer.to_account_info(), - }; token::transfer( CpiContext::new_with_signer( self.token_program.to_account_info(), - cpi_accounts, + 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, ) } - - fn log_memo(&self) -> Result<()> { - let memo = self.swim_payload_message.memo; - if memo != [0u8; 16] { - let memo_ix = - spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); - invoke(&memo_ix, &[self.memo.to_account_info()])?; - } - Ok(()) - } } //TODO: allow this regardless of gasKickstart or only if gasKickstart? @@ -291,33 +361,6 @@ 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<()> { - //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); - - //TODO: check `vaa.to` is this program's address? - // let payload_transfer_with_payload = - // get_transfer_with_payload_from_message_account(&ctx.accounts.message.to_account_info())?; - // msg!("message_data_payload: {:?}", payload_transfer_with_payload); - // let PayloadTransferWithPayload { - // message_type, - // amount, - // token_address, - // token_chain, - // to, - // to_chain, - // from_address, - // payload, - // } = payload_transfer_with_payload; - // //TODO: do i need to re-check this? - // // any issue in doing so? - // msg!("payload_transfer_with_payload.to: {:?}", to); - // let to_pubkey = Pubkey::new_from_array(to); - // require_keys_eq!(to_pubkey, crate::ID); - let create_owner_token_account_total_fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; if create_owner_token_account_total_fees_in_lamports == 0 { //TODO: log memo still? @@ -325,99 +368,31 @@ pub fn handle_propeller_create_owner_token_accounts(ctx: Context( - user_unchecked_token_account: AccountInfo<'info>, - payer: AccountInfo<'info>, - user: AccountInfo<'info>, - mint: AccountInfo<'info>, - system_program: AccountInfo<'info>, - token_program: AccountInfo<'info>, - create_ata_fee: u64, -) -> Result { - //TODO: figure out actual cost of create ata txn. - let create_ata_fee = 10000u64; - let ata_data_len = user_unchecked_token_account.data_len(); - if ata_data_len == TokenAccount::LEN { - let token_account = - TokenAccount::try_deserialize(&mut &**user_unchecked_token_account.data.try_borrow_mut().unwrap())?; - require_keys_eq!(token_account.owner, user.key(), PropellerError::IncorrectOwnerForCreateTokenAccount); - return Ok(0u64); - } else if ata_data_len != 0 { - //TODO: spl_token_2022? - // panic!("data_len != 0 && != TokenAcount::LEN"); - return err!(PropellerError::InvalidTokenAccountDataLen); - } else { - let ix = spl_associated_token_account::instruction::create_associated_token_account( - &payer.key(), - &user.key(), - &mint.key(), + ctx.accounts.track_and_transfer_fees(create_owner_token_account_total_fees_in_swim_usd)?; + + let transfer_amount = ctx.accounts.swim_payload_message.transfer_amount; + let new_transfer_amount = transfer_amount + .checked_sub(create_owner_token_account_total_fees_in_swim_usd) + .ok_or(error!(PropellerError::InsufficientFunds))?; + + msg!( + "transfer_amount: {} - fees_in_swim_usd: {} = {}", + transfer_amount, + create_owner_token_account_total_fees_in_swim_usd, + new_transfer_amount ); - invoke(&ix, &[payer, user_unchecked_token_account, user, mint, system_program, token_program])?; - let fees = Rent::get()?.minimum_balance(TokenAccount::LEN) + create_ata_fee; - Ok(fees) + ctx.accounts.swim_payload_message.transfer_amount = new_transfer_amount; } + + ctx.accounts.log_memo()?; + Ok(()) } #[derive(Accounts)] @@ -427,6 +402,8 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, has_one = aggregator @ PropellerError::InvalidAggregator, + has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, #[account(mut)] @@ -554,46 +531,28 @@ 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()); - 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); - // } + TokenNumberMap::assert_is_invalid(&ctx.accounts.token_id_map.to_account_info())?; let propeller = &ctx.accounts.propeller; validate_marginal_prices_pool_accounts( &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(()) } - fn into_marginal_prices(&self) -> CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>> { - let program = self.two_pool_program.to_account_info(); - let accounts = 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(), - }; - CpiContext::new(program, accounts) + fn log_memo(&self) -> Result<()> { + let memo = self.swim_payload_message.memo; + if memo != [0u8; 16] { + let memo_ix = spl_memo::build_memo(get_memo_as_utf8(memo)?.as_ref(), &[]); + invoke(&memo_ix, &[self.memo.to_account_info()])?; + } + Ok(()) } +} +impl<'info> Fees<'info> for PropellerCreateOwnerSwimUsdAta<'info> { fn calculate_fees_in_lamports(&self) -> Result { let fees_in_lamports = Rent::get()? .minimum_balance(TokenAccount::LEN) @@ -602,21 +561,78 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { Ok(fees_in_lamports) } - pub fn handle_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = two_pool::cpi::marginal_prices(CpiContext::new( + self.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(), + }, + ))?; + Ok(result.get()) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { + msg!("fee_in_lamports: {:?}", fee_in_lamports); + let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; + + let propeller = &self.propeller; + let max_staleness = propeller.max_staleness; + 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( + &self.marginal_price_pool, + &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 + ); + Ok(fee_in_swim_usd_atomic) + } + + fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()> { let fee_tracker = &mut self.fee_tracker; - let updated_fees_owed = + fee_tracker.fees_owed = fee_tracker.fees_owed.checked_add(fees_in_swim_usd).ok_or(PropellerError::IntegerOverflow)?; - fee_tracker.fees_owed = updated_fees_owed; - let cpi_accounts = Transfer { - from: self.redeemer_escrow.to_account_info(), - to: self.fee_vault.to_account_info(), - authority: self.redeemer.to_account_info(), - }; token::transfer( CpiContext::new_with_signer( self.token_program.to_account_info(), - cpi_accounts, + 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, @@ -625,41 +641,28 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { } pub fn handle_propeller_create_owner_swim_usd_ata(ctx: Context) -> Result<()> { - 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 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, - marginal_prices.get(), - &ctx.accounts.marginal_price_pool, - &ctx.accounts.aggregator, - i64::MAX, - )?; - ctx.accounts.handle_fees(fees_in_swim_usd_atomic)?; - - let transfer_amount = ctx.accounts.swim_payload_message.transfer_amount; - let new_transfer_amount = - transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; - - msg!( - "transfer_amount: {} - fees_in_swim_usd_atomic: {} = {}", - transfer_amount, - fees_in_swim_usd_atomic, - new_transfer_amount - ); - ctx.accounts.swim_payload_message.transfer_amount = new_transfer_amount; - - let memo = ctx.accounts.swim_payload_message.memo; - if memo != [0u8; 16] { - let memo_ix = spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; + let create_user_swim_usd_ata_fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + let swim_payload_owner = ctx.accounts.swim_payload_message.owner; + + if swim_payload_owner != ctx.accounts.payer.key() { + let create_user_swim_usd_ata_fees_in_swim_usd_atomic = + ctx.accounts.convert_fees_to_swim_usd_atomic(create_user_swim_usd_ata_fees_in_lamports)?; + + ctx.accounts.track_and_transfer_fees(create_user_swim_usd_ata_fees_in_swim_usd_atomic)?; + + let transfer_amount = ctx.accounts.swim_payload_message.transfer_amount; + let new_transfer_amount = transfer_amount + .checked_sub(create_user_swim_usd_ata_fees_in_swim_usd_atomic) + .ok_or(error!(PropellerError::InsufficientFunds))?; + + msg!( + "transfer_amount: {} - fees_in_swim_usd: {} = {}", + transfer_amount, + create_user_swim_usd_ata_fees_in_swim_usd_atomic, + new_transfer_amount + ); + ctx.accounts.swim_payload_message.transfer_amount = new_transfer_amount; } + ctx.accounts.log_memo()?; Ok(()) } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs new file mode 100644 index 000000000..481254a30 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs @@ -0,0 +1,23 @@ +use { + crate::{error::*, Propeller}, + anchor_lang::prelude::*, +}; +#[derive(Accounts)] +pub struct Governance<'info> { + #[account( + seeds = [ + b"propeller".as_ref(), + propeller.swim_usd_mint.as_ref(), + ], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Account<'info, Propeller>, + pub governance_key: Signer<'info>, +} + +pub fn handle_prepare_governance_change(ctx: Context) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + propeller.governance_key = *ctx.accounts.governance_key.key; + Ok(()) +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs new file mode 100644 index 000000000..3a2131296 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs @@ -0,0 +1,4 @@ +pub use {gov::*, pause::*}; + +mod gov; +mod pause; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs new file mode 100644 index 000000000..f48a405f9 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs @@ -0,0 +1,48 @@ +use { + crate::{error::*, Propeller}, + anchor_lang::prelude::*, +}; + +/// Accounts needed for all pause-related ixs +#[derive(Accounts)] +pub struct SetPaused<'info> { + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + propeller.swim_usd_mint.as_ref(), + ], + bump = propeller.bump, + has_one = pause_key @ PropellerError::InvalidPropellerPauseKey, + )] + pub propeller: Box>, + pub pause_key: Signer<'info>, +} + +#[derive(Accounts)] +pub struct ChangePauseKey<'info> { + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + propeller.swim_usd_mint.as_ref(), + ], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Box>, + pub governance_key: Signer<'info>, + pub new_pause_key: Signer<'info>, +} + +pub fn handle_set_paused(ctx: Context, is_paused: bool) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + propeller.is_paused = is_paused; + Ok(()) +} + +pub fn handle_change_pause_key(ctx: Context) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + propeller.pause_key = ctx.accounts.new_pause_key.key(); + Ok(()) +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs index c985d478e..a8e02645c 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs @@ -41,7 +41,9 @@ pub struct Initialize<'info> { )] pub propeller_fee_vault: Box>, - pub admin: Signer<'info>, + pub governance_key: Signer<'info>, + /// CHECK: pause_key + pub pause_key: Signer<'info>, pub swim_usd_mint: Box>, #[account(mut)] @@ -109,13 +111,14 @@ pub struct InitializeParams { pub fn handle_initialize(ctx: Context, params: InitializeParams) -> Result<()> { // let pool = &ctx.accounts.pool; // let mint0 = pool.get_token_mint_0().unwrap(); + msg!("in handle_initialize"); let propeller = &mut ctx.accounts.propeller; propeller.bump = *ctx.bumps.get("propeller").unwrap(); - propeller.nonce = 0; - propeller.admin = ctx.accounts.admin.key(); - //TODO: these should be passed in as params or read based on features used when deploying? - propeller.wormhole = propeller.wormhole()?; - propeller.token_bridge = propeller.token_bridge()?; + propeller.is_paused = false; + propeller.governance_key = ctx.accounts.governance_key.key(); + propeller.prepared_governance_key = Pubkey::default(); + propeller.governance_transition_ts = 0; + propeller.pause_key = ctx.accounts.pause_key.key(); propeller.swim_usd_mint = ctx.accounts.swim_usd_mint.key(); propeller.sender_bump = *ctx.bumps.get("propeller_sender").unwrap(); @@ -136,7 +139,6 @@ pub fn handle_initialize(ctx: Context, params: InitializeParams) -> // propeller.evm_routing_contract_address = params.evm_routing_contract_address; propeller.fee_vault = ctx.accounts.propeller_fee_vault.key(); propeller.aggregator = ctx.accounts.aggregator.key(); + propeller.max_staleness = params.max_staleness; Ok(()) } - -// pub fn init_redeemer_escrow diff --git a/packages/solana-contracts/programs/propeller/src/instructions/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/mod.rs index 7918a3a3f..02ebebf75 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/mod.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/mod.rs @@ -1,6 +1,6 @@ pub use { - create_owner_token_accounts::*, fee_tracker::*, initialize::*, process_swim_payload::*, target_chain_map::*, - token_id_map::*, utils::*, wormhole::*, + create_owner_token_accounts::*, fee_tracker::*, governance::*, initialize::*, process_swim_payload::*, + target_chain_map::*, token_number_map::*, utils::*, wormhole::*, }; pub mod process_swim_payload; @@ -9,8 +9,9 @@ pub mod initialize; // pub mod pool; pub mod create_owner_token_accounts; pub mod fee_tracker; +pub mod governance; pub mod target_chain_map; -pub mod token_id_map; +pub mod token_number_map; pub mod two_pool_cpi; pub mod utils; pub mod wormhole; 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 efe499840..790fb4337 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 @@ -13,13 +13,12 @@ use { hash_vaa, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, - token_id_map::{PoolInstruction, TokenIdMap}, + token_number_map::{ToTokenStep, TokenNumberMap}, ClaimData, PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, - RawSwimPayload, TOKEN_COUNT, }, anchor_lang::system_program, @@ -38,18 +37,19 @@ use { two_pool::state::TwoPool, }; use { - crate::{convert_fees_to_swim_usd_atomic_2, get_lamports_intermediate_token_price, Fees}, + crate::{get_lamports_intermediate_token_price, get_memo_as_utf8, Fees}, two_pool::BorshDecimal, }; pub const SWIM_USD_TO_TOKEN_NUMBER: u16 = 0; #[derive(Accounts)] -#[instruction(target_token_id: u16)] +#[instruction(to_token_number: u16)] pub struct ProcessSwimPayload<'info> { #[account( seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], - bump = propeller.bump + bump = propeller.bump, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, #[account(mut)] @@ -88,8 +88,8 @@ pub struct ProcessSwimPayload<'info> { claim.key().as_ref(), ], bump = swim_payload_message.bump, - has_one = swim_payload_message_payer, - has_one = claim, + has_one = swim_payload_message_payer @ PropellerError::InvalidSwimPayloadMessagePayer, + has_one = claim @ PropellerError::InvalidWormholeClaimAccount, )] pub swim_payload_message: Box>, @@ -117,11 +117,12 @@ pub struct ProcessSwimPayload<'info> { b"propeller".as_ref(), b"token_id".as_ref(), propeller.key().as_ref(), - &target_token_id.to_le_bytes() + &to_token_number.to_le_bytes() ], - bump = token_id_map.bump, + bump = token_number_map.bump, + has_one = pool @ PropellerError::InvalidTokenNumberMapPool, )] - pub token_id_map: Account<'info, TokenIdMap>, + pub token_number_map: Account<'info, TokenNumberMap>, /* Pool Used for final swap to get token_id_map.pool_token_mint */ #[account( @@ -139,18 +140,18 @@ pub struct ProcessSwimPayload<'info> { #[account( mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, + address = get_associated_token_address(&pool.key(), &pool_token_account_0.mint), + constraint = pool.token_keys[0] == pool_token_account_0.key(), )] pub pool_token_account_0: Box>, #[account( mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, + address = get_associated_token_address(&pool.key(), &pool_token_account_1.mint), + constraint = pool.token_keys[1] == pool_token_account_1.key(), )] pub pool_token_account_1: Box>, - #[account(mut)] + #[account(mut, address = pool.lp_mint_key)] pub lp_mint: Box>, #[account( mut, @@ -190,8 +191,8 @@ impl<'info> ProcessSwimPayload<'info> { require_keys_eq!(ctx.accounts.swim_payload_message.claim.key(), ctx.accounts.claim.key()); require_keys_eq!( ctx.accounts.pool.key(), - ctx.accounts.token_id_map.pool, - PropellerError::InvalidTokenIdMapPool + ctx.accounts.token_number_map.pool, + PropellerError::InvalidTokenNumberMapPool ); Ok(()) } @@ -200,29 +201,21 @@ impl<'info> ProcessSwimPayload<'info> { // verify claim // verify message require_keys_eq!(self.swim_payload_message.claim.key(), self.claim.key()); - require_keys_eq!(self.pool.key(), self.token_id_map.pool, PropellerError::InvalidTokenIdMapPool); + require_keys_eq!(self.pool.key(), self.token_number_map.pool, PropellerError::InvalidTokenNumberMapPool); Ok(()) } - pub fn transfer_tokens( - &self, - output_token_index: u16, - transfer_amount: u64, - min_output_amount: u64, - ) -> Result { - let token_id_mapping = &self.token_id_map; - let pool_ix = &token_id_mapping.pool_ix; + pub fn transfer_tokens(&self, to_token_number: u16, transfer_amount: u64, min_output_amount: u64) -> Result { + let token_id_mapping = &self.token_number_map; + let to_token_step = &token_id_mapping.to_token_step; let pool_token_mint = &token_id_mapping.pool_token_mint; let pool_token_index = token_id_mapping.pool_token_index; - //TODO: decide if using user_transfer_auth - // remove user_transfer_authority account if not. - - self.execute_transfer_or_pool_ix( + self.execute_to_token_step( transfer_amount, min_output_amount, - output_token_index, - pool_ix, + to_token_number, + to_token_step, pool_token_index, pool_token_mint, &self.redeemer.to_account_info(), @@ -230,12 +223,12 @@ impl<'info> ProcessSwimPayload<'info> { ) } - fn execute_transfer_or_pool_ix( + fn execute_to_token_step( &self, transfer_amount: u64, min_output_amount: u64, output_token_index: u16, - pool_ix: &PoolInstruction, + to_token_step: &ToTokenStep, pool_token_index: u8, pool_token_mint: &Pubkey, user_transfer_authority: &AccountInfo<'info>, @@ -243,8 +236,8 @@ impl<'info> ProcessSwimPayload<'info> { ) -> Result { let swim_payload_owner = self.swim_payload_message.owner; require_gt!(TOKEN_COUNT, pool_token_index as usize); - match pool_ix { - PoolInstruction::RemoveExactBurn => { + match to_token_step { + ToTokenStep::RemoveExactBurn => { msg!("Executing RemoveExactBurn"); require_keys_eq!(self.pool.token_mint_keys[pool_token_index as usize], *pool_token_mint); @@ -272,7 +265,7 @@ impl<'info> ProcessSwimPayload<'info> { )? .get()) } - PoolInstruction::SwapExactInput => { + ToTokenStep::SwapExactInput => { msg!("Executing SwapExactInput"); require_keys_eq!(self.pool.token_mint_keys[pool_token_index as usize], *pool_token_mint); @@ -298,7 +291,7 @@ impl<'info> ProcessSwimPayload<'info> { )? .get()) } - PoolInstruction::Transfer => { + ToTokenStep::Transfer => { require_eq!(output_token_index, SWIM_USD_TO_TOKEN_NUMBER, PropellerError::InvalidOutputTokenIndex); self.transfer_swim_usd_tokens(transfer_amount, user_transfer_authority, signer_seeds) } @@ -337,7 +330,7 @@ impl<'info> ProcessSwimPayload<'info> { pub fn handle_process_swim_payload( ctx: Context, - target_token_id: u16, + to_token_number: u16, min_output_amount: u64, ) -> Result { let propeller_message = &ctx.accounts.swim_payload_message; @@ -353,10 +346,11 @@ pub fn handle_process_swim_payload( let token_program = &ctx.accounts.token_program; msg!("transfer_amount: {}", transfer_amount); - let output_amount = ctx.accounts.transfer_tokens(target_token_id, transfer_amount, min_output_amount)?; + let output_amount = ctx.accounts.transfer_tokens(to_token_number, transfer_amount, min_output_amount)?; let swim_claim_bump = *ctx.bumps.get("swim_claim").unwrap(); ctx.accounts.init_swim_claim(swim_claim_bump)?; + msg!("output_amount: {}", output_amount); Ok(output_amount) } @@ -437,8 +431,16 @@ pub struct PropellerProcessSwimPayload<'info> { } impl<'info> PropellerProcessSwimPayload<'info> { - pub fn accounts(ctx: &Context, target_token_id: u16) -> Result<()> { - ctx.accounts.validate()?; + pub fn accounts(ctx: &Context, to_token_number: u16) -> Result<()> { + require_keys_eq!( + ctx.accounts.process_swim_payload.swim_payload_message.claim.key(), + ctx.accounts.process_swim_payload.claim.key() + ); + require_keys_eq!( + ctx.accounts.process_swim_payload.pool.key(), + ctx.accounts.process_swim_payload.token_number_map.pool, + PropellerError::InvalidTokenNumberMapPool + ); require_keys_eq!( ctx.accounts.process_swim_payload.propeller.aggregator, ctx.accounts.aggregator.key(), @@ -446,36 +448,19 @@ impl<'info> PropellerProcessSwimPayload<'info> { ); require_eq!( ctx.accounts.process_swim_payload.swim_payload_message.target_token_id, - target_token_id, - // PropellerError::InvalidTargetTokenId + to_token_number, + PropellerError::ToTokenNumberMismatch ); + let propeller = &ctx.accounts.process_swim_payload.propeller; validate_marginal_prices_pool_accounts( - &ctx.accounts.process_swim_payload.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, - ], + &propeller, + &ctx.accounts.marginal_price_pool, + &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], )?; msg!("Finished PropellerProcessSwimPayload::accounts()"); Ok(()) } - pub fn validate(&self) -> Result<()> { - // verify claim - // verify message - require_keys_eq!( - self.process_swim_payload.swim_payload_message.claim.key(), - self.process_swim_payload.claim.key() - ); - require_keys_eq!( - self.process_swim_payload.pool.key(), - self.process_swim_payload.token_id_map.pool, - PropellerError::InvalidTokenIdMapPool - ); - Ok(()) - } - fn transfer_gas_kickstart(&self) -> Result<()> { let propeller = &self.process_swim_payload.propeller; let owner_account = &self.owner.to_account_info(); @@ -503,11 +488,8 @@ impl<'info> PropellerProcessSwimPayload<'info> { fn log_memo(&self) -> Result<()> { let memo = self.process_swim_payload.swim_payload_message.memo; if memo != [0u8; 16] { - let memo_ix = - spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); + let memo_ix = spl_memo::build_memo(get_memo_as_utf8(memo)?.as_ref(), &[]); invoke(&memo_ix, &[self.memo.to_account_info()])?; - } else { - msg!("memo is empty"); } Ok(()) } @@ -645,7 +627,7 @@ TODO: */ pub fn handle_propeller_process_swim_payload( ctx: Context, - target_token_id: u16, + to_token_number: u16, ) -> Result { let swim_payload_message = &ctx.accounts.process_swim_payload.swim_payload_message; let is_gas_kickstart = swim_payload_message.gas_kickstart; @@ -672,9 +654,6 @@ pub fn handle_propeller_process_swim_payload( } transfer_amount = transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; - } else { - //TODO: a user should just call processSwimPayload instead to avoid passing in extra accounts. end result is same. - msg!("swim_payload_owner == ctx.accounts.payer.key(). Owner bypass"); } msg!("transfer_amount - fee = {}", transfer_amount); @@ -736,9 +715,9 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { claim.key().as_ref(), ], bump = swim_payload_message.bump, - has_one = swim_payload_message_payer, + has_one = swim_payload_message_payer @ PropellerError::InvalidSwimPayloadMessagePayer, + has_one = claim @ PropellerError::InvalidWormholeClaimAccount, has_one = owner, - has_one = claim, )] pub swim_payload_message: Box>, #[account(mut)] @@ -769,10 +748,10 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { ], 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 + /// CHECK: Unchecked b/c if `to_token_number` is invalid then this account should not exist/be able to be + /// deserialized as a `TokenNumberMap`. if it does exist, then engine should have called /// propeller_create_owner_token_accounts instead - pub token_id_map: UncheckedAccount<'info>, + pub token_number_map: UncheckedAccount<'info>, #[account( mut, @@ -841,11 +820,8 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { require_keys_eq!(ctx.accounts.owner.key(), ctx.accounts.swim_payload_message.owner); validate_marginal_prices_pool_accounts( &ctx.accounts.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 PropellerProcessSwimPayloadFallback::accounts() check"); Ok(()) @@ -903,8 +879,7 @@ impl<'info> PropellerProcessSwimPayloadFallback<'info> { fn log_memo(&self) -> Result<()> { let memo = self.swim_payload_message.memo; if memo != [0u8; 16] { - let memo_ix = - spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); + let memo_ix = spl_memo::build_memo(get_memo_as_utf8(memo)?.as_ref(), &[]); invoke(&memo_ix, &[self.memo.to_account_info()])?; } Ok(()) @@ -1048,9 +1023,6 @@ pub fn handle_propeller_process_swim_payload_fallback( } transfer_amount = transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; - } else { - //TODO: a user should just call processSwimPayload instead to avoid passing in extra accounts. end result is same. - msg!("swim_payload_owner == ctx.accounts.payer.key(). Owner bypass"); } msg!("transfer_amount - fee = {}", transfer_amount); diff --git a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs index e59621982..e0afe3c85 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs @@ -14,11 +14,11 @@ pub struct CreateTargetChainMap<'info> { #[account( seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = admin, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, )] pub propeller: Account<'info, Propeller>, - pub admin: Signer<'info>, + pub governance_key: Signer<'info>, #[account(mut)] pub payer: Signer<'info>, @@ -42,10 +42,11 @@ pub struct TargetChainMap { pub bump: u8, pub target_chain: u16, pub target_address: [u8; 32], + pub is_paused: bool, } impl TargetChainMap { - pub const LEN: usize = 1 + 2 + 32; + pub const LEN: usize = 1 + 2 + 32 + 1; } pub fn handle_create_target_chain_map( @@ -58,6 +59,7 @@ pub fn handle_create_target_chain_map( target_chain_map.bump = *bump; target_chain_map.target_chain = target_chain; target_chain_map.target_address = target_address; + target_chain_map.is_paused = false; Ok(()) } @@ -66,11 +68,11 @@ pub struct UpdateTargetChainMap<'info> { #[account( seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = admin, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, )] - pub propeller: Account<'info, Propeller>, + pub propeller: Box>, - pub admin: Signer<'info>, + pub governance_key: Signer<'info>, #[account(mut)] pub payer: Signer<'info>, @@ -84,7 +86,6 @@ pub struct UpdateTargetChainMap<'info> { bump = target_chain_map.bump, )] pub target_chain_map: Account<'info, TargetChainMap>, - pub system_program: Program<'info, System>, } pub fn handle_update_target_chain_map(ctx: Context, routing_contract: [u8; 32]) -> Result<()> { @@ -96,3 +97,35 @@ pub fn handle_update_target_chain_map(ctx: Context, routin pub fn handle_close_target_chain_map() -> Result<()> { todo!() } + +#[derive(Accounts)] +pub struct TargetChainMapSetPaused<'info> { + #[account( + seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], + bump = propeller.bump, + has_one = pause_key @ PropellerError::InvalidPropellerPauseKey, + )] + pub propeller: Account<'info, Propeller>, + + pub pause_key: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + propeller.key().as_ref(), + &target_chain_map.target_chain.to_le_bytes() + ], + bump = target_chain_map.bump, + )] + pub target_chain_map: Account<'info, TargetChainMap>, +} + +pub fn handle_target_chain_map_set_paused(ctx: Context, is_paused: bool) -> Result<()> { + let target_chain_map = &mut ctx.accounts.target_chain_map; + target_chain_map.is_paused = is_paused; + Ok(()) +} 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 deleted file mode 100644 index 2cf358ea2..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/token_id_map.rs +++ /dev/null @@ -1,139 +0,0 @@ -use { - crate::{error::PropellerError, Propeller, TOKEN_COUNT}, - anchor_lang::prelude::*, - anchor_spl::{ - associated_token::{create, AssociatedToken, Create}, - token::{Mint, Token, TokenAccount}, - }, - two_pool::state::TwoPool, -}; - -#[derive(Accounts)] -#[instruction(target_token_index: u16, pool: Pubkey, pool_token_index: u8, pool_token_mint: Pubkey)] -pub struct CreateTokenIdMap<'info> { - #[account( - seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], - bump = propeller.bump, - has_one = admin @ PropellerError::InvalidPropellerAdmin, - )] - pub propeller: Account<'info, Propeller>, - - pub admin: Signer<'info>, - - #[account(mut)] - pub payer: Signer<'info>, - - #[account( - seeds = [ - b"two_pool".as_ref(), - pool.get_token_mint_0().unwrap().as_ref(), - pool.get_token_mint_1().unwrap().as_ref(), - pool.lp_mint_key.as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key(), - )] - pub pool: Account<'info, TwoPool>, - - #[account( - init, - payer = payer, - seeds = [ - b"propeller".as_ref(), - b"token_id".as_ref(), - propeller.key().as_ref(), - &target_token_index.to_le_bytes() - ], - bump, - space = 8 + TokenIdMap::LEN, - )] - pub token_id_map: Account<'info, TokenIdMap>, - pub system_program: Program<'info, System>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -} - -#[account] -pub struct TokenIdMap { - pub output_token_index: u16, - pub pool: Pubkey, - pub pool_token_index: u8, - pub pool_token_mint: Pubkey, - pub pool_ix: PoolInstruction, - pub bump: u8, -} - -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)] -pub enum PoolInstruction { - Transfer, - RemoveExactBurn, - SwapExactInput, -} - -impl<'info> CreateTokenIdMap<'info> { - pub fn accounts( - ctx: &Context, - target_token_index: u16, - pool: Pubkey, - pool_token_index: u8, - pool_token_mint: Pubkey, - pool_ix: PoolInstruction, - ) -> Result<()> { - //TODO: add error codes - require_keys_eq!(ctx.accounts.propeller.admin, ctx.accounts.admin.key(), PropellerError::InvalidPropellerAdmin); - require_keys_eq!(ctx.accounts.pool.key(), pool, PropellerError::InvalidTokenIdMapPool); - if let PoolInstruction::Transfer = pool_ix { - require_keys_eq!( - ctx.accounts.propeller.swim_usd_mint, - pool_token_mint, - PropellerError::InvalidTokenIdMapPoolTokenMint - ); - return Ok(()); - } - - let pool_token_index = pool_token_index as usize; - require_gt!(TOKEN_COUNT, pool_token_index, PropellerError::InvalidTokenIdMapPoolTokenIndex); - require_keys_eq!( - ctx.accounts.pool.token_mint_keys[pool_token_index], - pool_token_mint, - PropellerError::InvalidTokenIdMapPoolTokenMint - ); - Ok(()) - } -} - -pub fn handle_create_token_id_map( - ctx: Context, - target_token_index: u16, - pool: Pubkey, - pool_token_index: u8, - pool_token_mint: Pubkey, - pool_ix: PoolInstruction, -) -> Result<()> { - let mut token_id_map = &mut ctx.accounts.token_id_map; - token_id_map.output_token_index = target_token_index; - token_id_map.pool = pool; - token_id_map.pool_token_index = pool_token_index; - token_id_map.pool_token_mint = pool_token_mint; - token_id_map.bump = *ctx.bumps.get("token_id_map").unwrap(); - token_id_map.pool_ix = pool_ix; - Ok(()) -} - -pub fn handle_update_token_id_map() -> Result<()> { - todo!() -} - -pub fn handle_close_token_id_map() -> Result<()> { - todo!() -} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs new file mode 100644 index 000000000..06f0c1f9e --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs @@ -0,0 +1,276 @@ +use { + crate::{error::PropellerError, Propeller, TOKEN_COUNT}, + anchor_lang::prelude::*, + anchor_spl::{ + associated_token::{create, AssociatedToken, Create}, + token::{Mint, Token, TokenAccount}, + }, + two_pool::state::TwoPool, +}; + +#[derive(Accounts)] +#[instruction(to_token_number: u16, pool: Pubkey, pool_token_index: u8, pool_token_mint: Pubkey)] +pub struct CreateTokenNumberMap<'info> { + #[account( + seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Box>, + + pub governance_key: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + seeds = [ + b"two_pool".as_ref(), + pool.token_mint_keys[0].as_ref(), + pool.token_mint_keys[1].as_ref(), + pool.lp_mint_key.as_ref(), + ], + bump = pool.bump, + seeds::program = two_pool_program.key(), + )] + pub pool: Box>, + + #[account( + init, + payer = payer, + seeds = [ + b"propeller".as_ref(), + b"token_id".as_ref(), + propeller.key().as_ref(), + &to_token_number.to_le_bytes() + ], + bump, + space = 8 + TokenNumberMap::LEN, + )] + pub token_number_map: Account<'info, TokenNumberMap>, + pub system_program: Program<'info, System>, + pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +} + +#[account] +pub struct TokenNumberMap { + pub bump: u8, + pub to_token_number: u16, + pub pool: Pubkey, + pub pool_token_index: u8, + pub pool_token_mint: Pubkey, + pub to_token_step: ToTokenStep, +} + +impl TokenNumberMap { + pub const LEN: usize = 2 + 32 + 1 + 32 + 1 + 1 + 1; + + pub fn assert_is_invalid(token_id_map: &AccountInfo) -> Result<()> { + if let Ok(_) = TokenNumberMap::try_deserialize(&mut &**token_id_map.try_borrow_mut_data()?) { + return err!(PropellerError::TokenNumberMapExists); + } + Ok(()) + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, Copy, Clone, Debug)] +pub enum ToTokenStep { + Transfer, + RemoveExactBurn, + SwapExactInput, +} + +impl<'info> CreateTokenNumberMap<'info> { + pub fn accounts( + ctx: &Context, + to_token_number: u16, + pool: Pubkey, + pool_token_index: u8, + pool_token_mint: Pubkey, + to_token_step: ToTokenStep, + ) -> Result<()> { + require_keys_eq!(ctx.accounts.pool.key(), pool, PropellerError::InvalidTokenNumberMapPool); + if let ToTokenStep::Transfer = to_token_step { + require_keys_eq!( + ctx.accounts.propeller.swim_usd_mint, + pool_token_mint, + PropellerError::InvalidTokenNumberMapPoolTokenMint + ); + return Ok(()); + } + + let pool_token_index = pool_token_index as usize; + require_gt!(TOKEN_COUNT, pool_token_index, PropellerError::InvalidTokenNumberMapPoolTokenIndex); + require_keys_eq!( + ctx.accounts.pool.token_mint_keys[pool_token_index], + pool_token_mint, + PropellerError::InvalidTokenNumberMapPoolTokenMint + ); + Ok(()) + } +} + +pub fn handle_create_token_number_map( + ctx: Context, + to_token_number: u16, + pool: Pubkey, + pool_token_index: u8, + pool_token_mint: Pubkey, + to_token_step: ToTokenStep, +) -> Result<()> { + let mut token_number_map = &mut ctx.accounts.token_number_map; + token_number_map.to_token_number = to_token_number; + token_number_map.pool = pool; + token_number_map.pool_token_index = pool_token_index; + token_number_map.pool_token_mint = pool_token_mint; + token_number_map.bump = *ctx.bumps.get("token_number_map").unwrap(); + token_number_map.to_token_step = to_token_step; + Ok(()) +} + +#[derive(Accounts)] +#[instruction(to_token_number: u16)] +pub struct UpdateTokenNumberMap<'info> { + #[account( + seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Box>, + + pub governance_key: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + // #[account( + // seeds = [ + // b"two_pool".as_ref(), + // pool.token_mint_keys[0].as_ref(), + // pool.token_mint_keys[1].as_ref(), + // pool.lp_mint_key.as_ref(), + // ], + // bump = pool.bump, + // seeds::program = two_pool_program.key(), + // )] + // Note: anchor is unable to compile when i use the `#[account]` macro here even though it's the + // exact same as above. manually validating the address in `accounts` fn + pub pool: Box>, + + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + b"token_id".as_ref(), + propeller.key().as_ref(), + &to_token_number.to_le_bytes() + ], + bump = token_number_map.bump, + constraint = token_number_map.to_token_number == to_token_number, + )] + pub token_number_map: Account<'info, TokenNumberMap>, + pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +} + +impl<'info> UpdateTokenNumberMap<'info> { + pub fn accounts( + ctx: &Context, + pool_token_index: &u8, + pool_token_mint: &Pubkey, + to_token_step: &ToTokenStep, + ) -> Result<()> { + let propeller = &ctx.accounts.propeller; + let pool = &ctx.accounts.pool; + let pool_token_mint = *pool_token_mint; + let expected_pool_key = Pubkey::create_program_address( + &[ + b"two_pool".as_ref(), + pool.token_mint_keys[0].as_ref(), + &pool.token_mint_keys[1].as_ref(), + &pool.lp_mint_key.as_ref(), + &[pool.bump], + ], + &ctx.accounts.two_pool_program.key(), + ) + .map_err(|_| PropellerError::InvalidTokenNumberMapPool)?; + require_keys_eq!( + *pool.to_account_info().owner, + ctx.accounts.two_pool_program.key(), + PropellerError::InvalidTokenNumberMapPool + ); + require_keys_eq!(ctx.accounts.pool.key(), expected_pool_key, PropellerError::InvalidTokenNumberMapPool); + let pool_token_index = *pool_token_index as usize; + require_gt!(TOKEN_COUNT, pool_token_index as usize, PropellerError::InvalidTokenNumberMapPoolTokenIndex); + match *to_token_step { + // metapools must have swimUSD as token_mint_keys[0] + ToTokenStep::SwapExactInput => { + require_keys_eq!(pool.token_mint_keys[0], propeller.swim_usd_mint); + require_keys_eq!(pool.token_mint_keys[1], pool_token_mint); + require_eq!(pool_token_index, 1 as usize); + } + ToTokenStep::RemoveExactBurn => { + require_keys_eq!(pool.lp_mint_key, pool_token_mint); + require_keys_eq!(pool.lp_mint_key, propeller.swim_usd_mint); + require_keys_eq!(pool.token_mint_keys[pool_token_index], pool_token_mint); + } + ToTokenStep::Transfer => { + require_keys_eq!( + ctx.accounts.propeller.swim_usd_mint, + pool_token_mint, + PropellerError::InvalidTokenNumberMapPoolTokenMint + ); + } + } + Ok(()) + } +} + +pub fn handle_update_token_number_map( + ctx: Context, + _to_token_number: u16, + pool_token_index: u8, + pool_token_mint: Pubkey, + to_token_step: ToTokenStep, +) -> Result<()> { + let token_number_map = &mut ctx.accounts.token_number_map; + token_number_map.pool = ctx.accounts.pool.key(); + token_number_map.pool_token_index = pool_token_index; + token_number_map.pool_token_mint = pool_token_mint; + token_number_map.to_token_step = to_token_step; + Ok(()) +} + +#[derive(Accounts)] +#[instruction(to_token_number: u16)] +pub struct CloseTokenNumberMap<'info> { + #[account( + seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Box>, + + pub governance_key: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + b"token_id".as_ref(), + propeller.key().as_ref(), + &to_token_number.to_le_bytes() + ], + bump = token_number_map.bump, + close = payer, + )] + pub token_number_map: Account<'info, TokenNumberMap>, +} + +pub fn handle_close_token_number_map(ctx: Context, to_token_number: u16) -> Result<()> { + //TODO emit event? + msg!("Closed TokenNumberMap {} for to_token_number {}", ctx.accounts.token_number_map.key(), to_token_number); + Ok(()) +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs index 2dc13ea37..081e46525 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs @@ -13,7 +13,7 @@ pub struct Add<'info> { #[account( seeds = [ b"propeller".as_ref(), lp_mint.key().as_ref()], bump = propeller.bump, - + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, #[account( @@ -139,6 +139,7 @@ pub fn handle_cross_chain_add( lp_mint: ctx.accounts.lp_mint.to_account_info(), governance_fee: ctx.accounts.governance_fee.to_account_info(), user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), + user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs index 36186376f..091f88e29 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs @@ -17,6 +17,7 @@ pub struct SwapExactInput<'info> { ], bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Account<'info, Propeller>, #[account( diff --git a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs index cdaef24f0..7c216ac31 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs @@ -68,59 +68,59 @@ pub fn convert_fees_to_swim_usd_atomic<'info>( res = fee_in_swim_usd_atomic; 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 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, @@ -169,12 +169,8 @@ pub fn get_lamports_intermediate_token_price( max_staleness: i64, ) -> Result { let feed = aggregator.load()?; - feed.check_staleness( - Clock::get().unwrap().unix_timestamp, - // 300 - i64::MAX, - ) - .map_err(|_| error!(PropellerError::StaleFeed))?; + feed.check_staleness(Clock::get().unwrap().unix_timestamp, max_staleness) + .map_err(|_| error!(PropellerError::StaleFeed))?; // check feed does not exceed max_confidence_interval // if let Some(max_confidence_interval) = params.max_confidence_interval { @@ -191,3 +187,7 @@ pub fn get_lamports_intermediate_token_price( Ok(lamports_usd_price) // check whether the feed has been updated in the last 300 seconds } + +pub fn get_memo_as_utf8(memo: [u8; 16]) -> Result { + String::from_utf8(hex::encode(memo).into_bytes()).map_err(|_| error!(PropellerError::InvalidMemo)) +} 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 f02ec58ac..ba015eb9c 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 @@ -1,13 +1,12 @@ -use crate::Fees; +use crate::{get_memo_as_utf8, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees}; use { crate::{ constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, get_lamports_intermediate_token_price, get_marginal_price_decimal, get_marginal_prices, get_message_data, get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, - instructions::fee_tracker::FeeTracker, state::SwimPayloadMessage, validate_marginal_prices_pool_accounts, - Address, ChainID, ClaimData, MessageData, PayloadTransferWithPayload, PostVAAData, PostedMessageData, - PostedVAAData, Propeller, RawSwimPayload, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, - TOKEN_COUNT, + instructions::fee_tracker::FeeTracker, state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, + PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, TokenBridge, Wormhole, + COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, }, anchor_lang::{ prelude::*, @@ -35,6 +34,7 @@ pub struct CompleteNativeWithPayload<'info> { bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, has_one = fee_vault @ PropellerError::InvalidFeeVault, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, @@ -45,7 +45,7 @@ pub struct CompleteNativeWithPayload<'info> { mut, seeds = [ b"config".as_ref() ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = token_bridge.key(), )] /// CHECK: Token Bridge Config pub token_bridge_config: UncheckedAccount<'info>, @@ -77,14 +77,20 @@ pub struct CompleteNativeWithPayload<'info> { // bump, // seeds::program = propeller.wormhole()? // )] + // pub message: Box>, #[account( mut, - owner = propeller.wormhole()?, + owner = wormhole.key(), )] /// CHECK: wormhole message account. seeds = [ "PostedVAA", hash(vaa) ], seeds::program = token_bridge pub message: UncheckedAccount<'info>, - // pub message: Account<'info, PostedMessageData>, - // pub message: Account<'info, PostedVAAData>, + // Note: this works only without the Box wrapper + // error[E0277]: the trait bound `Box>: AsRef>` is not satisfied + // + // #[derive(Accounts)] + // ^^^^^^^^ the trait `AsRef>` is not implemented for `Box>` + + // pub message: Box>, /// seeds = [ /// vaa.emitter_address, vaa.emitter_chain, vaa.sequence ///], @@ -131,39 +137,49 @@ pub struct CompleteNativeWithPayload<'info> { )] /// this is "to_fees" /// recipient of fees for executing complete transfer (e.g. relayer) + /// this is only used in `propellerCompleteNativeWithPayload`. pub fee_vault: Box>, + + #[account( + init, + payer = payer, + seeds = [ + b"propeller".as_ref(), + b"swim_payload".as_ref(), + claim.key().as_ref(), + ], + bump, + space = 8 + SwimPayloadMessage::LEN, + )] + pub swim_payload_message: Box>, // #[account(mut)] // /// this is "to_fees" // /// TODO: type as TokenAccount? // /// CHECK: recipient of fees for executing complete transfer (e.g. relayer) // pub fee_recipient: AccountInfo<'info>, - #[account(mut)] + #[account( + mut, + seeds = [swim_usd_mint.key().as_ref()], + seeds::program = token_bridge.key(), + bump, + )] /// CHECK: wormhole_custody_account: seeds = [mint], seeds::program = token_bridge pub custody: UncheckedAccount<'info>, // #[account(address = propeller.token_bridge_mint)] pub swim_usd_mint: Box>, + #[account( + seeds = [b"custody_signer".as_ref()], + seeds::program = token_bridge.key(), + bump, + )] /// CHECK: custody_signer_account: seeds = [b"custody_signer"], seeds::program = token_bridge pub custody_signer: UncheckedAccount<'info>, - pub rent: Sysvar<'info, Rent>, - pub system_program: Program<'info, System>, - pub wormhole: Program<'info, Wormhole>, pub token_program: Program<'info, Token>, pub token_bridge: Program<'info, TokenBridge>, - - #[account( - init, - payer = payer, - seeds = [ - b"propeller".as_ref(), - b"swim_payload".as_ref(), - claim.key().as_ref(), - ], - bump, - space = 8 + SwimPayloadMessage::LEN, - )] - pub swim_payload_message: Account<'info, SwimPayloadMessage>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent>, } impl<'info> CompleteNativeWithPayload<'info> { @@ -242,20 +258,45 @@ impl<'info> CompleteNativeWithPayload<'info> { } pub fn get_transfer_with_payload(&self, message_data: &MessageData) -> Result { - // let message_account_info = &self.message.to_account_info(); - // let message_data = get_message_data(message_account_info)?; - // msg!("message_data: {:?}", message_data); - let transfer_with_payload = deserialize_message_payload(&mut message_data.payload.as_slice())?; + // let transfer_with_payload = deserialize_message_payload(&mut message_data.payload.as_slice())?; + let transfer_with_payload = PayloadTransferWithPayload::deserialize(&mut message_data.payload.as_slice())?; msg!("transfer_with_payload: {:?}", transfer_with_payload); Ok(transfer_with_payload) } + // fn write_swim_payload_message( + // &mut self, + // bump: u8, + // message_data: &MessageData, + // transfer_amount: u64, + // swim_payload: &RawSwimPayload, + // ) -> Result<()> { + // let swim_payload_message = &mut self.swim_payload_message; + // swim_payload_message.bump = bump; + // swim_payload_message.claim = self.claim.key(); + // // swim_payload_message.claim_bump = *ctx.bumps.get("claim").unwrap(); + // swim_payload_message.swim_payload_message_payer = self.payer.key(); + // // swim_payload_message.wh_message_bump = *ctx.bumps.get("message").unwrap(); + // swim_payload_message.vaa_emitter_address = message_data.emitter_address; + // swim_payload_message.vaa_emitter_chain = message_data.emitter_chain; + // swim_payload_message.vaa_sequence = message_data.sequence; + // swim_payload_message.transfer_amount = transfer_amount; + // swim_payload_message.swim_payload_version = swim_payload.swim_payload_version; + // swim_payload_message.max_fee = swim_payload.max_fee; + // swim_payload_message.target_token_id = swim_payload.target_token_id; + // swim_payload_message.owner = Pubkey::new_from_array(swim_payload.owner); + // swim_payload_message.memo = swim_payload.memo; + // swim_payload_message.propeller_enabled = swim_payload.propeller_enabled; + // swim_payload_message.gas_kickstart = swim_payload.gas_kickstart; + // Ok(()) + // } + fn write_swim_payload_message( &mut self, bump: u8, message_data: &MessageData, transfer_amount: u64, - swim_payload: &RawSwimPayload, + swim_payload: &SwimPayload, ) -> Result<()> { let swim_payload_message = &mut self.swim_payload_message; swim_payload_message.bump = bump; @@ -268,11 +309,12 @@ impl<'info> CompleteNativeWithPayload<'info> { swim_payload_message.vaa_sequence = message_data.sequence; swim_payload_message.transfer_amount = transfer_amount; swim_payload_message.swim_payload_version = swim_payload.swim_payload_version; - swim_payload_message.target_token_id = swim_payload.target_token_id; swim_payload_message.owner = Pubkey::new_from_array(swim_payload.owner); - swim_payload_message.memo = swim_payload.memo; - swim_payload_message.propeller_enabled = swim_payload.propeller_enabled; - swim_payload_message.gas_kickstart = swim_payload.gas_kickstart; + swim_payload_message.propeller_enabled = swim_payload.propeller_enabled.unwrap_or_default(); + swim_payload_message.gas_kickstart = swim_payload.gas_kickstart.unwrap_or_default(); + swim_payload_message.max_fee = swim_payload.max_fee.unwrap_or_default(); + swim_payload_message.target_token_id = swim_payload.target_token_id.unwrap_or_default(); + swim_payload_message.memo = swim_payload.memo.unwrap_or_default(); Ok(()) } } @@ -369,11 +411,8 @@ impl<'info> PropellerCompleteNativeWithPayload<'info> { let propeller = &ctx.accounts.complete_native_with_payload.propeller; validate_marginal_prices_pool_accounts( &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], )?; require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.key(), propeller.fee_vault); require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.owner, propeller.key()); @@ -383,9 +422,8 @@ impl<'info> PropellerCompleteNativeWithPayload<'info> { fn log_memo(&self, memo: [u8; 16]) -> Result<()> { if memo != [0u8; 16] { - let memo_ix = - spl_memo::build_memo(std::str::from_utf8(hex::encode(memo).as_bytes()).unwrap().as_ref(), &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; + let memo_ix = spl_memo::build_memo(get_memo_as_utf8(memo)?.as_ref(), &[]); + invoke(&memo_ix, &[self.memo.to_account_info()])?; } Ok(()) } @@ -520,7 +558,7 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context { #[account( mut, seeds = [b"propeller".as_ref(), swim_usd_mint.key().as_ref()], bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, @@ -187,7 +191,8 @@ pub struct TransferNativeWithPayload<'info> { propeller.key().as_ref(), &target_chain.to_le_bytes() ], - bump = target_chain_map.bump + bump = target_chain_map.bump, + constraint = !target_chain_map.is_paused @ PropellerError::TargetChainIsPaused, )] pub target_chain_map: Account<'info, TargetChainMap>, pub system_program: Program<'info, System>, @@ -268,12 +273,6 @@ impl<'info> TransferNativeWithPayload<'info> { )?; Ok(()) } - - pub fn increment_nonce(&mut self) -> Result<()> { - let propeller = &mut self.propeller; - propeller.nonce = propeller.nonce.wrapping_add(1); - Ok(()) - } } #[derive(AnchorDeserialize, AnchorSerialize, Default)] @@ -289,6 +288,7 @@ pub struct TransferWithPayloadData { pub fn handle_cross_chain_transfer_native_with_payload( ctx: Context, + nonce: u32, amount: u64, target_chain: u16, owner: Vec, @@ -314,43 +314,11 @@ pub fn handle_cross_chain_transfer_native_with_payload( let swim_payload = SwimPayload { swim_payload_version: CURRENT_SWIM_PAYLOAD_VERSION, owner: owner_addr, ..Default::default() }; - // let swim_payload = RawSwimPayload { - // //TODO: this should come from the propeller or global constant? - // swim_payload_version: CURRENT_SWIM_PAYLOAD_VERSION, - // owner: owner_addr, - // propeller_enabled, - // gas_kickstart, - // max_fee, - // target_token_id, - // // min_output_amount: U256::from(0u64), - // memo: memo.clone().try_into().unwrap(), - // }; msg!("transfer_native_with_payload swim_payload: {:?}", swim_payload); - // let mut swim_payload_bytes = [0u8; 32]; - // let swim_payload_bytes = swim_payload.try_to_vec()?; - // anchor_lang::prelude::msg!("swim_payload_bytes {:?}", swim_payload_bytes); - // - // Note: - // 1. nonce is created randomly client side using this - // export function createNonce() { - // const nonceConst = Math.random() * 100000; - // const nonceBuffer = Buffer.alloc(4); - // nonceBuffer.writeUInt32LE(nonceConst, 0); - // return nonceBuffer; - // } - // 2. fee is relayerFee - // a. removed in payload3 - // 3. targetAddress is Uint8Array (on wasm.rs its Vec - // a. WH client has special handling/formatting for this - // see - wh-sdk/src/utils/array.ts tryNativeToUint8Array(address: string, chain: ChainId | ChainName) - // 4. targetChain is number/u16 - // 5. payload is Vec - // ok let target_address = ctx.accounts.target_chain_map.target_address.clone(); let transfer_with_payload_data = TransferWithPayloadData { - //TODO: update this. - nonce: ctx.accounts.propeller.nonce, + nonce, amount, target_address, target_chain, @@ -369,12 +337,12 @@ pub fn handle_cross_chain_transfer_native_with_payload( }, ))?; msg!("Revoked authority_signer approval"); - ctx.accounts.increment_nonce()?; Ok(()) } pub fn handle_propeller_transfer_native_with_payload( ctx: Context, + nonce: u32, amount: u64, target_chain: u16, owner: Vec, @@ -398,8 +366,6 @@ pub fn handle_propeller_transfer_native_with_payload( amount, )?; msg!("finished approve for authority_signer"); - // let mut target_token_addr = [0u8; 32]; - // target_token_addr.copy_from_slice(target_token.as_slice()); let mut owner_addr = [0u8; 32]; owner_addr.copy_from_slice(owner.as_slice()); @@ -416,7 +382,7 @@ pub fn handle_propeller_transfer_native_with_payload( let target_address = ctx.accounts.target_chain_map.target_address.clone(); let transfer_with_payload_data = TransferWithPayloadData { - nonce: ctx.accounts.propeller.nonce, + nonce, amount, target_address, target_chain, @@ -436,41 +402,5 @@ pub fn handle_propeller_transfer_native_with_payload( }, ))?; msg!("Revoked authority_signer approval"); - ctx.accounts.increment_nonce()?; Ok(()) } - -#[derive(PartialEq, Debug, Clone, AnchorDeserialize, Default)] -pub struct SwimPayload { - //TOOD: should this come from propeller? - //required - pub swim_payload_version: u8, - pub owner: [u8; 32], - // required for all propellerEngines - pub propeller_enabled: Option, - pub gas_kickstart: Option, - pub max_fee: Option, - pub target_token_id: Option, - // required for SWIM propellerEngine - pub memo: Option<[u8; 16]>, -} - -impl AnchorSerialize for SwimPayload { - fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - // Payload ID - // writer.write_u8(self.swim_payload_version)?; - writer.write_u8(self.swim_payload_version)?; - writer.write_all(&self.owner)?; - - if self.propeller_enabled.is_some() { - writer.write_u8(1)?; - writer.write_u8(self.gas_kickstart.unwrap() as u8)?; - writer.write_u64::(self.max_fee.unwrap())?; - writer.write_u16::(self.target_token_id.unwrap())?; - if self.memo.is_some() { - writer.write_all(&self.memo.unwrap())?; - } - } - Ok(()) - } -} diff --git a/packages/solana-contracts/programs/propeller/src/lib.rs b/packages/solana-contracts/programs/propeller/src/lib.rs index 7c2c6c9e8..29e0959bf 100644 --- a/packages/solana-contracts/programs/propeller/src/lib.rs +++ b/packages/solana-contracts/programs/propeller/src/lib.rs @@ -1,31 +1,15 @@ -use anchor_lang::solana_program::{ - borsh::try_from_slice_unchecked, - instruction::Instruction, - program::{get_return_data, invoke, invoke_signed}, - program_option::COption, - system_instruction::transfer, - sysvar::SysvarId, // sysvar::Sysvar::to_account_info, -}; use { crate::two_pool_cpi::{ - add::*, remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_input::*, - swap_exact_output::*, + add::*, + swap_exact_input::*, + // remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_output::*, }, anchor_lang::{prelude::*, solana_program}, // crate::two_pool_cpi::*, - anchor_spl::{ - associated_token::{get_associated_token_address, AssociatedToken}, - token::{Mint, Token, TokenAccount}, - *, - }, constants::TOKEN_COUNT, fees::*, - // error::PropellerError, - // instructions::*, - solana_program::clock::Epoch, state::*, token_bridge::*, - two_pool::instructions::AddParams, wormhole::*, }; @@ -52,27 +36,60 @@ pub mod propeller { handle_initialize(ctx, params) } + pub fn set_paused(ctx: Context, paused: bool) -> Result<()> { + handle_set_paused(ctx, paused) + } + + pub fn change_pause_key(ctx: Context) -> Result<()> { + handle_change_pause_key(ctx) + } + + pub fn prepare_governance_transition(ctx: Context) -> Result<()> { + Ok(()) + } + + pub fn enact_governance_transition(ctx: Context) -> Result<()> { + Ok(()) + } + #[inline(never)] #[access_control( - CreateTokenIdMap::accounts( + CreateTokenNumberMap::accounts( &ctx, - target_token_index, + to_token_number, pool, pool_token_index, pool_token_mint, - pool_ix, + to_token_step, ))] - pub fn create_token_id_map( - ctx: Context, - target_token_index: u16, + pub fn create_token_number_map( + ctx: Context, + to_token_number: u16, pool: Pubkey, pool_token_index: u8, pool_token_mint: Pubkey, - pool_ix: PoolInstruction, + to_token_step: ToTokenStep, + ) -> Result<()> { + handle_create_token_number_map(ctx, to_token_number, pool, pool_token_index, pool_token_mint, to_token_step) + } + + #[inline(never)] + #[access_control(UpdateTokenNumberMap::accounts(&ctx, &pool_token_index, &pool_token_mint, &to_token_step))] + pub fn update_token_number_map( + ctx: Context, + to_token_number: u16, + pool_token_index: u8, + pool_token_mint: Pubkey, + to_token_step: ToTokenStep, ) -> Result<()> { - handle_create_token_id_map(ctx, target_token_index, pool, pool_token_index, pool_token_mint, pool_ix) + handle_update_token_number_map(ctx, to_token_number, pool_token_index, pool_token_mint, to_token_step) } + pub fn close_token_number_map(ctx: Context, to_token_number: u16) -> Result<()> { + handle_close_token_number_map(ctx, to_token_number) + } + + /** Target Chain Map **/ pub fn create_target_chain_map( ctx: Context, target_chain: u16, @@ -81,10 +98,15 @@ pub mod propeller { handle_create_target_chain_map(ctx, target_chain, target_address) } + //TODO: pass in `target_chain` as input parameter for these? pub fn update_target_chain_map(ctx: Context, routing_contract: [u8; 32]) -> Result<()> { handle_update_target_chain_map(ctx, routing_contract) } + pub fn target_chain_map_set_paused(ctx: Context, is_paused: bool) -> Result<()> { + handle_target_chain_map_set_paused(ctx, is_paused) + } + #[inline(never)] pub fn initialize_fee_tracker(ctx: Context) -> Result<()> { handle_initialize_fee_tracker(ctx) @@ -280,21 +302,22 @@ pub mod propeller { #[access_control(TransferNativeWithPayload::accounts(&ctx))] pub fn cross_chain_transfer_native_with_payload( ctx: Context, + nonce: u32, amount: u64, target_chain: u16, owner: Vec, ) -> Result<()> { - handle_cross_chain_transfer_native_with_payload(ctx, amount, target_chain, owner) + handle_cross_chain_transfer_native_with_payload(ctx, nonce, amount, target_chain, owner) } #[inline(never)] #[access_control(TransferNativeWithPayload::accounts(&ctx))] pub fn propeller_transfer_native_with_payload( ctx: Context, + nonce: u32, amount: u64, target_chain: u16, owner: Vec, - // propeller_enabled: bool, gas_kickstart: bool, max_fee: u64, target_token_id: u16, @@ -302,6 +325,7 @@ pub mod propeller { ) -> Result<()> { handle_propeller_transfer_native_with_payload( ctx, + nonce, amount, target_chain, owner, @@ -322,10 +346,10 @@ pub mod propeller { #[access_control(ProcessSwimPayload::accounts(&ctx))] pub fn process_swim_payload( ctx: Context, - target_token_id: u16, + to_token_number: u16, min_output_amount: u64, ) -> Result { - handle_process_swim_payload(ctx, target_token_id, min_output_amount) + handle_process_swim_payload(ctx, to_token_number, min_output_amount) } #[inline(never)] @@ -344,12 +368,12 @@ pub mod propeller { /// Note: passing in target_token_id here due to PDA seed derivation. /// for propeller_process_swim_payload, require_eq!(target_token_id, propeller_message.target_token_id); #[inline(never)] - #[access_control(PropellerProcessSwimPayload::accounts(&ctx, target_token_id))] + #[access_control(PropellerProcessSwimPayload::accounts(&ctx, to_token_number))] pub fn propeller_process_swim_payload( ctx: Context, - target_token_id: u16, + to_token_number: u16, ) -> Result { - handle_propeller_process_swim_payload(ctx, target_token_id) + handle_propeller_process_swim_payload(ctx, to_token_number) } /// This ix is used if a propeller engine detects (off-chain) that the target_token_id is not valid diff --git a/packages/solana-contracts/programs/propeller/src/state/propeller.rs b/packages/solana-contracts/programs/propeller/src/state/propeller.rs index eb472eeb7..d01751ca6 100644 --- a/packages/solana-contracts/programs/propeller/src/state/propeller.rs +++ b/packages/solana-contracts/programs/propeller/src/state/propeller.rs @@ -16,11 +16,12 @@ use { #[account] pub struct Propeller { pub bump: u8, - pub nonce: u32, - pub admin: Pubkey, //32 - pub wormhole: Pubkey, //32 - pub token_bridge: Pubkey, //32 - pub swim_usd_mint: Pubkey, //32 + pub is_paused: bool, // 1 + pub governance_key: Pubkey, //32 + pub prepared_governance_key: Pubkey, // 32 + pub governance_transition_ts: i64, // 8 + pub pause_key: Pubkey, //32 + pub swim_usd_mint: Pubkey, //32 pub sender_bump: u8, pub redeemer_bump: u8, @@ -35,13 +36,6 @@ pub struct Propeller { pub init_ata_fee: u64, pub complete_with_payload_fee: u64, pub process_swim_payload_fee: u64, - // minimum amount of tokens that must be transferred in token bridge transfer - // if propeller enabled transfer. - // Note: No longer using min transfer amounts - // client will set `max_fee` for propellerEnabled transfers and engine will - // be responsible for checking if the fee is sufficient for it to relay the transfer - // pub propeller_min_transfer_amount: u64, - // pub propeller_eth_min_transfer_amount: u64, // gas kickstart parameters // 1. marginal_price_pool will be pool used to calculate token_bridge_mint -> stablecoin @@ -58,9 +52,10 @@ pub struct Propeller { pub fee_vault: Pubkey, //32 pub aggregator: Pubkey, //32 - pub max_staleness: i64, - //TODO: add this? - // pub fallback_oracle: Pubkey, //32 + pub max_staleness: i64, //8 + + //TODO: add this? + // pub fallback_oracle: Pubkey, //32 } // better to save pda keys on chain and always calculate/derive client side? // - if save pubkeys and don't use #[account(seeds=[...])] then need to manually call or save @@ -68,16 +63,17 @@ pub struct Propeller { // or save pda bumps impl Propeller { pub const LEN: usize = 1 + //bump - 4 + //nonce - 32 + //admin - 32 + //wormhole - 32 + //token_bridge + 1 + //is_paused + 32 + //governance_key + 32 + //prepared_governance_key + 8 + //governance_transition_ts + 32 + //pause_key 32 + //swim_usd_mint + 1 + //sender_bump + 1 + //redeemer_bump 32 + //marginal_price_pool 32 + //marginal_price_token_mint 1 + //marginal_price_pool_token_index - 1 + //sender_bump - 1 + //redeemer_bump 8 + //gas_kickstart_amount 8 + //propeller_fee 8 + // secp_verify_init_fee @@ -158,155 +154,39 @@ impl SwimPayloadMessage { 8 + // vaa_sequence 8 + // transfer_amount // swim_payload - RawSwimPayload::LEN; // swim_payload - // 1 + //version - // 32 + //owner - // 1 + // propeller_enabled - // 1 + // gas_kickstart - // 8 + // max_fee - // 2 + // target_token_id - // 16; // memo - // SwimPayload::LEN; // swim_payload -} - -//TODO: look into options for versioning. -// ex - metaplex metadata versioning - (probably not. its messy). -#[derive(PartialEq, Debug, Clone, Default)] -pub struct RawSwimPayload { - /* always required fields */ - pub swim_payload_version: u8, - pub owner: Address, - /* required for all propellerEnabled */ - pub propeller_enabled: bool, - pub gas_kickstart: bool, - pub max_fee: u64, - pub target_token_id: u16, - /* required for swim propeller */ - pub memo: [u8; 16], -} - -impl RawSwimPayload { - pub const LEN: usize = 1 + //version + 1 + //version 32 + //owner 1 + // propeller_enabled 1 + // gas_kickstart 8 + // max_fee 2 + // target_token_id 16; // memo -} -#[repr(u8)] -#[derive(PartialEq, Debug, Clone)] -pub enum SwimPayloadVersion { - V0 = 0, - V1 = 1, -} - -impl AnchorDeserialize for RawSwimPayload { - fn deserialize(buf: &mut &[u8]) -> std::io::Result { - let mut v = Cursor::new(buf); - - //TODO: add some error handling/checking here if payload version is incorrect. - // https://stackoverflow.com/questions/28028854/how-do-i-match-enum-values-with-an-integer - let swim_payload_version = v.read_u8()?; - // if swim_payload_version == 1 { - // deseraialize_swim_payload_v1() - // } - if swim_payload_version != CURRENT_SWIM_PAYLOAD_VERSION { - return Err(std::io::Error::new(ErrorKind::InvalidInput, "Wrong Swim Payload Version".to_string())); - } - - let mut owner: [u8; 32] = Address::default(); - v.read_exact(&mut owner)?; - - /* optional fields */ - match v.read_u8() { - Ok(propeller_enabled_val) => { - let propeller_enabled = !(propeller_enabled_val == 0); - let gas_kickstart = !(v.read_u8()? == 0); - let max_fee = v.read_u64::()?; - let target_token_id = v.read_u16::()?; - // optional memo field - let mut memo: [u8; 16] = [0; 16]; - if let Ok(_) = v.read_exact(&mut memo) { - Ok(RawSwimPayload { - swim_payload_version, - owner, - propeller_enabled, - gas_kickstart, - max_fee, - target_token_id, - memo, - }) - } else { - Ok(RawSwimPayload { - swim_payload_version, - owner, - propeller_enabled, - gas_kickstart, - max_fee, - target_token_id, - memo: [0; 16], - }) - } - } - Err(error) => match error.kind() { - ErrorKind::UnexpectedEof => Ok(RawSwimPayload { swim_payload_version, owner, ..Default::default() }), - _ => return Err(error), - }, - } - } -} - -impl AnchorSerialize for RawSwimPayload { - fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - // Payload ID - // writer.write_u8(self.swim_payload_version)?; - writer.write_u8(CURRENT_SWIM_PAYLOAD_VERSION)?; - - writer.write_all(&self.owner)?; - writer.write_u8(if self.propeller_enabled { 1 } else { 0 })?; - writer.write_u8(if self.gas_kickstart { 1 } else { 0 })?; - writer.write_u64::(self.max_fee)?; - writer.write_u16::(self.target_token_id)?; - writer.write_all(&self.memo)?; - Ok(()) - } + // RawSwimPayload::LEN; // swim_payload + // 1 + //version + // 32 + //owner + // 1 + // propeller_enabled + // 1 + // gas_kickstart + // 8 + // max_fee + // 2 + // target_token_id + // 16; // memo + // SwimPayload::LEN; // swim_payload } +/// Utility function that verifies: +/// 1. pool_token_index < TOKEN_COUNT +/// 2. marginal_price_pool_token_accounts[pool_token_index].mint = propeller.marginal_price_pool_token_mint +/// 3. marginal_price_pool.token_mint_keys[pool_token_index] = propeller.marginal_price_pool_token_mint pub fn validate_marginal_prices_pool_accounts<'info>( - propeller: &Propeller, - marginal_price_pool_key: &Pubkey, - marginal_price_pool_token_account_mints: &[Pubkey; TOKEN_COUNT], -) -> Result<()> { - 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.mint, propeller.marginal_price_pool_token_mint); + require_keys_eq!(marginal_price_pool.token_mint_keys[pool_token_index], propeller.marginal_price_pool_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/propeller/src/token_bridge.rs b/packages/solana-contracts/programs/propeller/src/token_bridge.rs index 0cb7a79fc..3f54698ea 100644 --- a/packages/solana-contracts/programs/propeller/src/token_bridge.rs +++ b/packages/solana-contracts/programs/propeller/src/token_bridge.rs @@ -1,8 +1,22 @@ use { - anchor_lang::{prelude::*, solana_program::pubkey}, + anchor_lang::{ + prelude::*, + solana_program::{declare_id, pubkey}, + }, borsh::{BorshDeserialize, BorshSerialize}, }; - +// mod token_bridge { +// use super::*; +// #[cfg(all(feature = "localnet", not(feature = "devnet"), not(feature = "mainnet")))] +// declare_id!("B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE"); +// +// // #[cfg(feature = "devnet")] +// #[cfg(all(feature = "devnet", not(feature = "localnet"), not(feature = "mainnet")))] +// declare_id!("DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe"); +// +// #[cfg(all(feature = "mainnet", not(feature = "localnet"), not(feature = "devnet")))] +// declare_id!("wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb"); +// } #[derive(Debug, Clone)] pub struct TokenBridge; @@ -11,6 +25,7 @@ impl anchor_lang::Id for TokenBridge { // #[cfg(feature = "localnet")] #[cfg(all(feature = "localnet", not(feature = "devnet"), not(feature = "mainnet")))] fn id() -> Pubkey { + // declare_id!("B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE") pubkey!("B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE") } @@ -18,11 +33,13 @@ impl anchor_lang::Id for TokenBridge { #[cfg(all(feature = "devnet", not(feature = "localnet"), not(feature = "mainnet")))] fn id() -> Pubkey { + // declare_id!("DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe") pubkey!("DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe") } #[cfg(all(feature = "mainnet", not(feature = "localnet"), not(feature = "devnet")))] fn id() -> Pubkey { + // declare_id!("wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb") pubkey!("wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb") } } diff --git a/packages/solana-contracts/programs/propeller/src/wormhole.rs b/packages/solana-contracts/programs/propeller/src/wormhole.rs index 3d17a44b7..6a31f6bd0 100644 --- a/packages/solana-contracts/programs/propeller/src/wormhole.rs +++ b/packages/solana-contracts/programs/propeller/src/wormhole.rs @@ -1,5 +1,5 @@ use { - crate::{Propeller, PropellerError, RawSwimPayload}, + crate::{constants::CURRENT_SWIM_PAYLOAD_VERSION, Propeller, PropellerError}, anchor_lang::{prelude::*, solana_program::pubkey}, borsh::{BorshDeserialize, BorshSerialize}, byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, @@ -94,13 +94,48 @@ pub struct BridgeConfig { /// [From womrhole repo] #[repr(transparent)] -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct PostedMessageData { pub message: MessageData, } +impl AnchorSerialize for PostedMessageData { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write(b"msg")?; + BorshSerialize::serialize(&self.message, writer) + } +} + +impl AnchorDeserialize for PostedMessageData { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + *buf = &buf[3..]; + Ok(PostedMessageData { message: ::deserialize(buf)? }) + } +} +impl anchor_lang::Owner for PostedMessageData { + fn owner() -> Pubkey { + Wormhole::id() + } +} + +impl anchor_lang::AccountDeserialize for PostedMessageData { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result { + *buf = &buf[3..]; + Ok(::deserialize(buf)?) + } +} +impl anchor_lang::AccountSerialize for PostedMessageData {} + +impl Deref for PostedMessageData { + type Target = PostedMessageData; + + fn deref(&self) -> &Self { + &self + } +} + // #[derive(Debug, Default, BorshDeserialize, BorshSerialize)] -#[derive(Debug, AnchorDeserialize, AnchorSerialize, Clone)] +#[derive(Debug, AnchorDeserialize, AnchorSerialize, Clone, PartialEq)] pub struct MessageData { /// Header of the posted VAA pub vaa_version: u8, @@ -155,6 +190,101 @@ impl anchor_lang::Owner for MessageData { impl anchor_lang::AccountSerialize for MessageData {} +// #[derive(PartialEq, Debug, Clone)] +// pub struct PayloadTransferWithPayload { +// pub message_type: u8, +// /// Amount being transferred (big-endian uint256) +// pub amount: U256, +// +// //TODO: safe to assume pubkey for these since this should only be used for +// // completeTransferWithPayload(e.g. solana side)? +// /// Address of the token. Left-zero-padded if shorter than 32 bytes +// pub token_address: Address, +// /// Chain ID of the token +// pub token_chain: ChainID, +// /// Address of the recipient. Left-zero-padded if shorter than 32 bytes +// pub to: Address, +// /// Chain ID of the recipient +// pub to_chain: ChainID, +// +// /// TODO: only this one needs to be `Address` since it should come from the evm contract/user +// /// Sender of the transaction +// pub from_address: Address, +// /// Arbitrary payload +// // pub payload: Vec, +// // pub payload: RawSwimPayload, +// } +// +// impl AnchorDeserialize for PayloadTransferWithPayload { +// fn deserialize(buf: &mut &[u8]) -> std::io::Result { +// let mut v = Cursor::new(buf); +// let message_type = v.read_u8()?; +// if message_type != 3 { +// // return Err(error!(PropellerError::InvalidPayloadTypeInVaa)).into() +// // return Err(ProgramError::BorshIoError("Wrong Payload Type".to_string()).into()); +// return Err(std::io::Error::new(ErrorKind::InvalidInput, "Wrong Payload Type".to_string())); +// // return Err(PropellerError::InvalidPayloadTypeInVaa); +// }; +// +// let mut am_data: [u8; 32] = [0; 32]; +// v.read_exact(&mut am_data)?; +// let amount = U256::from_big_endian(&am_data); +// +// let mut token_address = Address::default(); +// v.read_exact(&mut token_address)?; +// +// let token_chain = v.read_u16::()?; +// +// let mut to = Address::default(); +// v.read_exact(&mut to)?; +// +// let to_chain = v.read_u16::()?; +// +// let mut from_address = Address::default(); +// v.read_exact(&mut from_address)?; +// +// let mut payload = vec![]; +// v.read_to_end(&mut payload)?; +// let swim_payload = RawSwimPayload::deserialize(&mut payload.as_slice())?; +// +// Ok(PayloadTransferWithPayload { +// message_type, +// amount, +// token_address, +// token_chain, +// to, +// to_chain, +// from_address, +// payload: swim_payload, +// }) +// } +// } +// +// //TODO: probably not needed since we shouldn't be serializing any payload directly. +// // this would be handled in CPI +// impl AnchorSerialize for PayloadTransferWithPayload { +// fn serialize(&self, writer: &mut W) -> std::io::Result<()> { +// // Payload ID +// writer.write_u8(3)?; +// +// let mut am_data: [u8; 32] = [0; 32]; +// self.amount.to_big_endian(&mut am_data); +// writer.write_all(&am_data)?; +// +// writer.write_all(&self.token_address)?; +// writer.write_u16::(self.token_chain)?; +// writer.write_all(&self.to)?; +// writer.write_u16::(self.to_chain)?; +// +// writer.write_all(&self.from_address)?; +// +// AnchorSerialize::serialize(&self.payload, writer)?; +// // writer.write_all(self.payload.as_slice())?; +// +// Ok(()) +// } +// } + #[derive(PartialEq, Debug, Clone)] pub struct PayloadTransferWithPayload { pub message_type: u8, @@ -177,7 +307,8 @@ pub struct PayloadTransferWithPayload { pub from_address: Address, /// Arbitrary payload // pub payload: Vec, - pub payload: RawSwimPayload, + // pub payload: RawSwimPayload, + pub payload: SwimPayload, } impl AnchorDeserialize for PayloadTransferWithPayload { @@ -210,7 +341,7 @@ impl AnchorDeserialize for PayloadTransferWithPayload { let mut payload = vec![]; v.read_to_end(&mut payload)?; - let swim_payload = RawSwimPayload::deserialize(&mut payload.as_slice())?; + let swim_payload = SwimPayload::deserialize(&mut payload.as_slice())?; Ok(PayloadTransferWithPayload { message_type, @@ -243,27 +374,14 @@ impl AnchorSerialize for PayloadTransferWithPayload { writer.write_all(&self.from_address)?; - AnchorSerialize::serialize(&self.payload, writer)?; + self.payload.serialize(writer)?; + // AnchorSerialize::serialize(&self.payload, writer)?; // writer.write_all(self.payload.as_slice())?; Ok(()) } } -impl AnchorSerialize for PostedMessageData { - fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - writer.write(b"msg")?; - BorshSerialize::serialize(&self.message, writer) - } -} - -impl AnchorDeserialize for PostedMessageData { - fn deserialize(buf: &mut &[u8]) -> std::io::Result { - *buf = &buf[3..]; - Ok(PostedMessageData { message: ::deserialize(buf)? }) - } -} - pub fn get_message_data(vaa_account: &AccountInfo) -> Result { Ok(PostedMessageData::try_from_slice(&vaa_account.data.borrow())?.message) } @@ -278,9 +396,6 @@ pub fn deserialize_message_payload(buf: &mut &[u8]) -> Res Ok(T::deserialize(buf)?) } -pub fn deserialize_swim_payload(buf: &mut &[u8]) -> Result { - Ok(RawSwimPayload::deserialize(buf)?) -} /** Adding PostedVAA version here for parity */ #[repr(transparent)] @@ -411,3 +526,91 @@ pub fn hash_vaa(vaa: &PostVAAData) -> [u8; 32] { h.write_all(body.as_slice()).unwrap(); h.finalize().into() } + +#[derive(PartialEq, Debug, Clone, Default)] +pub struct SwimPayload { + //TOOD: should this come from propeller? + //required + pub swim_payload_version: u8, + pub owner: [u8; 32], + // required for all propellerEngines + pub propeller_enabled: Option, + pub gas_kickstart: Option, + pub max_fee: Option, + pub target_token_id: Option, + // required for SWIM propellerEngine + pub memo: Option<[u8; 16]>, +} + +impl AnchorSerialize for SwimPayload { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + // Payload ID + // writer.write_u8(self.swim_payload_version)?; + writer.write_u8(self.swim_payload_version)?; + writer.write_all(&self.owner)?; + + if self.propeller_enabled.is_some() { + writer.write_u8(1)?; + writer.write_u8(self.gas_kickstart.unwrap() as u8)?; + writer.write_u64::(self.max_fee.unwrap())?; + writer.write_u16::(self.target_token_id.unwrap())?; + if self.memo.is_some() { + writer.write_all(&self.memo.unwrap())?; + } + } + Ok(()) + } +} + +impl AnchorDeserialize for SwimPayload { + fn deserialize(buf: &mut &[u8]) -> std::io::Result { + let mut v = Cursor::new(buf); + + //TODO: add some error handling/checking here if payload version is incorrect. + // https://stackoverflow.com/questions/28028854/how-do-i-match-enum-values-with-an-integer + let swim_payload_version = v.read_u8()?; + if swim_payload_version != CURRENT_SWIM_PAYLOAD_VERSION { + return Err(std::io::Error::new(ErrorKind::InvalidInput, "Wrong Swim Payload Version".to_string())); + } + + let mut owner: [u8; 32] = Address::default(); + v.read_exact(&mut owner)?; + + /* optional fields */ + match v.read_u8() { + Ok(propeller_enabled_val) => { + let propeller_enabled = !(propeller_enabled_val == 0); + let gas_kickstart = !(v.read_u8()? == 0); + let max_fee = v.read_u64::()?; + let target_token_id = v.read_u16::()?; + // optional memo field + let mut memo: [u8; 16] = [0; 16]; + if let Ok(_) = v.read_exact(&mut memo) { + Ok(SwimPayload { + swim_payload_version, + owner, + propeller_enabled: Some(propeller_enabled), + gas_kickstart: Some(gas_kickstart), + max_fee: Some(max_fee), + target_token_id: Some(target_token_id), + memo: Some(memo), + }) + } else { + Ok(SwimPayload { + swim_payload_version, + owner, + propeller_enabled: Some(propeller_enabled), + gas_kickstart: Some(gas_kickstart), + max_fee: Some(max_fee), + target_token_id: Some(target_token_id), + memo: None, + }) + } + } + Err(error) => match error.kind() { + ErrorKind::UnexpectedEof => Ok(SwimPayload { swim_payload_version, owner, ..Default::default() }), + _ => return Err(error), + }, + } + } +} 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 dba350348..1ec0e709c 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -1,10 +1,7 @@ use { crate::{common, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, anchor_lang::prelude::*, - anchor_spl::{ - associated_token::get_associated_token_address, - token::{self, Mint, Token, TokenAccount}, - }, + anchor_spl::token::{self, Mint, Token, TokenAccount}, std::iter::zip, }; @@ -21,9 +18,6 @@ pub struct Add<'info> { bump = pool.bump, )] pub pool: Box>, - // /// TODO: could be removed if initialized with pool_v2 - // /// CHECK: checked in CPI - // pub pool_auth: UncheckedAccount<'info>, #[account( mut, address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, @@ -45,7 +39,6 @@ pub struct Add<'info> { address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, )] pub governance_fee: Box>, - ///CHECK: checked in CPI pub user_transfer_authority: Signer<'info>, #[account( mut, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs index 7fba51476..7fa2500ce 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs @@ -9,8 +9,8 @@ pub struct CommonGovernance<'info> { mut, seeds = [ b"two_pool".as_ref(), - pool.get_token_mint_0().unwrap().as_ref(), - pool.get_token_mint_1().unwrap().as_ref(), + pool.get_token_mint_0().as_ref(), + pool.get_token_mint_1().as_ref(), pool.lp_mint_key.as_ref(), ], bump = pool.bump diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs index 2954883ad..b25a53dcf 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs @@ -1,8 +1,5 @@ use { - crate::{ - error::*, - TwoPool, - }, + crate::{error::*, TwoPool}, anchor_lang::prelude::*, }; @@ -12,8 +9,8 @@ pub struct SetPaused<'info> { mut, seeds = [ b"two_pool".as_ref(), - pool.get_token_mint_0().unwrap().as_ref(), - pool.get_token_mint_1().unwrap().as_ref(), + pool.get_token_mint_0().as_ref(), + pool.get_token_mint_1().as_ref(), pool.lp_mint_key.as_ref(), ], bump = pool.bump diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs index 92e18a700..88b564592 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs @@ -148,28 +148,5 @@ pub fn handle_initialize( two_pool.prepared_governance_fee = PoolFee::default(); two_pool.fee_transition_ts = 0; two_pool.previous_depth = 0; - - /** - &PoolState { - nonce, - is_paused: false, - amp_factor: AmpFactor::new(amp_factor)?, - lp_fee: PoolFee::new(lp_fee)?, - governance_fee: PoolFee::new(governance_fee)?, - lp_mint_key: lp_mint_account.key.clone(), - lp_decimal_equalizer: decimal_range_max - lp_mint_state.decimals, - token_mint_keys: create_array(|i| token_mint_accounts[i].key.clone()), - token_decimal_equalizers: create_array(|i| decimal_range_max - token_decimals[i]), - token_keys: create_array(|i| token_accounts[i].key.clone()), - governance_key: governance_account.key.clone(), - governance_fee_key: governance_fee_account.key.clone(), - prepared_governance_key: Pubkey::default(), - governance_transition_ts: 0, - prepared_lp_fee: PoolFee::default(), - prepared_governance_fee: PoolFee::default(), - fee_transition_ts: 0, - previous_depth: 0, - }, - */ Ok(()) } diff --git a/packages/solana-contracts/programs/two-pool/src/state.rs b/packages/solana-contracts/programs/two-pool/src/state.rs index 771200e38..ac07efb97 100644 --- a/packages/solana-contracts/programs/two-pool/src/state.rs +++ b/packages/solana-contracts/programs/two-pool/src/state.rs @@ -1,6 +1,6 @@ use { crate::{amp_factor::AmpFactor, pool_fee::PoolFee, TOKEN_COUNT}, - anchor_lang::{prelude::*}, + anchor_lang::prelude::*, }; // use pool_lib::amp_factor::AmpFactor; @@ -45,54 +45,42 @@ impl TwoPool { // self.lp_mint_key != Pubkey::default() // } - pub const LEN: usize = - // nonce - 1 + - // is_paused - 1 + - // amp_factor - AmpFactor::LEN + - // lp_fee - PoolFee::LEN + - // governance_fee - PoolFee::LEN + - // lp_mint_key - 32 + - // lp_decimal_equalizer - 1 + - // token_mint_keys - 32 * TOKEN_COUNT + - // token_decimal_equalizers - TOKEN_COUNT + - // token_keys - 32 * TOKEN_COUNT + - // pause_key - 32 + - // governance_key - 32 + - // governance_fee_key - 32 + - // prepared_governance_key - 32 + - // governance_transition_ts - 8 + - // prepared_lp_fee - PoolFee::LEN + - // prepared_governance_fee - PoolFee::LEN + - // fee_transition_ts - 8 + - // previous_depth - 16; + pub const LEN: usize = 1 + // nonce + 1 + // is_paused + AmpFactor::LEN + // amp_factor + PoolFee::LEN + // lp_fee + PoolFee::LEN + // governance_fee + 32 + // lp_mint_key + 1 + // lp_decimal_equalizer + (32 * TOKEN_COUNT) + // token_mint_keys + TOKEN_COUNT + // token_decimal_equalizers + (32 * TOKEN_COUNT) + // token_keys + 32 + // pause_key + 32 + // governance_key + 32 + // governance_fee_key + 32 + // prepared_governance_key + 8 + // governance_transition_ts + PoolFee::LEN + // prepared_lp_fee + PoolFee::LEN + // prepared_governance_fee + 8 + // fee_transition_ts + 16; // previous_depth // Note: this is a workaround for to be able to declare the seeds in the // governance ix. anchor does not handle using `pool.token_mint_keys[0]` directly // in the #[account] macro - pub fn get_token_mint_0(&self) -> Result { - Ok(self.token_mint_keys[0]) + pub fn get_token_mint_0(&self) -> Pubkey { + self.token_mint_keys[0] } - pub fn get_token_mint_1(&self) -> Result { - Ok(self.token_mint_keys[1]) + pub fn get_token_mint_1(&self) -> Pubkey { + self.token_mint_keys[1] + } + + pub fn new_get_token_mint_0(&self) -> Pubkey { + self.token_mint_keys[0] + } + + pub fn new_get_token_mint_1(&self) -> Pubkey { + self.token_mint_keys[1] } } diff --git a/packages/solana-contracts/scripts/initializePropeller.ts b/packages/solana-contracts/scripts/initializePropeller.ts index 04190d7d8..b97e791ab 100644 --- a/packages/solana-contracts/scripts/initializePropeller.ts +++ b/packages/solana-contracts/scripts/initializePropeller.ts @@ -1,9 +1,11 @@ +import crypto from "crypto"; import * as fs from "fs"; import * as path from "path"; import type { ChainId } from "@certusone/wormhole-sdk"; import { CHAIN_ID_ETH, + createNonce, tryHexToNativeString, tryNativeToHexString, } from "@certusone/wormhole-sdk"; @@ -33,13 +35,14 @@ import { TWO_POOL_PID, USDC_TO_TOKEN_NUMBER, USDT_TO_TOKEN_NUMBER, - setComputeUnitLimitIx, maxStaleness, + maxStaleness, + setComputeUnitLimitIx, } from "../src/__tests__/consts"; import { getPropellerPda, getPropellerRedeemerPda, getTargetChainIdMapAddr, - getTargetTokenIdMapAddr, + getToTokenNumberMapAddr, } from "../src/__tests__/propeller/propellerUtils"; // import type { Propeller } from "../src/artifacts/propeller"; @@ -61,7 +64,8 @@ const propellerProgram = new Program( const splToken = Spl.token(provider); const payer = (provider.wallet as NodeWallet).payer; -const propellerAdmin = payer; +const propellerGovernanceKey = payer; +const propellerPauseKey = payer; type InitParameters = { readonly gasKickstartAmount: BN; @@ -160,7 +164,7 @@ async function setupPropeller() { console.info(`swimUsdPoolInfo: ${JSON.stringify(swimUsdPoolInfo)}`); propellerInfo = await initializePropellerState(); console.info(`propellerInfo: ${JSON.stringify(propellerInfo, null, 2)}`); - targetTokenIdMaps = await createTargetTokenIdMaps(); + targetTokenIdMaps = await createTokenNumberMaps(); console.info( `targetTokenIdMaps: ${JSON.stringify( Object.fromEntries(targetTokenIdMaps), @@ -168,7 +172,7 @@ async function setupPropeller() { ); await fetchAndPrintIdMap( targetTokenIdMaps, - async (addr) => await propellerProgram.account.tokenIdMap.fetch(addr), + async (addr) => await propellerProgram.account.tokenNumberMap.fetch(addr), // propellerProgram.account.tokenIdMap.fetch, "targetTokenId", ); @@ -285,9 +289,9 @@ async function initializePropellerState(): Promise { propellerFeeVault: ${propellerFeeVault.toString()} propellerRedeemer: ${propellerRedeemer.toString()} propellerRedeemerEscrow: ${propellerRedeemerEscrow.toString()} - propellerAdmin: ${propellerAdmin.publicKey.toString()} + propellerGovernanceKey: ${propellerGovernanceKey.publicKey.toString()} + propellerPauseKey: ${propellerPauseKey.publicKey.toString()} payer: ${payer.publicKey.toString()} - `); let propellerData = await propellerProgram.account.propeller.fetchNullable( @@ -301,7 +305,8 @@ async function initializePropellerState(): Promise { propeller: propellerAddr, propellerRedeemerEscrow, propellerFeeVault, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, + pauseKey: propellerGovernanceKey.publicKey, swimUsdMint, payer: payer.publicKey, tokenProgram: TOKEN_PROGRAM_ID, @@ -315,7 +320,7 @@ async function initializePropellerState(): Promise { twoPoolProgram: twoPoolProgram.programId, aggregator, }) - .signers([propellerAdmin, payer]) + .signers([propellerGovernanceKey, payer]) .rpc(); } propellerData = await propellerProgram.account.propeller.fetch(propellerAddr); @@ -330,83 +335,89 @@ async function initializePropellerState(): Promise { }; } -async function createTargetTokenIdMaps(): Promise< +async function createTokenNumberMaps(): Promise< ReadonlyMap > { - const swimUsdTokenIdMap = { + const swimUsdTokenNumberMap = { pool: swimUsdPoolInfo.address, poolTokenIndex: 0, poolTokenMint: swimUsdPoolInfo.lpMint, - poolIx: { transfer: {} }, + toTokenStep: { transfer: {} }, }; - const usdcTokenIdMap = { + const usdcTokenNumberMap = { pool: swimUsdPoolInfo.address, poolTokenIndex: 0, poolTokenMint: swimUsdPoolInfo.tokenMints[0], - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const usdtTokenIdMap = { + const usdtTokenNumberMap = { pool: swimUsdPoolInfo.address, poolTokenIndex: 1, poolTokenMint: swimUsdPoolInfo.tokenMints[1], - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const outputTokenIdMapAddrEntries = await Promise.all( + const tokenNumberMapAddrEntries = await Promise.all( [ { - targetTokenId: SWIM_USD_TO_TOKEN_NUMBER, - tokenIdMap: swimUsdTokenIdMap, + toTokenNumber: SWIM_USD_TO_TOKEN_NUMBER, + tokenNumberMap: swimUsdTokenNumberMap, + }, + { + toTokenNumber: USDC_TO_TOKEN_NUMBER, + tokenNumberMap: usdcTokenNumberMap, + }, + { + toTokenNumber: USDT_TO_TOKEN_NUMBER, + tokenNumberMap: usdtTokenNumberMap, }, - { targetTokenId: USDC_TO_TOKEN_NUMBER, tokenIdMap: usdcTokenIdMap }, - { targetTokenId: USDT_TO_TOKEN_NUMBER, tokenIdMap: usdtTokenIdMap }, - ].map(async ({ targetTokenId, tokenIdMap }) => { - const [tokenIdMapAddr] = await getTargetTokenIdMapAddr( + ].map(async ({ toTokenNumber, tokenNumberMap }) => { + const [toTokenNumberMapAddr] = await getToTokenNumberMapAddr( propellerInfo.address, - targetTokenId, + toTokenNumber, propellerProgram.programId, ); if ( - !(await propellerProgram.account.tokenIdMap.fetchNullable( - tokenIdMapAddr, + !(await propellerProgram.account.tokenNumberMap.fetchNullable( + toTokenNumberMapAddr, )) ) { const createTokenIdMapTxn = propellerProgram.methods - .createTokenIdMap( - targetTokenId, - tokenIdMap.pool, - tokenIdMap.poolTokenIndex, - tokenIdMap.poolTokenMint, - tokenIdMap.poolIx, + .createTokenNumberMap( + toTokenNumber, + tokenNumberMap.pool, + tokenNumberMap.poolTokenIndex, + tokenNumberMap.poolTokenMint, + tokenNumberMap.toTokenStep, ) .accounts({ propeller: propellerInfo.address, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, payer: payer.publicKey, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, - pool: tokenIdMap.pool, + pool: tokenNumberMap.pool, twoPoolProgram: twoPoolProgram.programId, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey]); const pubkeys = await createTokenIdMapTxn.pubkeys(); await createTokenIdMapTxn.rpc(); - const derivedTokenIdMapAddr = pubkeys.tokenIdMap; - if (!derivedTokenIdMapAddr) { + const derivedTokenNumberMapAddr = pubkeys.tokenNumberMap; + if (!derivedTokenNumberMapAddr) { throw new Error("Failed to derive tokenIdMapAddr"); } console.info(` - derivedTokenIdMapAddr: ${derivedTokenIdMapAddr.toString()} - tokenIdMapAddr: ${tokenIdMapAddr.toString()} + derivedTokenIdMapAddr: ${derivedTokenNumberMapAddr.toString()} + toTokenNumberMapAddr: ${toTokenNumberMapAddr.toString()} `); } - return { targetTokenId, tokenIdMapAddr }; + return { toTokenNumber, toTokenNumberMapAddr }; }), ); return new Map( - outputTokenIdMapAddrEntries.map(({ targetTokenId, tokenIdMapAddr }) => { - return [targetTokenId, tokenIdMapAddr]; + tokenNumberMapAddrEntries.map(({ toTokenNumber, toTokenNumberMapAddr }) => { + return [toTokenNumber, toTokenNumberMapAddr]; }), ); } @@ -466,13 +477,13 @@ async function createTargetChainMaps() { .createTargetChainMap(wormholeChainId, targetAddrWormholeFormat) .accounts({ propeller: propellerInfo.address, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, payer: payer.publicKey, targetChainMap: targetChainMapAddr, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, }) - .signers([propellerAdmin]) + .signers([propellerGovernanceKey]) .rpc(); } @@ -546,7 +557,6 @@ async function transferTokens() { payer.publicKey, ); - let memo = 0; // const evmTargetTokenIds = [0, 1]; const evmTargetTokenIds = [0]; const targetChain = CHAIN_ID_ETH; @@ -603,10 +613,7 @@ async function transferTokens() { // crossChainTransferNativeWithPayloadTxnSig: ${crossChainTransferNativeWithPayloadTxnSig}`, // ); - const memoStr = (++memo).toString().padStart(16, "0"); - const memoBuffer2 = Buffer.alloc(16); - memoBuffer2.write(memoStr); - + const memoBuffer = createMemoId(); const propellerEnabledTransferAmount = transferAmount.div(new BN(2)); const propellerEnabledWormholeMessage = web3.Keypair.generate(); @@ -619,21 +626,23 @@ async function transferTokens() { targetChain: ${targetChain}, targetOwner(native): ${evmOwnerNative}, targetOwner(Hex): ${evmOwnerEthHexStr}, - memo(str): ${memoStr}, - memo(buffer): ${memoBuffer2.toString("hex")}, + memo("hex"): ${memoBuffer.toString("hex")}, + ) `); + const nonce = createNonce().readUInt32LE(0); const propellerTransferNativeWithPayloadTxnSig: string = await propellerProgram.methods .propellerTransferNativeWithPayload( + nonce, propellerEnabledTransferAmount, targetChain, evmOwner, gasKickstart, maxFee, evmTargetTokenId, - memoBuffer2, + memoBuffer, ) .accounts({ propeller: propellerInfo.address, @@ -660,7 +669,7 @@ async function transferTokens() { tokenProgram: splToken.programId, }) .preInstructions([setComputeUnitLimitIx]) - .postInstructions([createMemoInstruction(memoStr)]) + .postInstructions([createMemoInstruction(memoBuffer.toString("hex"))]) .signers([payer, propellerEnabledWormholeMessage]) .rpc(); @@ -671,5 +680,12 @@ async function transferTokens() { ); } +function createMemoId() { + const SWIM_MEMO_LENGTH = 16; + // NOTE: Please always use random bytes to avoid conflicts with other users + return crypto.randomBytes(SWIM_MEMO_LENGTH); + // return (++memoId).toString().padStart(16, "0"); +} + void setupPropeller(); // voidloadConfig(); diff --git a/packages/solana-contracts/scripts/parseAccount.ts b/packages/solana-contracts/scripts/parseAccount.ts new file mode 100644 index 000000000..acc96678e --- /dev/null +++ b/packages/solana-contracts/scripts/parseAccount.ts @@ -0,0 +1,44 @@ +import { AnchorProvider, web3 } from "@project-serum/anchor"; + +import { + formatParsedTokenTransferWithSwimPayloadPostedMessage, + parseTokenTransferWithSwimPayloadPostedMessage, +} from "../src/__tests__/propeller/propellerUtils"; + +const envProvider = AnchorProvider.env(); + +async function parseWormholeMessageAccount(address: web3.PublicKey) { + const wormholeMessageAccountInfo = + await envProvider.connection.getAccountInfo(address); + if (!wormholeMessageAccountInfo) { + console.error(`No account found at ${address.toBase58()}`); + return; + } + const parsedTokenTransferWithSwimPayloadPostedMessage = + await parseTokenTransferWithSwimPayloadPostedMessage( + wormholeMessageAccountInfo.data, + ); + console.info(`finished parsing`); + const formattedMessage = + formatParsedTokenTransferWithSwimPayloadPostedMessage( + parsedTokenTransferWithSwimPayloadPostedMessage, + ); + console.info( + `formattedMessage: ${JSON.stringify(formattedMessage, null, 2)}`, + ); +} + +const main = async (): Promise => { + const [address] = process.argv.slice(2); + if (!address) { + console.error("Please provide a wormhole message account address"); + process.exit(1); + } + console.info(`address: ${address}`); + await parseWormholeMessageAccount(new web3.PublicKey(address)); +}; + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/packages/solana-contracts/scripts/scratch.ts b/packages/solana-contracts/scripts/scratch.ts index 9c28a0ff0..37ab10c67 100644 --- a/packages/solana-contracts/scripts/scratch.ts +++ b/packages/solana-contracts/scripts/scratch.ts @@ -31,7 +31,7 @@ import { getPropellerPda, getPropellerRedeemerPda, getTargetChainIdMapAddr, - getTargetTokenIdMapAddr, + getToTokenNumberMapAddr, } from "../src/__tests__/propeller/propellerUtils"; import type { Propeller } from "../src/artifacts/propeller"; import type { TwoPool } from "../src/artifacts/two_pool"; @@ -143,8 +143,8 @@ async function setupPropeller() { // ); // await fetchAndPrintIdMap( // targetTokenIdMaps, - // async (addr) => await propellerProgram.account.tokenIdMap.fetch(addr), - // // propellerProgram.account.tokenIdMap.fetch, + // async (addr) => await propellerProgram.account.tokenNumberMap.fetch(addr), + // // propellerProgram.account.tokenNumberMap.fetch, // "targetTokenId", // ); // @@ -258,7 +258,7 @@ async function initializePropellerState(): Promise { propeller: propellerAddr, propellerRedeemerEscrow, propellerFeeVault, - admin: propellerAdmin.publicKey, + governanceKey: propellerAdmin.publicKey, swimUsdMint, payer: payer.publicKey, tokenProgram: TOKEN_PROGRAM_ID, diff --git a/packages/solana-contracts/src/__tests__/consts.ts b/packages/solana-contracts/src/__tests__/consts.ts index b46cdbe0c..27a3c0391 100644 --- a/packages/solana-contracts/src/__tests__/consts.ts +++ b/packages/solana-contracts/src/__tests__/consts.ts @@ -9,15 +9,15 @@ import { LAMPORTS_PER_SOL } from "@solana/web3.js"; export const commitment = "confirmed" as web3.Commitment; export const rpcCommitmentConfig = { - commitment: "confirmed", + commitment, preflightCommitment: commitment, skipPreflight: true, }; -const ethTokenBridgeStr = "0x0290FB167208Af455bB137780163b7B7a9a10C16"; +export const ethTokenBridgeNativeStr = "0x0290FB167208Af455bB137780163b7B7a9a10C16"; //0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16 const ethTokenBridgeEthHexStr = tryNativeToHexString( - ethTokenBridgeStr, + ethTokenBridgeNativeStr, CHAIN_ID_ETH, ); //ethTokenBridge.toString() = gibberish @@ -52,9 +52,9 @@ export const routingContracts = [ { targetChainId: CHAIN_ID_ETH, address: ethRoutingContract }, { targetChainId: CHAIN_ID_BSC, address: ethRoutingContract }, ]; +//TODO: figure out actual value for compute budget export const setComputeUnitLimitIx: web3.TransactionInstruction = web3.ComputeBudgetProgram.setComputeUnitLimit({ - // units: 420690, units: 900000, }); export const SWIM_USD_TO_TOKEN_NUMBER = 0; @@ -64,11 +64,11 @@ export const marginalPricePoolTokenIndex = 0; export const swimPayloadVersion = 1; export const usdcPoolTokenIndex = 0; export const usdtPoolTokenIndex = 1; -export const metapoolMint1OutputTokenIndex = 3; +export const metapoolMint1ToTokenNumber = 3; export const metapoolMint1PoolTokenIndex = 1; // const evmOwner = Buffer.from(evmOwnerEthHexStr, "hex"); -export const gasKickstartAmount: BN = new BN(0.75 * LAMPORTS_PER_SOL); -export const initAtaFee: BN = new BN(0.25 * LAMPORTS_PER_SOL); +export const gasKickstartAmount: BN = new BN(0.25 * LAMPORTS_PER_SOL); +export const initAtaFee: BN = new BN(0.0025 * LAMPORTS_PER_SOL); export const secpVerifyInitFee: BN = new BN(0.000045 * LAMPORTS_PER_SOL); export const secpVerifyFee: BN = new BN(0.00004 * LAMPORTS_PER_SOL); export const postVaaFee: BN = new BN(0.00005 * LAMPORTS_PER_SOL); diff --git a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts index af1fc0178..304062baf 100644 --- a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts @@ -61,8 +61,8 @@ import { lpFee, marginalPricePoolTokenIndex, maxStaleness, - metapoolMint1OutputTokenIndex, metapoolMint1PoolTokenIndex, + metapoolMint1ToTokenNumber, postVaaFee, processSwimPayloadFee, routingContracts, @@ -75,6 +75,7 @@ import { usdtPoolTokenIndex, } from "../consts"; import { + getOwnerAtaAddrsForPool, getPoolUserBalances, printPoolUserBalances, setupPoolPrereqs, @@ -86,12 +87,11 @@ import { encodeSwimPayload, generatePropellerEngineTxns, getFeeTrackerPda, - getOwnerTokenAccountsForPool, getPropellerPda, getPropellerRedeemerPda, getSwimClaimPda, getSwimPayloadMessagePda, - getTargetTokenIdMapAddr, + getToTokenNumberMapAddr, getWormholeAddressesForMint, } from "./propellerUtils"; import { @@ -156,7 +156,8 @@ let propeller: web3.PublicKey; let propellerSender: web3.PublicKey; let propellerRedeemer: web3.PublicKey; let propellerRedeemerEscrowAccount: web3.PublicKey; -const propellerAdmin: web3.Keypair = web3.Keypair.generate(); +const propellerGovernanceKey: web3.Keypair = web3.Keypair.generate(); +const propellerPauseKey: web3.Keypair = web3.Keypair.generate(); let propellerFeeVault: web3.PublicKey; const initialMintAmount = new BN(100_000_000_000_000); @@ -217,7 +218,7 @@ let marginalPricePoolToken1Account: web3.PublicKey; let marginalPricePoolLpMint: web3.PublicKey; const marginalPricePoolTokenMint = usdcKeypair.publicKey; -let outputTokenIdMappingAddrs: ReadonlyMap; +let toTokenNumberMapAddrs: ReadonlyMap; let wormholeAddresses: WormholeAddresses; let custody: web3.PublicKey; @@ -716,30 +717,6 @@ describe("propeller", () => { await seedWormholeCustody(); console.info(`finished seeing wormhole custody`); - - console.info(`setting up switchboard`); - - // // If fails, fallback to looking for a local env file - // try { - // switchboard = await SwitchboardTestContext.loadFromEnv(provider); - // console.info(`set up switchboard`); - // const aggregatorAccount = await switchboard.createStaticFeed(100); - // aggregator = aggregatorAccount.publicKey; - // // switchboard = await SwitchboardTestContext.loadDevnetQueue( - // // provider, - // // "F8ce7MsckeZAbAGmxjJNetxYXQa9mKr9nnrC3qKubyYy" - // // ); - // // aggregatorKey = DEFAULT_SOL_USD_FEED; - // console.info("local env detected"); - // return; - // } catch (error: any) { - // console.info(`Error: SBV2 Localnet - ${JSON.stringify(error.message)}`); - // throw new Error( - // `Failed to load localenv SwitchboardTestContext: ${JSON.stringify( - // error.message, - // )}`, - // ); - // } }, 50000); describe("propellerEngine CompleteWithPayload and ProcessSwimPayload", () => { @@ -1282,7 +1259,7 @@ describe("propeller", () => { )}`, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -1298,7 +1275,7 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await propellerEnginePropellerProgram.methods .processSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, minOutputAmount, ) .accounts({ @@ -1327,7 +1304,7 @@ describe("propeller", () => { const propellerProcessSwimPayloadIxs = propellerEnginePropellerProgram.methods .propellerProcessSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, @@ -1351,41 +1328,35 @@ describe("propeller", () => { console.info( `${JSON.stringify(propellerProcessSwimPayloadPubkeys, null, 2)}`, ); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } + const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); - const expectedTokenIdMap = - outputTokenIdMappingAddrs.get(targetTokenId); - if (!expectedTokenIdMap) { - throw new Error("expectedTokenIdMap not found"); + const expectedTokenNumberMap = + toTokenNumberMapAddrs.get(targetTokenId); + if (!expectedTokenNumberMap) { + throw new Error("expectedTokenNumberMap not found"); } - const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch( - expectedTokenIdMap, + const expectedTokenNumberMapAcct = + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenNumberMap, ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} - expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : - ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} + expectedTokenIdMapAcct: ${expectedTokenNumberMap.toBase58()} : + ${JSON.stringify(expectedTokenNumberMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; - expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); + const derivedTokenNumberMap = + processSwimPayloadPubkeys.tokenNumberMap; + expect(derivedTokenNumberMap).toEqual(expectedTokenNumberMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); } @@ -1866,13 +1837,29 @@ describe("propeller", () => { const poolToken0Mint = usdcKeypair.publicKey; const poolToken1Mint = usdtKeypair.publicKey; const lpMint = swimUsdMint; + const swimPayloadMessageDataTransferAmountBefore = ( + await propellerEnginePropellerProgram.account.swimPayloadMessage.fetch( + swimPayloadMessage, + ) + ).transferAmount; + const userAtas = await Promise.all([ + getAssociatedTokenAddress(usdcKeypair.publicKey, owner), + getAssociatedTokenAddress(usdtKeypair.publicKey, owner), + getAssociatedTokenAddress(swimUsdKeypair.publicKey, owner), + ]); const [userTokenAccount0, userTokenAccount1, userLpTokenAccount] = - await Promise.all([ - getAssociatedTokenAddress(usdcKeypair.publicKey, owner), - getAssociatedTokenAddress(usdtKeypair.publicKey, owner), - getAssociatedTokenAddress(swimUsdKeypair.publicKey, owner), - ]); + userAtas; + const userAtaInitCount = ( + await Promise.all( + userAtas.map(async (ata) => { + return await splToken.account.token.fetchNullable(ata); + }), + ) + ).reduce((acc, ata) => { + return acc + (ata === null ? 1 : 0); + }, 0); + expect(userAtaInitCount).toEqual(3); const propellerFeeVaultBalanceBefore = ( await splToken.account.token.fetch(propellerFeeVault) ).amount; @@ -1920,6 +1907,37 @@ describe("propeller", () => { .preInstructions([setComputeUnitLimitIx]) .rpc(); + const userAtaAccountLength = ( + await connection.getAccountInfo(userAtas[0]) + ).data.length; + const userAtaRentExemption = + await connection.getMinimumBalanceForRentExemption( + userAtaAccountLength, + ); + const totalRentExemptionInLamports = new BN(userAtaInitCount).mul( + new BN(userAtaRentExemption), + ); + const expectedFeesInLamports = new BN(userAtaInitCount) + .mul(initAtaFee) + .add(totalRentExemptionInLamports); + + const feeSwimUsdBn = await convertLamportsToSwimUsdAtomic( + expectedFeesInLamports, + ); + + console.info(` + userAtaInitCount: ${userAtaInitCount} + * userAtaRentExemption: ${userAtaRentExemption} + = totalRentExemptionInLamports: ${totalRentExemptionInLamports.toString()} + + (initAtaFee: ${initAtaFee.toString()} + * userAtaInitCount: ${userAtaInitCount}) + + totalRentExemptionInLamports: ${totalRentExemptionInLamports.toString()} + = expectedFeesInLamports: ${expectedFeesInLamports.toString()} + + feeSwimUsdBn = ${feeSwimUsdBn.toString()} + `); + const propellerFeeVaultBalanceAfter = ( await splToken.account.token.fetch(propellerFeeVault) ).amount; @@ -1937,6 +1955,23 @@ describe("propeller", () => { propellerEngineFeeTrackerFeesOwedBefore, ), ).toBeTruthy(); + + const fees = propellerEngineFeeTrackerFeesOwedAfter.sub( + propellerEngineFeeTrackerFeesOwedBefore, + ); + expect(fees.eq(feeSwimUsdBn)).toBeTruthy(); + + const swimPayloadMessageDataTransferAmountAfter = ( + await propellerEnginePropellerProgram.account.swimPayloadMessage.fetch( + swimPayloadMessage, + ) + ).transferAmount; + + expect( + swimPayloadMessageDataTransferAmountAfter.eq( + swimPayloadMessageDataTransferAmountBefore.sub(feeSwimUsdBn), + ), + ).toBeTruthy(); const userTokenAccount0Data = await splToken.account.token.fetch( userTokenAccount0, ); @@ -1987,7 +2022,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -2002,33 +2037,19 @@ describe("propeller", () => { await splToken.account.token.fetch(userTokenAccount1) ).amount; const [calculatedSwimClaim, calculatedSwimClaimBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("claim"), - wormholeClaim.toBuffer(), - ], - propellerProgram.programId, - ); + await getSwimClaimPda(wormholeClaim, propellerProgram.programId); - const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + const [calculatedTokenNumberMap, calculatedTokenNumberMapBump] = + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); + const processSwimPayloadPubkeys = await propellerEnginePropellerProgram.methods .processSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, new BN(0), ) .accounts({ @@ -2041,7 +2062,7 @@ describe("propeller", () => { swimPayloadMessageAccount.swimPayloadMessagePayer, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - // tokenIdMap: calculatedTokenIdMap, + // tokenIdMap: calculatedTokenNumberMap, pool, poolTokenAccount0, poolTokenAccount1, @@ -2062,7 +2083,7 @@ describe("propeller", () => { const propellerProcessSwimPayloadIxs = propellerEnginePropellerProgram.methods .propellerProcessSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, ) .accounts({ // Note: anchor can't autoderive nested accounts. @@ -2075,7 +2096,7 @@ describe("propeller", () => { // swimPayloadMessage, // redeemer: propellerRedeemer, // redeemerEscrow: propellerRedeemerEscrowAccount, - // tokenIdMap: calculatedTokenIdMap, + // tokenIdMap: calculatedTokenNumberMap, // pool, // poolTokenAccount0, // poolTokenAccount1, @@ -2114,26 +2135,26 @@ describe("propeller", () => { console.info( `${JSON.stringify(propellerProcessSwimPayloadPubkeys, null, 2)}`, ); - // if (!propellerProcessSwimPayloadPubkeys.tokenIdMap) { + // if (!propellerProcessSwimPayloadPubkeys.tokenNumberMap) { // throw new Error("tokenIdMap not derived"); // } - const expectedTokenIdMap = - outputTokenIdMappingAddrs.get(targetTokenId); - if (!expectedTokenIdMap) { - throw new Error("expectedTokenIdMap not found"); + const expectedTokenNumberMap = + toTokenNumberMapAddrs.get(targetTokenId); + if (!expectedTokenNumberMap) { + throw new Error("expectedTokenNumberMap not found"); } - const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch( - expectedTokenIdMap, + const expectedTokenNumberMapAcct = + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenNumberMap, ); console.info(` - calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} - calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} - expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : - ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} + calculatedTokenIdMap: ${calculatedTokenNumberMap.toBase58()} + calculatedTokenIdMapBump: ${calculatedTokenNumberMapBump} + expectedTokenIdMapAcct: ${expectedTokenNumberMap.toBase58()} : + ${JSON.stringify(expectedTokenNumberMapAcct, null, 2)} `); - expect(calculatedTokenIdMap).toEqual(expectedTokenIdMap); + expect(calculatedTokenNumberMap).toEqual(expectedTokenNumberMap); const processSwimPayloadTxnSig: string = await propellerProcessSwimPayloadIxs.rpc(); @@ -2650,7 +2671,7 @@ describe("propeller", () => { ) ).feesOwed; - [invalidTokenIdMapAddr] = await getTargetTokenIdMapAddr( + [invalidTokenIdMapAddr] = await getToTokenNumberMapAddr( propeller, targetTokenId, propellerEnginePropellerProgram.programId, @@ -2753,7 +2774,7 @@ describe("propeller", () => { swimPayloadMessageAccount.swimPayloadMessagePayer, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - tokenIdMap: invalidTokenIdMapAddr, + tokenNumberMap: invalidTokenIdMapAddr, userSwimUsdAta: ownerSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, @@ -3228,7 +3249,7 @@ describe("propeller", () => { // // const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); // console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - // if (!processSwimPayloadPubkeys.tokenIdMap) { + // if (!processSwimPayloadPubkeys.tokenNumberMap) { // throw new Error("tokenIdMap not derived"); // } // @@ -3248,19 +3269,19 @@ describe("propeller", () => { // ); // // const expectedTokenIdMap = - // outputTokenIdMappingAddrs.get(targetTokenId); + // toTokenNumberMapAddrs.get(targetTokenId); // if (!expectedTokenIdMap) { // throw new Error("expectedTokenIdMap not found"); // } // const expectedTokenIdMapAcct = - // await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + // await propellerProgram.account.tokenNumberMap.fetch(expectedTokenIdMap); // console.info(` // calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} // calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} // expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : // ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} // `); - // const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + // const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; // expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); // if (!processSwimPayloadPubkeys.swimClaim) { // throw new Error("swimClaim key not derived"); @@ -3341,7 +3362,7 @@ describe("propeller", () => { // let wormholeClaim: web3.PublicKey; // let wormholeMessage: web3.PublicKey; // let swimPayloadMessage: web3.PublicKey; - // const targetTokenId = metapoolMint1OutputTokenIndex; + // const targetTokenId = metapoolMint1ToTokenNumber; // const memoBuffer = createMemoId(); // // const memo = "e45794d6c5a2750b"; // @@ -3642,7 +3663,7 @@ describe("propeller", () => { // // const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); // console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - // if (!processSwimPayloadPubkeys.tokenIdMap) { + // if (!processSwimPayloadPubkeys.tokenNumberMap) { // throw new Error("tokenIdMap not derived"); // } // const [calculatedTokenIdMap, calculatedTokenIdMapBump] = @@ -3661,19 +3682,19 @@ describe("propeller", () => { // ); // // const expectedTokenIdMap = - // outputTokenIdMappingAddrs.get(targetTokenId); + // toTokenNumberMapAddrs.get(targetTokenId); // if (!expectedTokenIdMap) { // throw new Error("expectedTokenIdMap not found"); // } // const expectedTokenIdMapAcct = - // await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + // await propellerProgram.account.tokenNumberMap.fetch(expectedTokenIdMap); // console.info(` // calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} // calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} // expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : // ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} // `); - // const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + // const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; // expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); // if (!processSwimPayloadPubkeys.swimClaim) { // throw new Error("swimClaim key not derived"); @@ -4257,7 +4278,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -4271,7 +4292,7 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await propellerEnginePropellerProgram.methods .processSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, new BN(0), ) .accounts({ @@ -4301,7 +4322,7 @@ describe("propeller", () => { const propellerProcessSwimPayloadIxs = propellerEnginePropellerProgram.methods .propellerProcessSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, @@ -4325,31 +4346,23 @@ describe("propeller", () => { console.info( `${JSON.stringify(propellerProcessSwimPayloadPubkeys, null, 2)}`, ); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } + const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); - const expectedTokenIdMap = - outputTokenIdMappingAddrs.get(targetTokenId); + const expectedTokenIdMap = toTokenNumberMapAddrs.get(targetTokenId); if (!expectedTokenIdMap) { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch( + await propellerProgram.account.tokenNumberMap.fetch( expectedTokenIdMap, ); console.info(` @@ -4358,7 +4371,7 @@ describe("propeller", () => { expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -4886,7 +4899,7 @@ describe("propeller", () => { // getAssociatedTokenAddress(usdtKeypair.publicKey, owner), // getAssociatedTokenAddress(swimUsdKeypair.publicKey, owner), // ]); - const userPoolAtas = await getOwnerTokenAccountsForPool( + const userPoolAtas = await getOwnerAtaAddrsForPool( flagshipPool, owner, twoPoolProgram, @@ -4951,7 +4964,7 @@ describe("propeller", () => { `[Ricky] swimPayloadMessage: ${swimPayloadMessage.toString()}`, ); const userBalanceBefore = await connection.getBalance(owner); - const userPoolAtas = await getOwnerTokenAccountsForPool( + const userPoolAtas = await getOwnerAtaAddrsForPool( flagshipPool, owner, twoPoolProgram, @@ -5456,7 +5469,7 @@ describe("propeller", () => { ) ).feesOwed; - [invalidTokenIdMapAddr] = await getTargetTokenIdMapAddr( + [invalidTokenIdMapAddr] = await getToTokenNumberMapAddr( propeller, targetTokenId, propellerEnginePropellerProgram.programId, @@ -6139,7 +6152,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -6153,7 +6166,7 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await propellerEnginePropellerProgram.methods .processSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, new BN(0), ) .accounts({ @@ -6183,7 +6196,7 @@ describe("propeller", () => { const propellerProcessSwimPayloadIxs = propellerEnginePropellerProgram.methods .propellerProcessSwimPayload( - swimPayloadMessageAccountTargetTokenId, + swimPayloadMessageAccountToTokenNumber, ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, @@ -6207,31 +6220,22 @@ describe("propeller", () => { console.info( `${JSON.stringify(propellerProcessSwimPayloadPubkeys, null, 2)}`, ); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); - const expectedTokenIdMap = - outputTokenIdMappingAddrs.get(targetTokenId); + const expectedTokenIdMap = toTokenNumberMapAddrs.get(targetTokenId); if (!expectedTokenIdMap) { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch( + await propellerProgram.account.tokenNumberMap.fetch( expectedTokenIdMap, ); console.info(` @@ -6240,7 +6244,7 @@ describe("propeller", () => { expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -6500,7 +6504,7 @@ describe("propeller", () => { // ], // propellerProgramId, // ); -// const tokenIdMapData = await propellerProgram.account.tokenIdMap.fetch( +// const tokenIdMapData = await propellerProgram.account.tokenNumberMap.fetch( // tokenIdMap, // ); // const poolKey = tokenIdMapData.pool; @@ -6889,21 +6893,18 @@ const initializePropeller = async () => { completeWithPayloadFee, initAtaFee, processSwimPayloadFee, - // propellerMinTransferAmount, - // propellerEthMinTransferAmount, marginalPricePool, marginalPricePoolTokenIndex, marginalPricePoolTokenMint, maxStaleness, - // evmRoutingContractAddress: ethRoutingContract, - // evmRoutingContractAddress: ethRoutingContractEthUint8Arr }; const tx = propellerProgram.methods .initialize(initializeParams) .accounts({ propellerRedeemerEscrow: propellerRedeemerEscrowAddr, propellerFeeVault, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, + pauseKey: propellerPauseKey.publicKey, swimUsdMint: swimUsdMint, payer: userKeypair.publicKey, tokenProgram: TOKEN_PROGRAM_ID, @@ -6917,7 +6918,7 @@ const initializePropeller = async () => { twoPoolProgram: twoPoolProgram.programId, aggregator, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey, propellerPauseKey]); const pubkeys = await tx.pubkeys(); console.info(`pubkeys: ${JSON.stringify(pubkeys, null, 2)}`); @@ -6974,102 +6975,105 @@ const initializePropeller = async () => { }; const createTokenIdMaps = async () => { - const swimUsdTokenIdMap = { + const swimUsdTokenNumberMap = { pool: flagshipPool, poolTokenIndex: 0, poolTokenMint: swimUsdKeypair.publicKey, - poolIx: { transfer: {} }, + toTokenStep: { transfer: {} }, }; - const usdcTokenIdMap = { + const usdcTokenNumberMap = { pool: flagshipPool, poolTokenIndex: usdcPoolTokenIndex, poolTokenMint: usdcKeypair.publicKey, - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const usdtTokenIdMap = { + const usdtTokenNumberMap = { pool: flagshipPool, poolTokenIndex: usdtPoolTokenIndex, poolTokenMint: usdtKeypair.publicKey, - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const metapoolMint1TokenIdMap = { + const metapoolMint1TokenNumberMap = { pool: metapool, poolTokenIndex: metapoolMint1PoolTokenIndex, poolTokenMint: metapoolMint1Keypair.publicKey, - poolIx: { swapExactInput: {} }, + toTokenStep: { swapExactInput: {} }, }; - const outputTokenIdMapAddrEntries = await Promise.all( + const toTokenNumberMapAddrEntries = await Promise.all( [ { - outputTokenIndex: SWIM_USD_TO_TOKEN_NUMBER, - tokenIdMap: swimUsdTokenIdMap, + toTokenNumber: SWIM_USD_TO_TOKEN_NUMBER, + tokenNumberMap: swimUsdTokenNumberMap, + }, + { + toTokenNumber: USDC_TO_TOKEN_NUMBER, + tokenNumberMap: usdcTokenNumberMap, + }, + { + toTokenNumber: USDT_TO_TOKEN_NUMBER, + tokenNumberMap: usdtTokenNumberMap, }, - { outputTokenIndex: USDC_TO_TOKEN_NUMBER, tokenIdMap: usdcTokenIdMap }, - { outputTokenIndex: USDT_TO_TOKEN_NUMBER, tokenIdMap: usdtTokenIdMap }, { - outputTokenIndex: metapoolMint1OutputTokenIndex, - tokenIdMap: metapoolMint1TokenIdMap, + toTokenNumber: metapoolMint1ToTokenNumber, + tokenNumberMap: metapoolMint1TokenNumberMap, }, - ].map(async ({ outputTokenIndex, tokenIdMap }) => { - const createTokenIdMappingTxn = propellerProgram.methods - .createTokenIdMap( - outputTokenIndex, - tokenIdMap.pool, - tokenIdMap.poolTokenIndex, - tokenIdMap.poolTokenMint, - tokenIdMap.poolIx, + ].map(async ({ toTokenNumber, tokenNumberMap }) => { + console.info(`creating tokenNumberMap for ${toTokenNumber}`); + const createTokenNumberMapTxn = propellerProgram.methods + .createTokenNumberMap( + toTokenNumber, + tokenNumberMap.pool, + tokenNumberMap.poolTokenIndex, + tokenNumberMap.poolTokenMint, + tokenNumberMap.toTokenStep, ) .accounts({ propeller, - admin: propellerAdmin.publicKey, - payer: userKeypair.publicKey, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, - pool: tokenIdMap.pool, + pool: tokenNumberMap.pool, twoPoolProgram: twoPoolProgram.programId, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey]); - const pubkeys = await createTokenIdMappingTxn.pubkeys(); - if (!pubkeys.tokenIdMap) { + const pubkeys = await createTokenNumberMapTxn.pubkeys(); + if (!pubkeys.tokenNumberMap) { throw new Error("Token Id Map PDA Address was not auto-derived"); } - const tokenIdMapAddr = pubkeys.tokenIdMap; - expect(tokenIdMapAddr).toBeTruthy(); + const tokenNumberMapAddr = pubkeys.tokenNumberMap; + expect(tokenNumberMapAddr).toBeTruthy(); const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(outputTokenIndex).toArrayLike(Buffer, "le", 2), - // byteify.serializeUint16(usdcOutputTokenIndex), - ], + await getToTokenNumberMapAddr( + propeller, + toTokenNumber, propellerProgram.programId, ); - expect(tokenIdMapAddr).toEqual(calculatedTokenIdMap); - await createTokenIdMappingTxn.rpc(); + expect(tokenNumberMapAddr).toEqual(calculatedTokenIdMap); + await createTokenNumberMapTxn.rpc(); - const fetchedTokenIdMap = await propellerProgram.account.tokenIdMap.fetch( - tokenIdMapAddr, - ); - expect(fetchedTokenIdMap.outputTokenIndex).toEqual(outputTokenIndex); - expect(fetchedTokenIdMap.pool).toEqual(tokenIdMap.pool); + const fetchedTokenIdMap = + await propellerProgram.account.tokenNumberMap.fetch(tokenNumberMapAddr); + expect(fetchedTokenIdMap.toTokenNumber).toEqual(toTokenNumber); + expect(fetchedTokenIdMap.pool).toEqual(tokenNumberMap.pool); expect(fetchedTokenIdMap.poolTokenIndex).toEqual( - tokenIdMap.poolTokenIndex, + tokenNumberMap.poolTokenIndex, ); - expect(fetchedTokenIdMap.poolTokenMint).toEqual(tokenIdMap.poolTokenMint); - expect(fetchedTokenIdMap.poolIx).toEqual(tokenIdMap.poolIx); + expect(fetchedTokenIdMap.poolTokenMint).toEqual( + tokenNumberMap.poolTokenMint, + ); + expect(fetchedTokenIdMap.toTokenStep).toEqual(tokenNumberMap.toTokenStep); expect(fetchedTokenIdMap.bump).toEqual(calculatedTokenIdMapBump); - return { outputTokenIndex, tokenIdMapAddr }; + return { toTokenNumber, tokenNumberMapAddr }; }), ); - outputTokenIdMappingAddrs = new Map( - outputTokenIdMapAddrEntries.map(({ outputTokenIndex, tokenIdMapAddr }) => { - return [outputTokenIndex, tokenIdMapAddr]; + toTokenNumberMapAddrs = new Map( + toTokenNumberMapAddrEntries.map(({ toTokenNumber, tokenNumberMapAddr }) => { + return [toTokenNumber, tokenNumberMapAddr]; }), ); }; @@ -7081,12 +7085,12 @@ const createTargetChainMaps = async () => { .createTargetChainMap(targetChainId, address) .accounts({ propeller, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, payer: propellerEngineKeypair.publicKey, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey]); const createTargetChainMapPubkeys = await createTargetChainMap.pubkeys(); await createTargetChainMap.rpc(); @@ -7118,8 +7122,14 @@ const seedWormholeCustody = async () => { const transferAmount = userLpTokenBalanceBefore.div(new BN(2)); const wormholeMessage = web3.Keypair.generate(); + const nonce = createNonce().readUInt32LE(0); const crossChainTransferNativeTxnSig = await propellerProgram.methods - .crossChainTransferNativeWithPayload(transferAmount, CHAIN_ID_ETH, evmOwner) + .crossChainTransferNativeWithPayload( + nonce, + transferAmount, + CHAIN_ID_ETH, + evmOwner, + ) .accounts({ propeller, payer: payer.publicKey, @@ -7186,6 +7196,37 @@ const convertLamportsToSwimUsdAtomic = async (feeInLamports: BN) => { return new BN(feeSwimUsdAtomic.toNumber()); }; +const getExpectedFeesForCreateUserAtasInLamports = async ( + swimUsdMintKey: web3.PublicKey, + swimPayloadMessage: web3.PublicKey, +) => { + const swimPayloadMessageAcctData = + await propellerProgram.account.swimPayloadMessage.fetch(swimPayloadMessage); + const swimPayloadOwner = swimPayloadMessageAcctData.owner; + const outputTokenIndex = swimPayloadMessageAcctData.toTokenNumber; + const propellerAddr = await getPropellerPda( + swimUsdMintKey, + propellerProgram.programId, + ); + const [tokenIdMapAddr] = await getToTokenNumberMapAddr( + propellerAddr, + outputTokenIndex, + propellerProgram.programId, + ); + const tokenNumberMapAcctData = + await propellerProgram.account.tokenNumberMap.fetch(tokenIdMapAddr); + const tokenNumberMapPool = tokenNumberMapAcctData.pool; + const poolAcctData = await twoPoolProgram.account.twoPool.fetch( + tokenNumberMapPool, + ); + const poolMints = [...poolAcctData.tokenMintKeys, poolAcctData.lpMintKey]; + const userAtas = await Promise.all( + poolMints.map(async (mint) => { + return await getAssociatedTokenAddress(mint, swimPayloadOwner); + }), + ); +}; + function createMemoId() { const SWIM_MEMO_LENGTH = 16; // NOTE: Please always use random bytes to avoid conflicts with other users diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index 58eebee77..6a2c799d0 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -1,3 +1,5 @@ +import * as crypto from "crypto"; + import { CHAIN_ID_ETH, CHAIN_ID_SOLANA, @@ -26,6 +28,7 @@ import { TOKEN_PROGRAM_ID, getAccount, getAssociatedTokenAddress, + getOrCreateAssociatedTokenAccount, } from "@solana/spl-token"; import { PublicKey } from "@solana/web3.js"; @@ -46,6 +49,7 @@ import { ethRoutingContract, ethRoutingContractEthHexStr, ethTokenBridge, + ethTokenBridgeNativeStr, evmOwner, evmTargetTokenId, gasKickstartAmount, @@ -54,8 +58,8 @@ import { lpFee, marginalPricePoolTokenIndex, maxStaleness, - metapoolMint1OutputTokenIndex, metapoolMint1PoolTokenIndex, + metapoolMint1ToTokenNumber, postVaaFee, processSwimPayloadFee, routingContracts, @@ -68,23 +72,31 @@ import { usdtPoolTokenIndex, } from "../consts"; import { + getPoolTokenAccountBalances, getPoolUserBalances, + getUserAtaBalancesForPool, printBeforeAndAfterPoolUserBalances, printPoolUserBalances, setupPoolPrereqs, setupUserAssociatedTokenAccts, } from "../twoPool/poolTestUtils"; +import type { WormholeAddresses } from "./propellerUtils"; import { + DummyForeignRoutingProgram, encodeSwimPayload, formatParsedTokenTransferWithSwimPayloadPostedMessage, + getCompleteNativeWithPayloadTxn, + getProcessSwimPayloadTxn, getPropellerPda, getPropellerRedeemerPda, getPropellerSenderPda, getSwimClaimPda, getSwimPayloadMessagePda, + getToTokenNumberMapAddr, getWormholeAddressesForMint, - parseTokenTransferWithSwimPayloadPostedMessage, WormholeAddresses, + parseTokenTransferWithSwimPayloadPostedMessage, + postVaaToSolana, } from "./propellerUtils"; import { deriveEndpointPda, @@ -98,23 +110,8 @@ import { signAndEncodeVaa, } from "./wormholeUtils"; -// this just breaks everything for some reason... -// think it was something related to the cjs/esm stuff for spl-memo -// -// const MEMO_PROGRAM_ID: PublicKey = new PublicKey( -// "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr", -// ); + setDefaultWasm("node"); -// const pr2 = new AnchorProvider( -// connection, -// provider.wallet, -// { -// commitment: "confirmed", -// } -// ) -// const process = require("process"); -// const url = process.env.ANCHOR_PROVIDER_URL; -// const provider = AnchorProvider.local(url, {commitment: "confirmed"}); const envProvider = AnchorProvider.env(); const provider = new AnchorProvider( @@ -143,7 +140,7 @@ const wormhole = WORMHOLE_CORE_BRIDGE; const tokenBridge = WORMHOLE_TOKEN_BRIDGE; // start these higher to avoid issues when running this suite & engine.test.ts suite in one go -let ethTokenBridgeSequence = 1000; +const ethTokenBridgeSequence = 1000; // let ethTokenBridgeSequence = BigInt(0); let metapool: web3.PublicKey; @@ -157,7 +154,8 @@ let propeller: web3.PublicKey; let propellerSender: web3.PublicKey; let propellerRedeemer: web3.PublicKey; let propellerRedeemerEscrowAccount: web3.PublicKey; -const propellerAdmin: web3.Keypair = web3.Keypair.generate(); +const propellerGovernanceKey: web3.Keypair = web3.Keypair.generate(); +const propellerPauseKey: web3.Keypair = web3.Keypair.generate(); let propellerFeeVault: web3.PublicKey; const dummyUser = payer; @@ -181,8 +179,8 @@ const poolMintKeypairs = [usdcKeypair, usdtKeypair]; const poolMintDecimals = [mintDecimal, mintDecimal]; const poolMintAuthorities = [payer, payer]; const swimUsdKeypair = web3.Keypair.generate(); -const governanceKeypair = web3.Keypair.generate(); -const pauseKeypair = web3.Keypair.generate(); +const poolGovernanceKeypair = web3.Keypair.generate(); +const poolPauseKeypair = web3.Keypair.generate(); let poolUsdcAtaAddr: web3.PublicKey; let poolUsdtAtaAddr: web3.PublicKey; @@ -248,6 +246,16 @@ let tokenBridgeConfig: web3.PublicKey; let custodySigner: web3.PublicKey; const aggregator: web3.PublicKey = DEFAULT_SOL_USD_FEED; +const dummyEthTokenBridge: DummyForeignRoutingProgram = + new DummyForeignRoutingProgram( + ethTokenBridgeNativeStr, + CHAIN_ID_ETH, + ethTokenBridgeSequence, + swimUsdMint.toBuffer(), + propellerProgram.programId, + ethRoutingContract, + ); + describe("propeller", () => { beforeAll(async () => { console.info(`initializing two pool v2`); @@ -262,7 +270,7 @@ describe("propeller", () => { poolMintDecimals, poolMintAuthorities.map((k) => k.publicKey), swimUsdKeypair.publicKey, - governanceKeypair.publicKey, + poolGovernanceKeypair.publicKey, )); const initFlagshipPoolTxn = twoPoolProgram.methods // .initialize(params) @@ -274,8 +282,8 @@ describe("propeller", () => { lpMint: swimUsdKeypair.publicKey, poolTokenAccount0: poolUsdcAtaAddr, poolTokenAccount1: poolUsdtAtaAddr, - pauseKey: pauseKeypair.publicKey, - governanceAccount: governanceKeypair.publicKey, + pauseKey: poolPauseKeypair.publicKey, + governanceAccount: poolGovernanceKeypair.publicKey, governanceFeeAccount: flagshipPoolGovernanceFeeAcct, tokenProgram: splToken.programId, associatedTokenProgram: splAssociatedToken.programId, @@ -373,7 +381,7 @@ describe("propeller", () => { // [metapoolMint1Decimal], // [metapoolMint1Authority.publicKey], metapoolLpMintKeypair.publicKey, - governanceKeypair.publicKey, + poolGovernanceKeypair.publicKey, )); const initMetapoolTxn = twoPoolProgram.methods @@ -386,8 +394,8 @@ describe("propeller", () => { lpMint: metapoolLpMintKeypair.publicKey, poolTokenAccount0: metapoolPoolToken0Ata, poolTokenAccount1: metapoolPoolToken1Ata, - pauseKey: pauseKeypair.publicKey, - governanceAccount: governanceKeypair.publicKey, + pauseKey: poolPauseKeypair.publicKey, + governanceAccount: poolGovernanceKeypair.publicKey, governanceFeeAccount: metapoolGovernanceFeeAta, tokenProgram: splToken.programId, associatedTokenProgram: splAssociatedToken.programId, @@ -475,7 +483,6 @@ describe("propeller", () => { } `); - wormholeAddresses = await getWormholeAddressesForMint( WORMHOLE_CORE_BRIDGE, WORMHOLE_TOKEN_BRIDGE, @@ -483,7 +490,7 @@ describe("propeller", () => { ethTokenBridge, bscTokenBridge, ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + ({ authoritySigner, custody, @@ -550,7 +557,8 @@ describe("propeller", () => { .accounts({ propellerRedeemerEscrow: propellerRedeemerEscrowAddr, propellerFeeVault, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, + pauseKey: propellerPauseKey.publicKey, swimUsdMint: swimUsdMint, payer: payer.publicKey, tokenProgram: TOKEN_PROGRAM_ID, @@ -564,7 +572,7 @@ describe("propeller", () => { twoPoolProgram: twoPoolProgram.programId, aggregator, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey, propellerPauseKey]); const pubkeys = await tx.pubkeys(); console.info(`pubkeys: ${JSON.stringify(pubkeys, null, 2)}`); @@ -625,7 +633,9 @@ describe("propeller", () => { propeller, ); console.info(`propellerData: ${JSON.stringify(propellerData)}`); - expect(propellerData.admin).toEqual(propellerAdmin.publicKey); + expect(propellerData.governanceKey).toEqual( + propellerGovernanceKey.publicKey, + ); expect(propellerData.swimUsdMint).toEqual(swimUsdMint); console.info( @@ -648,117 +658,126 @@ describe("propeller", () => { `); }); - it("Creates Token Id Mappings", async () => { - const swimUsdTokenIdMap = { + it("Creates Token Number Maps", async () => { + const swimUsdTokenNumberMap = { pool: flagshipPool, poolTokenIndex: 0, poolTokenMint: swimUsdKeypair.publicKey, - poolIx: { transfer: {} }, + toTokenStep: { transfer: {} }, }; - const usdcTokenIdMap = { + const usdcTokenNumberMap = { pool: flagshipPool, poolTokenIndex: usdcPoolTokenIndex, poolTokenMint: usdcKeypair.publicKey, - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const usdtTokenIdMap = { + const usdtTokenNumberMap = { pool: flagshipPool, poolTokenIndex: usdtPoolTokenIndex, poolTokenMint: usdtKeypair.publicKey, - poolIx: { removeExactBurn: {} }, + toTokenStep: { removeExactBurn: {} }, }; - const metapoolMint1TokenIdMap = { + const metapoolMint1TokenNumberMap = { pool: metapool, poolTokenIndex: metapoolMint1PoolTokenIndex, poolTokenMint: metapoolMint1Keypair.publicKey, - poolIx: { swapExactInput: {} }, + toTokenStep: { swapExactInput: {} }, }; - const outputTokenIdMapAddrEntries = await Promise.all( + const toTokenNumberMapAddrEntries = await Promise.all( [ { - outputTokenIndex: SWIM_USD_TO_TOKEN_NUMBER, - tokenIdMap: swimUsdTokenIdMap, + toTokenNumber: SWIM_USD_TO_TOKEN_NUMBER, + tokenNumberMap: swimUsdTokenNumberMap, + }, + { + toTokenNumber: USDC_TO_TOKEN_NUMBER, + tokenNumberMap: usdcTokenNumberMap, }, - { outputTokenIndex: USDC_TO_TOKEN_NUMBER, tokenIdMap: usdcTokenIdMap }, - { outputTokenIndex: USDT_TO_TOKEN_NUMBER, tokenIdMap: usdtTokenIdMap }, { - outputTokenIndex: metapoolMint1OutputTokenIndex, - tokenIdMap: metapoolMint1TokenIdMap, + toTokenNumber: USDT_TO_TOKEN_NUMBER, + tokenNumberMap: usdtTokenNumberMap, }, - ].map(async ({ outputTokenIndex, tokenIdMap }) => { - const createTokenIdMappingTxn = propellerProgram.methods - .createTokenIdMap( - outputTokenIndex, - tokenIdMap.pool, - tokenIdMap.poolTokenIndex, - tokenIdMap.poolTokenMint, - tokenIdMap.poolIx, + { + toTokenNumber: metapoolMint1ToTokenNumber, + tokenNumberMap: metapoolMint1TokenNumberMap, + }, + ].map(async ({ toTokenNumber, tokenNumberMap }) => { + console.info(`creating tokenNumberMap for ${toTokenNumber}`); + const createTokenNumberMapTxn = propellerProgram.methods + .createTokenNumberMap( + toTokenNumber, + tokenNumberMap.pool, + tokenNumberMap.poolTokenIndex, + tokenNumberMap.poolTokenMint, + tokenNumberMap.toTokenStep, ) .accounts({ propeller, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, payer: payer.publicKey, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, - pool: tokenIdMap.pool, + pool: tokenNumberMap.pool, twoPoolProgram: twoPoolProgram.programId, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey]); - const pubkeys = await createTokenIdMappingTxn.pubkeys(); - if (!pubkeys.tokenIdMap) { + const pubkeys = await createTokenNumberMapTxn.pubkeys(); + if (!pubkeys.tokenNumberMap) { throw new Error("Token Id Map PDA Address was not auto-derived"); } - const tokenIdMapAddr = pubkeys.tokenIdMap; - expect(tokenIdMapAddr).toBeTruthy(); + const tokenNumberMapAddr = pubkeys.tokenNumberMap; + expect(tokenNumberMapAddr).toBeTruthy(); const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(outputTokenIndex).toArrayLike(Buffer, "le", 2), - // byteify.serializeUint16(usdcOutputTokenIndex), - ], + await getToTokenNumberMapAddr( + propeller, + toTokenNumber, propellerProgram.programId, ); - expect(tokenIdMapAddr).toEqual(calculatedTokenIdMap); - await createTokenIdMappingTxn.rpc(); + + expect(tokenNumberMapAddr).toEqual(calculatedTokenIdMap); + await createTokenNumberMapTxn.rpc(); const fetchedTokenIdMap = - await propellerProgram.account.tokenIdMap.fetch(tokenIdMapAddr); - expect(fetchedTokenIdMap.outputTokenIndex).toEqual(outputTokenIndex); - expect(fetchedTokenIdMap.pool).toEqual(tokenIdMap.pool); + await propellerProgram.account.tokenNumberMap.fetch( + tokenNumberMapAddr, + ); + expect(fetchedTokenIdMap.toTokenNumber).toEqual(toTokenNumber); + expect(fetchedTokenIdMap.pool).toEqual(tokenNumberMap.pool); expect(fetchedTokenIdMap.poolTokenIndex).toEqual( - tokenIdMap.poolTokenIndex, + tokenNumberMap.poolTokenIndex, ); expect(fetchedTokenIdMap.poolTokenMint).toEqual( - tokenIdMap.poolTokenMint, + tokenNumberMap.poolTokenMint, + ); + expect(fetchedTokenIdMap.toTokenStep).toEqual( + tokenNumberMap.toTokenStep, ); - expect(fetchedTokenIdMap.poolIx).toEqual(tokenIdMap.poolIx); expect(fetchedTokenIdMap.bump).toEqual(calculatedTokenIdMapBump); - return { outputTokenIndex, tokenIdMapAddr }; + return { toTokenNumber, tokenNumberMapAddr }; }), ); outputTokenIdMappingAddrs = new Map( - outputTokenIdMapAddrEntries.map( - ({ outputTokenIndex, tokenIdMapAddr }) => { - return [outputTokenIndex, tokenIdMapAddr]; + toTokenNumberMapAddrEntries.map( + ({ toTokenNumber, tokenNumberMapAddr }) => { + return [toTokenNumber, tokenNumberMapAddr]; }, ), ); for (const [ - outputTokenIndex, - tokenIdMapAddr, + toTokenNumber, + tokenNumberMapAddr, ] of outputTokenIdMappingAddrs.entries()) { console.info(` - outputTokenIndex: ${outputTokenIndex} - tokenIdMapAddr: ${tokenIdMapAddr.toBase58()} - tokenIdMap: ${JSON.stringify( - await propellerProgram.account.tokenIdMap.fetch(tokenIdMapAddr), + toTokenNumber: ${toTokenNumber} + tokenNumberMapAddr: ${tokenNumberMapAddr.toBase58()} + tokenNumberMap: ${JSON.stringify( + await propellerProgram.account.tokenNumberMap.fetch( + tokenNumberMapAddr, + ), )} `); } @@ -771,12 +790,12 @@ describe("propeller", () => { .createTargetChainMap(targetChainId, address) .accounts({ propeller, - admin: propellerAdmin.publicKey, + governanceKey: propellerGovernanceKey.publicKey, payer: payer.publicKey, systemProgram: web3.SystemProgram.programId, // rent: web3.SYSVAR_RENT_PUBKEY, }) - .signers([propellerAdmin]); + .signers([propellerGovernanceKey]); const createTargetChainMapPubkeys = await createTargetChainMap.pubkeys(); @@ -788,7 +807,6 @@ describe("propeller", () => { return { targetChainId, targetAddress: address, - targetChainMapData, }; }), @@ -1515,11 +1533,10 @@ describe("propeller", () => { const memo = createMemoId(); const wormholeMessage = web3.Keypair.generate(); - const nonceBefore = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; + const nonce = createNonce().readUInt32LE(0); const transferNativeTxn = await propellerProgram.methods .crossChainTransferNativeWithPayload( + nonce, transferAmount, CHAIN_ID_ETH, evmOwner, @@ -1558,11 +1575,6 @@ describe("propeller", () => { rpcCommitmentConfig, ); - const nonceAfter = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; - expect(nonceAfter).toEqual(nonceBefore + 1); - const transferNativeTxnSize = transferNativeTxn.serialize().length; console.info(`transferNativeTxnSize txnSize: ${transferNativeTxnSize}`); await connection.confirmTransaction({ @@ -1630,32 +1642,12 @@ describe("propeller", () => { 2, )}`, ); - expect(tokenTransferMessage.core.nonce).toEqual(nonceBefore); expect(swimPayload.owner).toEqual(evmOwner); expect(swimPayload.propellerEnabled).toBeUndefined(); expect(swimPayload.gasKickstart).toBeUndefined(); expect(swimPayload.maxFee).toBeUndefined(); expect(swimPayload.targetTokenId).toBeUndefined(); expect(swimPayload.memo).toBeUndefined(); - // this fails due to capitalization - // expect(formattedTokenTransferMessage.tokenTransfer.to).to.equal(ethRoutingContractStr); - // console.info(` - // tokenTransferMessage: ${JSON.stringify(tokenTransferMessage, null ,2)} - // `) - // console.info(`postedMessage:\n${JSON.stringify(postedMessage)}`); - // console.info(`postedMessagePayload:\n${JSON.stringify(postedMessagePayload)}`); - // const { - // payload: swimPayload - // } = postedMessagePayload; - // console.info(` - // evmOwnerEthHexStr: ${evmOwnerEthHexStr} - // evmOwner(Buffer.toString('hex')): ${evmOwner.toString('hex')} - // evmTargetTokenAddrEthHexStr: ${evmTargetTokenAddrEthHexStr} - // evmTargetTokenAddr(Buffer.toString('hex')): ${evmTargetTokenAddr.toString('hex')} - // `); - // console.info(`swimPayload:\n${JSON.stringify(swimPayload)}`); - // const transferAmountBuffer = transferAmount.toBuffer('be'); - // console.info(`transferAmountBufferHexStr: ${transferAmountBuffer.toString('hex')}`); }); it("calls propellerTransferNativeWithPayload with memo", async () => { @@ -1679,18 +1671,18 @@ describe("propeller", () => { const wormholeMessage = web3.Keypair.generate(); const gasKickstart = false; const maxFee = new BN(100_000); - const nonceBefore = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; + const nonce = createNonce().readUInt32LE(0); + const propellerTransferNativeTxn = await propellerProgram.methods .propellerTransferNativeWithPayload( + nonce, transferAmount, CHAIN_ID_ETH, evmOwner, gasKickstart, maxFee, evmTargetTokenId, - Buffer.from(memo, "hex"), + memo, ) .accounts({ propeller, @@ -1726,11 +1718,6 @@ describe("propeller", () => { rpcCommitmentConfig, ); - const nonceAfter = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; - expect(nonceAfter).toEqual(nonceBefore + 1); - const transferNativeTxnSize = propellerTransferNativeTxn.serialize().length; console.info(`transferNativeTxnSize txnSize: ${transferNativeTxnSize}`); @@ -1800,36 +1787,13 @@ describe("propeller", () => { 2, )}`, ); - expect(tokenTransferMessage.core.nonce).toEqual(nonceBefore); expect(swimPayload.owner).toEqual(evmOwner); expect(swimPayload.propellerEnabled).toEqual(true); expect(swimPayload.gasKickstart).toEqual(gasKickstart); expect(swimPayload.maxFee).toEqual(maxFee); expect(swimPayload.targetTokenId).toEqual(evmTargetTokenId); expect(swimPayload.memo.toString("hex")).toEqual(memo.toString("hex")); - await checkTxnLogsForMemo( - propellerTransferNativeTxnSig, - memo.toString("hex"), - ); - // this fails due to capitalization - // expect(formattedTokenTransferMessage.tokenTransfer.to).to.equal(ethRoutingContractStr); - // console.info(` - // tokenTransferMessage: ${JSON.stringify(tokenTransferMessage, null ,2)} - // `) - // console.info(`postedMessage:\n${JSON.stringify(postedMessage)}`); - // console.info(`postedMessagePayload:\n${JSON.stringify(postedMessagePayload)}`); - // const { - // payload: swimPayload - // } = postedMessagePayload; - // console.info(` - // evmOwnerEthHexStr: ${evmOwnerEthHexStr} - // evmOwner(Buffer.toString('hex')): ${evmOwner.toString('hex')} - // evmTargetTokenAddrEthHexStr: ${evmTargetTokenAddrEthHexStr} - // evmTargetTokenAddr(Buffer.toString('hex')): ${evmTargetTokenAddr.toString('hex')} - // `); - // console.info(`swimPayload:\n${JSON.stringify(swimPayload)}`); - // const transferAmountBuffer = transferAmount.toBuffer('be'); - // console.info(`transferAmountBufferHexStr: ${transferAmountBuffer.toString('hex')}`); + await checkTxnLogsForMemo(propellerTransferNativeTxnSig, memo); }); it("calls propellerTransferNativeWithPayload without memo", async () => { @@ -1852,11 +1816,11 @@ describe("propeller", () => { const wormholeMessage = web3.Keypair.generate(); const gasKickstart = false; const maxFee = new BN(100_000); - const nonceBefore = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; + const nonce = createNonce().readUInt32LE(0); + const propellerTransferNativeTxn = await propellerProgram.methods .propellerTransferNativeWithPayload( + nonce, transferAmount, CHAIN_ID_ETH, evmOwner, @@ -1898,10 +1862,6 @@ describe("propeller", () => { rpcCommitmentConfig, ); - const nonceAfter = ( - await propellerProgram.account.propeller.fetch(propeller) - ).nonce; - expect(nonceAfter).toEqual(nonceBefore + 1); const transferNativeTxnSize = propellerTransferNativeTxn.serialize().length; console.info(`transferNativeTxnSize txnSize: ${transferNativeTxnSize}`); @@ -1971,37 +1931,13 @@ describe("propeller", () => { 2, )}`, ); - expect(tokenTransferMessage.core.nonce).toEqual(nonceBefore); expect(swimPayload.owner).toEqual(evmOwner); expect(swimPayload.propellerEnabled).toEqual(true); expect(swimPayload.gasKickstart).toEqual(gasKickstart); expect(swimPayload.maxFee).toEqual(maxFee); expect(swimPayload.targetTokenId).toEqual(evmTargetTokenId); expect(swimPayload.memo).toBeUndefined(); - await checkTxnLogsForMemo( - transferNativeTxnSig, - memo.toString("hex"), - false, - ); - // this fails due to capitalization - // expect(formattedTokenTransferMessage.tokenTransfer.to).to.equal(ethRoutingContractStr); - // console.info(` - // tokenTransferMessage: ${JSON.stringify(tokenTransferMessage, null ,2)} - // `) - // console.info(`postedMessage:\n${JSON.stringify(postedMessage)}`); - // console.info(`postedMessagePayload:\n${JSON.stringify(postedMessagePayload)}`); - // const { - // payload: swimPayload - // } = postedMessagePayload; - // console.info(` - // evmOwnerEthHexStr: ${evmOwnerEthHexStr} - // evmOwner(Buffer.toString('hex')): ${evmOwner.toString('hex')} - // evmTargetTokenAddrEthHexStr: ${evmTargetTokenAddrEthHexStr} - // evmTargetTokenAddr(Buffer.toString('hex')): ${evmTargetTokenAddr.toString('hex')} - // `); - // console.info(`swimPayload:\n${JSON.stringify(swimPayload)}`); - // const transferAmountBuffer = transferAmount.toBuffer('be'); - // console.info(`transferAmountBufferHexStr: ${transferAmountBuffer.toString('hex')}`); + await checkTxnLogsForMemo(transferNativeTxnSig, memo, false); }); it("Fails propellerTransferNativeWithPayload if transferAmount <= maxFee for targetChain", async () => { @@ -2010,9 +1946,11 @@ describe("propeller", () => { const wormholeMessage = web3.Keypair.generate(); const gasKickstart = false; const maxFee = transferAmount.add(new BN(1)); + const nonce = createNonce().readUInt32LE(0); await expect(() => { return propellerProgram.methods .propellerTransferNativeWithPayload( + nonce, transferAmount, CHAIN_ID_ETH, evmOwner, @@ -2068,46 +2006,15 @@ describe("propeller", () => { const swimPayload = { version: swimPayloadVersion, owner: provider.publicKey.toBuffer(), - // owner: owner.toBuffer(), - // propellerEnabled, - // gasKickstart, - // maxFee, - // targetTokenId, - // memo: memoBuffer, }; - // - // const swimPayload = { - // version: swimPayloadVersion, - // targetTokenId, - // owner: provider.publicKey.toBuffer(), - // memo: memoBuffer, - // propellerEnabled, - // gasKickstart, - // }; + const amount = parseUnits("1", mintDecimal); console.info(`amount: ${amount.toString()}`); - /** - * this is encoding a token transfer from eth routing contract - * with a swimUSD token address that originated on solana - * the same as initializing a `TransferWrappedWithPayload` from eth - */ - - const nonce = createNonce().readUInt32LE(0); - const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( - 0, - nonce, - CHAIN_ID_ETH as number, - ethTokenBridge, - BigInt(++ethTokenBridgeSequence), - encodeTokenTransferWithPayload( + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( amount.toString(), - swimUsdKeypair.publicKey.toBuffer(), - CHAIN_ID_SOLANA, - propellerProgram.programId, - ethRoutingContract, - encodeSwimPayload(swimPayload), - ), - ); + swimPayload, + ); const propellerRedeemerEscrowAccountBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) ).amount; @@ -2159,7 +2066,6 @@ describe("propeller", () => { tokenTransferWithPayloadSignedVaa, ); - const completeNativeWithPayloadIxs = propellerProgram.methods .completeNativeWithPayload() .accounts({ @@ -2236,17 +2142,16 @@ describe("propeller", () => { expect(swimPayloadMessageAccount.bump).toEqual( expectedSwimPayloadMessageBump, ); - // expect(swimPayloadMessageAccount.whMessage).toEqual(wormholeMessage); expect(swimPayloadMessageAccount.claim).toEqual(wormholeClaim); expect( Buffer.from(swimPayloadMessageAccount.vaaEmitterAddress), - ).toEqual(ethTokenBridge); + ).toEqual(dummyEthTokenBridge.emitterAddress); expect(swimPayloadMessageAccount.vaaEmitterChain).toEqual( - CHAIN_ID_ETH, + dummyEthTokenBridge.emitterChain, ); expect( swimPayloadMessageAccount.vaaSequence.eq( - new BN(ethTokenBridgeSequence), + new BN(dummyEthTokenBridge.sequence), ), ).toBeTruthy(); expect( @@ -2254,14 +2159,7 @@ describe("propeller", () => { new BN(amount.toString()), ), ).toBeTruthy(); - // const { - // swimPayloadVersion, - // targetTokenId, - // owner, - // memo, - // propellerEnabled, - // gasKickstart - // } = swimPayloadMessageAccount.swimPayload; + expect(swimPayloadMessageAccount.swimPayloadVersion).toEqual( swimPayloadVersion, ); @@ -2367,21 +2265,13 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await processSwimPayloadIxs.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountTargetTokenId, propellerProgram.programId, ); @@ -2391,14 +2281,16 @@ describe("propeller", () => { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenIdMap, + ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -2477,28 +2369,12 @@ describe("propeller", () => { const amount = parseUnits("1", mintDecimal); console.info(`amount: ${amount.toString()}`); - /** - * this is encoding a token transfer from eth routing contract - * with a swimUSD token address that originated on solana - * the same as initializing a `TransferWrappedWithPayload` from eth - */ - const nonce = createNonce().readUInt32LE(0); - const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( - 0, - nonce, - CHAIN_ID_ETH as number, - ethTokenBridge, - BigInt(++ethTokenBridgeSequence), - encodeTokenTransferWithPayload( + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( amount.toString(), - swimUsdKeypair.publicKey.toBuffer(), - CHAIN_ID_SOLANA, - propellerProgram.programId, - ethRoutingContract, - encodeSwimPayload(swimPayload), - ), - ); + swimPayload, + ); const propellerRedeemerEscrowAccountBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) ).amount; @@ -2614,13 +2490,13 @@ describe("propeller", () => { expect(swimPayloadMessageAccount.claim).toEqual(wormholeClaim); expect( Buffer.from(swimPayloadMessageAccount.vaaEmitterAddress), - ).toEqual(ethTokenBridge); + ).toEqual(dummyEthTokenBridge.emitterAddress); expect(swimPayloadMessageAccount.vaaEmitterChain).toEqual( - CHAIN_ID_ETH, + dummyEthTokenBridge.emitterChain, ); expect( swimPayloadMessageAccount.vaaSequence.eq( - new BN(ethTokenBridgeSequence), + new BN(dummyEthTokenBridge.sequence), ), ).toBeTruthy(); expect( @@ -2696,7 +2572,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -2739,39 +2615,32 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); - const expectedTokenIdMap = outputTokenIdMappingAddrs.get(targetTokenId); if (!expectedTokenIdMap) { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenIdMap, + ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -2844,7 +2713,7 @@ describe("propeller", () => { let wormholeClaim: web3.PublicKey; let wormholeMessage: web3.PublicKey; let swimPayloadMessage: web3.PublicKey; - const targetTokenId = metapoolMint1OutputTokenIndex; + const targetTokenId = metapoolMint1ToTokenNumber; const memoStr = createMemoId(); // const memo = "e45794d6c5a2750b"; @@ -2856,28 +2725,12 @@ describe("propeller", () => { const amount = parseUnits("1", mintDecimal); console.info(`amount: ${amount.toString()}`); - /** - * this is encoding a token transfer from eth routing contract - * with a swimUSD token address that originated on solana - * the same as initializing a `TransferWrappedWithPayload` from eth - */ - const nonce = createNonce().readUInt32LE(0); - const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( - 0, - nonce, - CHAIN_ID_ETH as number, - ethTokenBridge, - BigInt(++ethTokenBridgeSequence), - encodeTokenTransferWithPayload( + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( amount.toString(), - swimUsdKeypair.publicKey.toBuffer(), - CHAIN_ID_SOLANA, - propellerProgram.programId, - ethRoutingContract, - encodeSwimPayload(swimPayload), - ), - ); + swimPayload, + ); const propellerRedeemerEscrowAccountBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) ).amount; @@ -2992,13 +2845,13 @@ describe("propeller", () => { expect(swimPayloadMessageAccount.claim).toEqual(wormholeClaim); expect( Buffer.from(swimPayloadMessageAccount.vaaEmitterAddress), - ).toEqual(ethTokenBridge); + ).toEqual(dummyEthTokenBridge.emitterAddress); expect(swimPayloadMessageAccount.vaaEmitterChain).toEqual( - CHAIN_ID_ETH, + dummyEthTokenBridge.emitterChain, ); expect( swimPayloadMessageAccount.vaaSequence.eq( - new BN(ethTokenBridgeSequence), + new BN(dummyEthTokenBridge.sequence), ), ).toBeTruthy(); expect( @@ -3067,7 +2920,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -3110,21 +2963,13 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); @@ -3134,14 +2979,16 @@ describe("propeller", () => { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenIdMap, + ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -3251,21 +3098,26 @@ describe("propeller", () => { */ const nonce = createNonce().readUInt32LE(0); - const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( - 0, - nonce, - CHAIN_ID_ETH as number, - ethTokenBridge, - BigInt(++ethTokenBridgeSequence), - encodeTokenTransferWithPayload( + // const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( + // 0, + // nonce, + // CHAIN_ID_ETH as number, + // ethTokenBridge, + // BigInt(++ethTokenBridgeSequence), + // encodeTokenTransferWithPayload( + // amount.toString(), + // swimUsdKeypair.publicKey.toBuffer(), + // CHAIN_ID_SOLANA, + // propellerProgram.programId, + // ethRoutingContract, + // encodeSwimPayload(swimPayload), + // ), + // ); + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( amount.toString(), - swimUsdKeypair.publicKey.toBuffer(), - CHAIN_ID_SOLANA, - propellerProgram.programId, - ethRoutingContract, - encodeSwimPayload(swimPayload), - ), - ); + swimPayload, + ); const propellerRedeemerEscrowAccountBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) ).amount; @@ -3382,13 +3234,13 @@ describe("propeller", () => { expect(swimPayloadMessageAccount.claim).toEqual(wormholeClaim); expect( Buffer.from(swimPayloadMessageAccount.vaaEmitterAddress), - ).toEqual(ethTokenBridge); + ).toEqual(dummyEthTokenBridge.emitterAddress); expect(swimPayloadMessageAccount.vaaEmitterChain).toEqual( - CHAIN_ID_ETH, + dummyEthTokenBridge.emitterChain, ); expect( swimPayloadMessageAccount.vaaSequence.eq( - new BN(ethTokenBridgeSequence), + new BN(dummyEthTokenBridge.sequence), ), ).toBeTruthy(); expect( @@ -3464,7 +3316,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -3507,21 +3359,14 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await processSwimPayloadIxs.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } + const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); @@ -3531,14 +3376,16 @@ describe("propeller", () => { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenIdMap, + ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -3639,21 +3486,26 @@ describe("propeller", () => { */ const nonce = createNonce().readUInt32LE(0); - const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( - 0, - nonce, - CHAIN_ID_ETH as number, - ethTokenBridge, - BigInt(++ethTokenBridgeSequence), - encodeTokenTransferWithPayload( + // const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( + // 0, + // nonce, + // CHAIN_ID_ETH as number, + // ethTokenBridge, + // BigInt(++ethTokenBridgeSequence), + // encodeTokenTransferWithPayload( + // amount.toString(), + // swimUsdKeypair.publicKey.toBuffer(), + // CHAIN_ID_SOLANA, + // propellerProgram.programId, + // ethRoutingContract, + // encodeSwimPayload(swimPayload), + // ), + // ); + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( amount.toString(), - swimUsdKeypair.publicKey.toBuffer(), - CHAIN_ID_SOLANA, - propellerProgram.programId, - ethRoutingContract, - encodeSwimPayload(swimPayload), - ), - ); + swimPayload, + ); const propellerRedeemerEscrowAccountBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) ).amount; @@ -3788,13 +3640,13 @@ describe("propeller", () => { expect(swimPayloadMessageAccount.claim).toEqual(wormholeClaim); expect( Buffer.from(swimPayloadMessageAccount.vaaEmitterAddress), - ).toEqual(ethTokenBridge); + ).toEqual(dummyEthTokenBridge.emitterAddress); expect(swimPayloadMessageAccount.vaaEmitterChain).toEqual( - CHAIN_ID_ETH, + dummyEthTokenBridge.emitterChain, ); expect( swimPayloadMessageAccount.vaaSequence.eq( - new BN(ethTokenBridgeSequence), + new BN(dummyEthTokenBridge.sequence), ), ).toBeTruthy(); expect( @@ -3870,7 +3722,7 @@ describe("propeller", () => { await propellerProgram.account.swimPayloadMessage.fetch( swimPayloadMessage, ); - const swimPayloadMessageAccountTargetTokenId = + const swimPayloadMessageAccountToTokenNumber = swimPayloadMessageAccount.targetTokenId; const propellerRedeemerEscrowBalanceBefore = ( await splToken.account.token.fetch(propellerRedeemerEscrowAccount) @@ -3913,22 +3765,14 @@ describe("propeller", () => { const processSwimPayloadPubkeys = await processSwimPayload.pubkeys(); console.info(`${JSON.stringify(processSwimPayloadPubkeys, null, 2)}`); - if (!processSwimPayloadPubkeys.tokenIdMap) { + if (!processSwimPayloadPubkeys.tokenNumberMap) { throw new Error("tokenIdMap not derived"); } const [calculatedTokenIdMap, calculatedTokenIdMapBump] = - await web3.PublicKey.findProgramAddress( - [ - Buffer.from("propeller"), - Buffer.from("token_id"), - propeller.toBuffer(), - new BN(swimPayloadMessageAccountTargetTokenId).toArrayLike( - Buffer, - "le", - 2, - ), - ], + await getToTokenNumberMapAddr( + propeller, + swimPayloadMessageAccountToTokenNumber, propellerProgram.programId, ); @@ -3938,14 +3782,16 @@ describe("propeller", () => { throw new Error("expectedTokenIdMap not found"); } const expectedTokenIdMapAcct = - await propellerProgram.account.tokenIdMap.fetch(expectedTokenIdMap); + await propellerProgram.account.tokenNumberMap.fetch( + expectedTokenIdMap, + ); console.info(` calculatedTokenIdMap: ${calculatedTokenIdMap.toBase58()} calculatedTokenIdMapBump: ${calculatedTokenIdMapBump} expectedTokenIdMapAcct: ${expectedTokenIdMap.toBase58()} : ${JSON.stringify(expectedTokenIdMapAcct, null, 2)} `); - const derivedTokenIdMap = processSwimPayloadPubkeys.tokenIdMap; + const derivedTokenIdMap = processSwimPayloadPubkeys.tokenNumberMap; expect(derivedTokenIdMap).toEqual(expectedTokenIdMap); if (!processSwimPayloadPubkeys.swimClaim) { throw new Error("swimClaim key not derived"); @@ -4016,9 +3862,537 @@ describe("propeller", () => { }); }); + describe("Updating/Closing Token Number Maps", () => { + let newMetapool: web3.PublicKey; + let newMetapoolToken0Ata: web3.PublicKey; + let newMetapoolToken1Ata: web3.PublicKey; + const newMetapoolLpMintKeypair = web3.Keypair.generate(); + let newMetapoolGovernanceFeeAta: web3.PublicKey; + let userNewMetapoolLpTokenAta: web3.PublicKey; + + // intiialize new metapool with same token_mint_keys as previous metapool but new lp token + beforeAll(async () => { + ({ + poolPubkey: newMetapool, + poolTokenAccounts: [newMetapoolToken0Ata, newMetapoolToken1Ata], + governanceFeeAccount: newMetapoolGovernanceFeeAta, + } = await setupPoolPrereqs( + twoPoolProgram, + splToken, + metapoolMintKeypairs, + metapoolMintDecimals, + [flagshipPool, metapoolMint1Authority.publicKey], + newMetapoolLpMintKeypair.publicKey, + poolGovernanceKeypair.publicKey, + )); + + await twoPoolProgram.methods + .initialize(ampFactor, lpFee, governanceFee) + .accounts({ + payer: provider.publicKey, + poolMint0: metapoolMintKeypairs[0].publicKey, + poolMint1: metapoolMintKeypairs[1].publicKey, + lpMint: newMetapoolLpMintKeypair.publicKey, + poolTokenAccount0: newMetapoolToken0Ata, + poolTokenAccount1: newMetapoolToken1Ata, + pauseKey: poolPauseKeypair.publicKey, + governanceAccount: poolGovernanceKeypair.publicKey, + governanceFeeAccount: newMetapoolGovernanceFeeAta, + tokenProgram: splToken.programId, + associatedTokenProgram: splAssociatedToken.programId, + systemProgram: web3.SystemProgram.programId, + rent: web3.SYSVAR_RENT_PUBKEY, + }) + .signers([newMetapoolLpMintKeypair]) + .rpc(); + const newMetapoolData = await twoPoolProgram.account.twoPool.fetch( + newMetapool, + ); + console.info(` + newMetapool: ${newMetapool.toBase58()} + newMetapoolData: ${JSON.stringify(newMetapoolData, null, 2)} + `); + console.info("seeding new metapool"); + userNewMetapoolLpTokenAta = ( + await getOrCreateAssociatedTokenAccount( + connection, + payer, + newMetapoolLpMintKeypair.publicKey, + dummyUser.publicKey, + ) + ).address; + const uiInputAmounts: readonly BN[] = [new BN(2_000), new BN(1_500)]; + const inputAmounts: readonly BN[] = uiInputAmounts.map( + (bn: BN, i: number) => { + const powerOfTen = new BN(10).pow(new BN(metapoolMintDecimals[i])); + return bn.mul(powerOfTen); + }, + ); + const minimumMintAmount = new BN(0); + // const addParams = { + // inputAmounts, + // minimumMintAmount, + // }; + const userTransferAuthority = web3.Keypair.generate(); + const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( + splToken, + [userMetapoolTokenAccount0, userMetapoolTokenAccount1], + inputAmounts, + userTransferAuthority.publicKey, + payer, + ); + const seedNewMetapoolTxn = await twoPoolProgram.methods + .add(inputAmounts, minimumMintAmount) + .accounts({ + // propeller: propeller, + poolTokenAccount0: newMetapoolToken0Ata, + poolTokenAccount1: newMetapoolToken1Ata, + lpMint: newMetapoolLpMintKeypair.publicKey, + governanceFee: newMetapoolGovernanceFeeAta, + userTransferAuthority: userTransferAuthority.publicKey, + userTokenAccount0: userMetapoolTokenAccount0, + userTokenAccount1: userMetapoolTokenAccount1, + userLpTokenAccount: userNewMetapoolLpTokenAta, + tokenProgram: splToken.programId, + }) + .preInstructions([...approveIxs]) + .postInstructions([...revokeIxs]) + .signers([userTransferAuthority]) + .rpc(); + + console.info(`seedNewMetapoolTxn: ${seedNewMetapoolTxn}`); + const newMetapoolTokenAccountAmounts = ( + await Promise.all( + newMetapoolData.tokenKeys.map(async (key) => { + return await splToken.account.token.fetch(key); + }), + ) + ).map((account) => account.amount.toString()); + + console.info(` + newMetapoolTokenAccountAmounts: ${newMetapoolTokenAccountAmounts.toString()} + `); + // seed new metapool + // await twoPoolProgram.methods.add().accounts({}).rpc(); + }); + + it("Can update a token number map", async () => { + const [tokenNumberMapAddr] = await getToTokenNumberMapAddr( + propeller, + metapoolMint1ToTokenNumber, + propellerProgram.programId, + ); + const tokenNumberMapDataBefore = + await propellerProgram.account.tokenNumberMap.fetch(tokenNumberMapAddr); + expect(tokenNumberMapDataBefore.toTokenNumber).toEqual( + metapoolMint1ToTokenNumber, + ); + expect(tokenNumberMapDataBefore.poolTokenMint).toEqual( + metapoolMintKeypairs[1].publicKey, + ); + expect(tokenNumberMapDataBefore.pool).toEqual(metapool); + expect(tokenNumberMapDataBefore.poolTokenIndex).toEqual(1); + const poolTokenIndex = 1; + const poolTokenMint = metapoolMint1Keypair.publicKey; + const toTokenStep = { swapExactInput: {} }; + await propellerProgram.methods + .updateTokenNumberMap( + metapoolMint1ToTokenNumber, + poolTokenIndex, + poolTokenMint, + toTokenStep, + ) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + // rent: web3.SYSVAR_RENT_PUBKEY, + pool: newMetapool, + twoPoolProgram: twoPoolProgram.programId, + }) + .signers([propellerGovernanceKey]) + .rpc(); + // create new metapool with same metapoolMint1 + + const tokenNumberMapDataAfter = + await propellerProgram.account.tokenNumberMap.fetch(tokenNumberMapAddr); + expect(tokenNumberMapDataAfter.toTokenNumber).toEqual( + metapoolMint1ToTokenNumber, + ); + expect(tokenNumberMapDataAfter.poolTokenMint).toEqual( + metapoolMintKeypairs[1].publicKey, + ); + expect(tokenNumberMapDataAfter.pool).toEqual(newMetapool); + expect(tokenNumberMapDataAfter.poolTokenIndex).toEqual(1); + + const oldMetapoolTokenAccountBalancesBefore = + await getPoolTokenAccountBalances(metapool, twoPoolProgram, splToken); + + const newMetapoolTokenAccountBalancesBefore = + await getPoolTokenAccountBalances( + newMetapool, + twoPoolProgram, + splToken, + ); + + // + + const targetTokenId = metapoolMint1ToTokenNumber; + const memoStr = createMemoId(); + + const swimPayload = { + version: swimPayloadVersion, + owner: provider.publicKey.toBuffer(), + }; + + const amount = parseUnits("1", mintDecimal); + console.info(`amount: ${amount.toString()}`); + /** + * this is encoding a token transfer from eth routing contract + * with a swimUSD token address that originated on solana + * the same as initializing a `TransferWrappedWithPayload` from eth + */ + + const nonce = createNonce().readUInt32LE(0); + // const tokenTransferWithPayloadSignedVaa = signAndEncodeVaa( + // 0, + // nonce, + // CHAIN_ID_ETH as number, + // ethTokenBridge, + // BigInt(++ethTokenBridgeSequence), + // encodeTokenTransferWithPayload( + // amount.toString(), + // swimUsdKeypair.publicKey.toBuffer(), + // CHAIN_ID_SOLANA, + // propellerProgram.programId, + // ethRoutingContract, + // encodeSwimPayload(swimPayload), + // ), + // ); + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( + amount.toString(), + swimPayload, + ); + const propellerRedeemerEscrowAccountBefore = ( + await splToken.account.token.fetch(propellerRedeemerEscrowAccount) + ).amount; + + const newMetapoolUserAtaBalancesBefore = await getUserAtaBalancesForPool( + dummyUser.publicKey, + newMetapool, + twoPoolProgram, + splToken, + ); + + await postVaaSolanaWithRetry( + connection, + async (tx) => { + return provider.wallet.signTransaction(tx); + }, + WORMHOLE_CORE_BRIDGE.toBase58(), + payer.publicKey.toBase58(), + tokenTransferWithPayloadSignedVaa, + 10, + ); + + const [wormholeMessage] = await deriveMessagePda( + tokenTransferWithPayloadSignedVaa, + WORMHOLE_CORE_BRIDGE, + ); + + const [endpointAccount] = await deriveEndpointPda( + CHAIN_ID_ETH, + ethTokenBridge, + // parsedVaa.emitterChain, + // parsedVaa.emitterAddress, + WORMHOLE_TOKEN_BRIDGE, + ); + console.info(`endpointAccount: ${endpointAccount.toBase58()}`); + const wormholeClaim = await getClaimAddressSolana( + WORMHOLE_TOKEN_BRIDGE.toBase58(), + tokenTransferWithPayloadSignedVaa, + ); + + const completeNativeWithPayloadMetapoolIxs = propellerProgram.methods + .completeNativeWithPayload() + .accounts({ + propeller, + payer: payer.publicKey, + tokenBridgeConfig, + // userTokenBridgeAccount: userLpTokenAccount.address, + message: wormholeMessage, + claim: wormholeClaim, + endpoint: endpointAccount, + redeemerEscrow: propellerRedeemerEscrowAccount, + redeemer: propellerRedeemer, + feeVault: propellerFeeVault, + custody: custody, + swimUsdMint: swimUsdMint, + custodySigner, + rent: web3.SYSVAR_RENT_PUBKEY, + systemProgram: web3.SystemProgram.programId, + wormhole, + tokenProgram: splToken.programId, + tokenBridge, + }) + .preInstructions([setComputeUnitLimitIx]) + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]); + + const completeNativeWithPayloadMetapoolPubkeys = + await completeNativeWithPayloadMetapoolIxs.pubkeys(); + + if (!completeNativeWithPayloadMetapoolPubkeys.swimPayloadMessage) { + throw new Error("swimPayloadMessage key not derived"); + } + + const swimPayloadMessage = + completeNativeWithPayloadMetapoolPubkeys.swimPayloadMessage; + + const completeNativeWithPayloadMetapoolTxn = + await completeNativeWithPayloadMetapoolIxs.transaction(); + const transferNativeTxnSig = await provider.sendAndConfirm( + completeNativeWithPayloadMetapoolTxn, + [payer], + { + skipPreflight: true, + }, + ); + + const swimPayloadMessageAccount = + await propellerProgram.account.swimPayloadMessage.fetch( + completeNativeWithPayloadMetapoolPubkeys.swimPayloadMessage, + ); + + await connection.confirmTransaction({ + signature: transferNativeTxnSig, + ...(await connection.getLatestBlockhash()), + }); + + const propellerRedeemerEscrowAccountAfter = ( + await splToken.account.token.fetch(propellerRedeemerEscrowAccount) + ).amount; + + expect( + propellerRedeemerEscrowAccountAfter.gt( + propellerRedeemerEscrowAccountBefore, + ), + ).toEqual(true); + await checkTxnLogsForMemo(transferNativeTxnSig, memoStr); + + const minOutputAmount = new BN(0); + await propellerProgram.methods + .processSwimPayload(targetTokenId, minOutputAmount) + .accounts({ + propeller, + payer: payer.publicKey, + claim: wormholeClaim, + swimPayloadMessage, + swimPayloadMessagePayer: + swimPayloadMessageAccount.swimPayloadMessagePayer, + redeemer: propellerRedeemer, + redeemerEscrow: propellerRedeemerEscrowAccount, + // tokenIdMap: ? + pool: newMetapool, + poolTokenAccount0: newMetapoolToken0Ata, + poolTokenAccount1: newMetapoolToken1Ata, + lpMint: newMetapoolLpMintKeypair.publicKey, + governanceFee: newMetapoolGovernanceFeeAta, + userTokenAccount0: userMetapoolTokenAccount0, + userTokenAccount1: userMetapoolTokenAccount1, + userLpTokenAccount: userNewMetapoolLpTokenAta, + tokenProgram: splToken.programId, + twoPoolProgram: twoPoolProgram.programId, + systemProgram: web3.SystemProgram.programId, + }) + .preInstructions([setComputeUnitLimitIx]) + .postInstructions([createMemoInstruction(memoStr.toString("hex"))]) + .rpc(); + + const oldMetapoolTokenAccountBalancesAfter = + await getPoolTokenAccountBalances(metapool, twoPoolProgram, splToken); + + const newMetapoolTokenAccountBalancesAfter = + await getPoolTokenAccountBalances( + newMetapool, + twoPoolProgram, + splToken, + ); + + expect( + oldMetapoolTokenAccountBalancesAfter[0].eq( + oldMetapoolTokenAccountBalancesBefore[0], + ), + ).toBeTruthy(); + expect( + oldMetapoolTokenAccountBalancesAfter[1].eq( + oldMetapoolTokenAccountBalancesBefore[1], + ), + ).toBeTruthy(); + expect( + newMetapoolTokenAccountBalancesAfter[0].gt( + newMetapoolTokenAccountBalancesBefore[0], + ), + ).toBeTruthy(); + expect( + newMetapoolTokenAccountBalancesAfter[1].lt( + newMetapoolTokenAccountBalancesBefore[1], + ), + ).toBeTruthy(); + + const newMetapoolUserAtaBalancesAfter = await getUserAtaBalancesForPool( + dummyUser.publicKey, + newMetapool, + twoPoolProgram, + splToken, + ); + + expect( + newMetapoolUserAtaBalancesBefore[0].eq( + newMetapoolUserAtaBalancesAfter[0], + ), + ).toBeTruthy(); + // should have received metapool token 1 + expect( + newMetapoolUserAtaBalancesBefore[1].lt( + newMetapoolUserAtaBalancesAfter[1], + ), + ).toBeTruthy(); + expect( + newMetapoolUserAtaBalancesBefore[2].eq( + newMetapoolUserAtaBalancesAfter[2], + ), + ).toBeTruthy(); + }); + it("Can close and re-create a token number map", async () => { + const [tokenNumberMapAddr] = await getToTokenNumberMapAddr( + propeller, + metapoolMint1ToTokenNumber, + propellerProgram.programId, + ); + await propellerProgram.methods + .closeTokenNumberMap(metapoolMint1ToTokenNumber) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + tokenNumberMap: tokenNumberMapAddr, + }) + .signers([propellerGovernanceKey]) + .rpc(); + const tokenNumberMapDataAfterClose = + await propellerProgram.account.tokenNumberMap.fetchNullable( + tokenNumberMapAddr, + ); + expect(tokenNumberMapDataAfterClose).toBeNull(); + + const swimPayload = { + version: swimPayloadVersion, + owner: provider.publicKey.toBuffer(), + }; + + const amount = parseUnits("1", mintDecimal); + console.info(`amount: ${amount.toString()}`); + + const tokenTransferWithPayloadSignedVaa = + dummyEthTokenBridge.createSignedTokenTransferWithSwimPayloadVAA( + amount.toString(), + swimPayload, + ); + await postVaaToSolana( + tokenTransferWithPayloadSignedVaa, + provider, + wormhole, + ); + + const completeNativeWithPayloadTxn = + await getCompleteNativeWithPayloadTxn( + tokenTransferWithPayloadSignedVaa, + wormhole, + tokenBridge, + propellerProgram, + ); + await provider.sendAndConfirm(completeNativeWithPayloadTxn); + + await expect(() => { + return getProcessSwimPayloadTxn( + metapoolMint1ToTokenNumber, + new BN(0), + tokenTransferWithPayloadSignedVaa, + wormhole, + tokenBridge, + propellerProgram, + twoPoolProgram, + splToken, + ); + }).rejects.toThrow("Token number map does not exist"); + + //recreate tokenNumberMap with original metapool + const metapoolMint1TokenNumberMap = { + pool: metapool, + poolTokenIndex: metapoolMint1PoolTokenIndex, + poolTokenMint: metapoolMint1Keypair.publicKey, + toTokenStep: { swapExactInput: {} }, + }; + + await propellerProgram.methods + .createTokenNumberMap( + metapoolMint1ToTokenNumber, + metapoolMint1TokenNumberMap.pool, + metapoolMint1TokenNumberMap.poolTokenIndex, + metapoolMint1TokenNumberMap.poolTokenMint, + metapoolMint1TokenNumberMap.toTokenStep, + ) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + systemProgram: web3.SystemProgram.programId, + // rent: web3.SYSVAR_RENT_PUBKEY, + pool: metapool, + twoPoolProgram: twoPoolProgram.programId, + }) + .signers([propellerGovernanceKey]) + .rpc(); + + const tokenNumberMapDataAfterRecreate = + await propellerProgram.account.tokenNumberMap.fetch(tokenNumberMapAddr); + expect(tokenNumberMapDataAfterRecreate.pool.toBase58()).toEqual( + metapool.toBase58(), + ); + const originalMetapoolAtaBalancesBefore = + await getPoolTokenAccountBalances(metapool, twoPoolProgram, splToken); + const processSwimPayloadTxn = await getProcessSwimPayloadTxn( + metapoolMint1ToTokenNumber, + new BN(0), + tokenTransferWithPayloadSignedVaa, + wormhole, + tokenBridge, + propellerProgram, + twoPoolProgram, + splToken, + ); + await provider.sendAndConfirm(processSwimPayloadTxn); + const originalMetapoolAtaBalancesAfter = + await getPoolTokenAccountBalances(metapool, twoPoolProgram, splToken); + //original metapool token[0] (swimUSD) balance should go up + expect( + originalMetapoolAtaBalancesAfter[0].gt( + originalMetapoolAtaBalancesBefore[0], + ), + ).toBeTruthy(); + // pool token[1] balance should go down + expect( + originalMetapoolAtaBalancesAfter[1].lt( + originalMetapoolAtaBalancesBefore[1], + ), + ).toBeTruthy(); + }); // end of close/recreate token number map test + }); + async function checkTxnLogsForMemo( txSig: string, - memoStr: Buffer, + memoBuffer: Buffer, exists = true, ) { console.info(`txSig: ${txSig}`); @@ -4040,7 +4414,7 @@ describe("propeller", () => { const memoLogFound = txnLogs.some( (log) => log.startsWith("Program log: Memo") && - log.includes(memoStr.toString("hex")), + log.includes(memoBuffer.toString("hex")), ); expect(memoLogFound).toEqual(exists); } diff --git a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts index 06464d03c..cbf161da1 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts @@ -2,16 +2,20 @@ import type { ChainId, ChainName } from "@certusone/wormhole-sdk"; import { CHAIN_ID_BSC, CHAIN_ID_ETH, + CHAIN_ID_SOLANA, + createNonce, getClaimAddressSolana, - tryHexToNativeString, + postVaaSolanaWithRetry, + tryNativeToHexString, tryUint8ArrayToNative, } from "@certusone/wormhole-sdk"; -import type { Program, SplToken } from "@project-serum/anchor"; +import type { AnchorProvider, Program, SplToken } from "@project-serum/anchor"; import { BN, web3 } from "@project-serum/anchor"; import { MEMO_PROGRAM_ID, createMemoInstruction } from "@solana/spl-memo"; import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, + createAssociatedTokenAccountInstruction, getAssociatedTokenAddress, } from "@solana/spl-token"; import { BigNumber } from "ethers"; @@ -19,6 +23,7 @@ import { BigNumber } from "ethers"; import type { Propeller } from "../../artifacts/propeller"; import type { TwoPool } from "../../artifacts/two_pool"; import { setComputeUnitLimitIx } from "../consts"; +import { getOwnerAtaAddrsForPool } from "../twoPool/poolTestUtils"; import type { ParsedTokenTransferPostedMessage, @@ -27,11 +32,13 @@ import type { import { deriveEndpointPda, deriveMessagePda, + encodeTokenTransferWithPayload, formatParsedTokenTransferPostedMessage, formatParsedTokenTransferSignedVaa, parseTokenTransferPostedMessage, parseTokenTransferSignedVaa, } from "./tokenBridgeUtils"; +import { signAndEncodeVaa } from "./wormholeUtils"; export async function getPropellerPda( mint: web3.PublicKey, @@ -433,14 +440,20 @@ export const formatSwimPayload = ( swimPayload: ParsedSwimPayload, chain: ChainId | ChainName, ) => { - return { + const formattedBaseSwimPayload = { ...swimPayload, - // minOutputAmount: swimPayload.minOutputAmount.toString(), - memo: swimPayload.memo !== undefined ? swimPayload.memo.toString() : "", - // minThreshold: swimPayload.minThreshold.toString(), owner: tryUint8ArrayToNative(swimPayload.owner, chain), - maxFee: - swimPayload.maxFee !== undefined ? swimPayload.maxFee.toString() : "", + }; + const formattedMemo = swimPayload.memo + ? { memo: swimPayload.memo.toString() } + : {}; + const formattedMaxFee = swimPayload.maxFee + ? { maxFee: swimPayload.maxFee.toString() } + : {}; + return { + ...formattedBaseSwimPayload, + ...formattedMemo, + ...formattedMaxFee, }; }; @@ -478,17 +491,17 @@ export const formatParsedTokenTransferWithSwimPayloadPostedMessage = ( }; }; -export const getTargetTokenIdMapAddr = async ( - propeller: web3.PublicKey, - targetTokenId: number, +export const getToTokenNumberMapAddr = async ( + propellerState: web3.PublicKey, + toTokenNumber: number, propellerProgramId: web3.PublicKey, ) => { return await web3.PublicKey.findProgramAddress( [ Buffer.from("propeller"), Buffer.from("token_id"), - propeller.toBuffer(), - new BN(targetTokenId).toArrayLike(Buffer, "le", 2), + propellerState.toBuffer(), + new BN(toTokenNumber).toArrayLike(Buffer, "le", 2), ], propellerProgramId, ); @@ -644,20 +657,6 @@ export const generatePropellerEngineTxns = async ( tokenTransferWithPayloadSignedVaa, ); - //TODO: https://solanacookbook.com/references/basic-transactions.html#how-to-change-compute-budget-fee-priority-for-a-transaction - // const modifyComputeUnits = web3.ComputeBudgetProgram.setComputeUnitLimit({ - // units: 900000 - // }); - // - // const addPriorityFee = web3.ComputeBudgetProgram.setComputeUnitPrice({ - // microLamports: 1 - // }); - - const requestUnitsIx = web3.ComputeBudgetProgram.requestUnits({ - // units: 420690, - units: 900000, - additionalFee: 0, - }); const propellerData = await propellerProgram.account.propeller.fetch( propeller, ); @@ -713,7 +712,7 @@ export const generatePropellerEngineTxns = async ( twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) - .preInstructions([requestUnitsIx]) + .preInstructions([setComputeUnitLimitIx]) .signers([payer]); const completeNativeWithPayloadPubkeys = @@ -729,17 +728,19 @@ export const generatePropellerEngineTxns = async ( const completeNativeWithPayloadTxn = await completeNativeWithPayloadIxs.transaction(); txns = [completeNativeWithPayloadTxn]; - const targetTokenId = swimPayload.targetTokenId; - if (!targetTokenId) { + const toTokenNumber = swimPayload.targetTokenId; + if (!toTokenNumber) { throw new Error("No target token id"); } - const [tokenIdMapAddr] = await getTargetTokenIdMapAddr( + const [tokenNumberMapAddr] = await getToTokenNumberMapAddr( propeller, - targetTokenId, + toTokenNumber, propellerProgram.programId, ); - const tokenIdMapData = - await propellerProgram.account.tokenIdMap.fetchNullable(tokenIdMapAddr); + const tokenNumberMapData = + await propellerProgram.account.tokenNumberMap.fetchNullable( + tokenNumberMapAddr, + ); const owner = new web3.PublicKey(swimPayload.owner); // const userTransferAuthority = web3.Keypair.generate(); const [swimClaim] = await getSwimClaimPda( @@ -747,9 +748,9 @@ export const generatePropellerEngineTxns = async ( propellerProgram.programId, ); - if (!tokenIdMapData) { + if (!tokenNumberMapData) { console.info( - `invalid tokenIdMap. targetTokenId: ${targetTokenId.toString()}. Generating fallback transactions`, + `invalid tokenNumberMap. toTokenNumber: ${toTokenNumber.toString()}. Generating fallback transactions`, ); const userSwimUsdAta: web3.PublicKey = await getAssociatedTokenAddress( @@ -771,7 +772,7 @@ export const generatePropellerEngineTxns = async ( feeTracker: propellerEngineFeeTracker, claim: wormholeClaim, swimPayloadMessage, - tokenIdMap: tokenIdMapAddr, + tokenIdMap: tokenNumberMapAddr, swimUsdMint: swimUsdMint, owner, ownerSwimUsdAta: userSwimUsdAta, @@ -803,7 +804,7 @@ export const generatePropellerEngineTxns = async ( swimPayloadMessagePayer: payer.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - tokenIdMap: tokenIdMapAddr, + tokenNumberMap: tokenNumberMapAddr, userSwimUsdAta: userSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, @@ -818,12 +819,12 @@ export const generatePropellerEngineTxns = async ( marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, owner, }) - .preInstructions([requestUnitsIx]) + .preInstructions([setComputeUnitLimitIx]) .signers([payer]) .transaction(); txns = [...txns, propellerProcessSwimPayloadFallbackTxn]; } else { - const tokenIdMapPoolAddr = tokenIdMapData.pool; + const tokenIdMapPoolAddr = tokenNumberMapData.pool; const tokenIdMapPoolData = await twoPoolProgram.account.twoPool.fetch( tokenIdMapPoolAddr, ); @@ -840,7 +841,7 @@ export const generatePropellerEngineTxns = async ( // return await getAssociatedTokenAddress(mint, owner); // }), // ); - const ownerAtaAddrs = await getOwnerTokenAccountsForPool( + const ownerAtaAddrs = await getOwnerAtaAddrsForPool( tokenIdMapPoolAddr, owner, twoPoolProgram, @@ -871,7 +872,7 @@ export const generatePropellerEngineTxns = async ( feeTracker: propellerEngineFeeTracker, claim: wormholeClaim, swimPayloadMessage, - tokenIdMap: tokenIdMapAddr, + tokenNumberMap: tokenNumberMapAddr, pool: tokenIdMapPoolInfo.pool, poolToken0Mint: tokenIdMapPoolInfo.tokenMints[0], poolToken1Mint: tokenIdMapPoolInfo.tokenMints[1], @@ -891,12 +892,12 @@ export const generatePropellerEngineTxns = async ( marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, twoPoolProgram: twoPoolProgram.programId, }) - .preInstructions([requestUnitsIx]) + .preInstructions([setComputeUnitLimitIx]) .transaction(); txns = [...txns, createOwnerAtasTxn]; } const processSwimPayloadPubkeys = await propellerProgram.methods - .processSwimPayload(targetTokenId, new BN(0)) + .processSwimPayload(toTokenNumber, new BN(0)) .accounts({ propeller, payer: payer.publicKey, @@ -921,35 +922,8 @@ export const generatePropellerEngineTxns = async ( }) .pubkeys(); const propellerProcessSwimPayloadTxn = await propellerProgram.methods - .propellerProcessSwimPayload(targetTokenId) + .propellerProcessSwimPayload(toTokenNumber) .accounts({ - // processSwimPayload: { - // propeller, - // payer: payer.publicKey, - // message: wormholeMessage, - // claim: wormholeClaim, - // swimPayloadMessage, - // swimClaim, - // redeemer: propellerRedeemer, - // redeemerEscrow: propellerRedeemerEscrowAccount, - // // tokenIdMap: ? - // pool: tokenIdMapPoolInfo.pool, - // poolTokenAccount0: tokenIdMapPoolInfo.tokenAccounts[0], - // poolTokenAccount1: tokenIdMapPoolInfo.tokenAccounts[1], - // lpMint: tokenIdMapPoolInfo.lpMint, - // governanceFee: tokenIdMapPoolInfo.governanceFeeAcct, - // userTransferAuthority: userTransferAuthority.publicKey, - // // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - // userTokenAccount0: ownerAtaAddrs[0], - // // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - // userTokenAccount1: ownerAtaAddrs[1], - // // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - // userLpTokenAccount: ownerAtaAddrs[2], - // tokenProgram: splToken.programId, - // memo: MEMO_PROGRAM_ID, - // twoPoolProgram: twoPoolProgram.programId, - // systemProgram: web3.SystemProgram.programId, - // }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore processSwimPayload: processSwimPayloadPubkeys, @@ -963,7 +937,7 @@ export const generatePropellerEngineTxns = async ( owner, memo: MEMO_PROGRAM_ID, }) - .preInstructions([requestUnitsIx]) + .preInstructions([setComputeUnitLimitIx]) .signers([payer]) .transaction(); txns = [...txns, propellerProcessSwimPayloadTxn]; @@ -972,7 +946,7 @@ export const generatePropellerEngineTxns = async ( return txns; }; -export const getCompleteNativeWithPayloadAccounts = async ( +export const getCompleteNativeWithPayloadAccounts3 = async ( tokenTransferWithPayloadSignedVaa: Buffer, wormholeAddresses: WormholeAddresses, propellerProgram: Program, @@ -1049,10 +1023,253 @@ export const getCompleteNativeWithPayloadAccounts = async ( tokenBridge: wormholeAddresses.tokenBridge, }); }; + +export const getCompleteNativeWithPayloadAccounts = async ( + tokenTransferWithPayloadSignedVaa: Buffer, + wormhole: web3.PublicKey, + tokenBridge: web3.PublicKey, + propellerProgram: Program, +) => { + const { tokenTransferVaa } = parseTokenTransferWithSwimPayloadSignedVaa( + tokenTransferWithPayloadSignedVaa, + ); + const [wormholeMessage] = await deriveMessagePda( + tokenTransferWithPayloadSignedVaa, + wormhole, + ); + const wormholeClaim = await getClaimAddressSolana( + tokenBridge.toBase58(), + tokenTransferWithPayloadSignedVaa, + ); + const [swimPayloadMessage] = await getSwimPayloadMessagePda( + wormholeClaim, + propellerProgram.programId, + ); + + const [endpoint] = await deriveEndpointPda( + tokenTransferVaa.core.emitterChain, + tokenTransferVaa.core.emitterAddress, + tokenBridge, + ); + const swimUsdMint = new web3.PublicKey( + tryUint8ArrayToNative( + tokenTransferVaa.tokenTransfer.tokenAddress, + tokenTransferVaa.tokenTransfer.tokenChain, + ), + ); + const [custody] = await web3.PublicKey.findProgramAddress( + [swimUsdMint.toBytes()], + tokenBridge, + ); + + const [tokenBridgeConfig] = await web3.PublicKey.findProgramAddress( + [Buffer.from("config")], + tokenBridge, + ); + const [custodySigner] = await web3.PublicKey.findProgramAddress( + [Buffer.from("custody_signer")], + tokenBridge, + ); + + const propeller = await getPropellerPda( + swimUsdMint, + propellerProgram.programId, + ); + + const propellerData = await propellerProgram.account.propeller.fetch( + propeller, + ); + const propellerFeeVault = propellerData.feeVault; + + const propellerRedeemer = await getPropellerRedeemerPda( + propellerProgram.programId, + ); + + const propellerRedeemerEscrowAccount = await getAssociatedTokenAddress( + swimUsdMint, + propellerRedeemer, + true, + ); + + return propellerProgram.methods + .completeNativeWithPayload() + .accounts({ + propeller, + payer: propellerProgram.provider.publicKey, + tokenBridgeConfig, + message: wormholeMessage, + claim: wormholeClaim, + swimPayloadMessage: swimPayloadMessage, + endpoint: endpoint, + redeemerEscrow: propellerRedeemerEscrowAccount, + redeemer: propellerRedeemer, + feeVault: propellerFeeVault, + custody: custody, + swimUsdMint: swimUsdMint, + custodySigner, + rent: web3.SYSVAR_RENT_PUBKEY, + systemProgram: web3.SystemProgram.programId, + wormhole: wormhole, + tokenProgram: TOKEN_PROGRAM_ID, + tokenBridge: tokenBridge, + }) + .pubkeys(); +}; + export const getCompleteNativeWithPayloadTxn = async ( + tokenTransferWithPayloadSignedVaa: Buffer, + wormhole: web3.PublicKey, + tokenBridge: web3.PublicKey, + propellerProgram: Program, + memo?: Buffer, +): Promise => { + const completeNativeWithPayloadAccounts = + await getCompleteNativeWithPayloadAccounts( + tokenTransferWithPayloadSignedVaa, + wormhole, + tokenBridge, + propellerProgram, + ); + console.info(` + completeNativeWithPayloadAccounts: ${JSON.stringify( + completeNativeWithPayloadAccounts, + null, + 2, + )} + `); + const postIxs = + typeof memo !== "undefined" + ? [createMemoInstruction(memo.toString("hex"))] + : []; + return await propellerProgram.methods + .completeNativeWithPayload() + .accounts({ + ...completeNativeWithPayloadAccounts, + }) + .preInstructions([setComputeUnitLimitIx]) + .postInstructions(postIxs) + .transaction(); +}; + +export const getProcessSwimPayloadTxn = async ( + toTokenNumber: number, + minOutputAmount: BN, + tokenTransferWithPayloadSignedVaa: Buffer, + wormhole: web3.PublicKey, + tokenBridge: web3.PublicKey, + propellerProgram: Program, + twoPoolProgram: Program, + splToken: Program, + memo?: Buffer, +) => { + const { tokenTransferVaa } = parseTokenTransferWithSwimPayloadSignedVaa( + tokenTransferWithPayloadSignedVaa, + ); + const wormholeClaim = await getClaimAddressSolana( + tokenBridge.toBase58(), + tokenTransferWithPayloadSignedVaa, + ); + const [swimPayloadMessage] = await getSwimPayloadMessagePda( + wormholeClaim, + propellerProgram.programId, + ); + + const swimUsdMint = new web3.PublicKey( + tryUint8ArrayToNative( + tokenTransferVaa.tokenTransfer.tokenAddress, + tokenTransferVaa.tokenTransfer.tokenChain, + ), + ); + const propeller = await getPropellerPda( + swimUsdMint, + propellerProgram.programId, + ); + const swimPayloadMessageData = + await propellerProgram.account.swimPayloadMessage.fetch(swimPayloadMessage); + + const propellerRedeemer = await getPropellerRedeemerPda( + propellerProgram.programId, + ); + + const propellerRedeemerEscrowAccount = await getAssociatedTokenAddress( + swimUsdMint, + propellerRedeemer, + true, + ); + const [tokenNumberMapAddr] = await getToTokenNumberMapAddr( + propeller, + toTokenNumber, + propellerProgram.programId, + ); + const tokenNumberMapData = + await propellerProgram.account.tokenNumberMap.fetchNullable( + tokenNumberMapAddr, + ); + //TODO: variant for fallback should be handled in propellerProcessSwimPayload? + if (!tokenNumberMapData) { + throw new Error("Token number map does not exist"); + } + const tokenNumberMapPool = tokenNumberMapData.pool; + const poolData = await twoPoolProgram.account.twoPool.fetch( + tokenNumberMapPool, + ); + const poolMints = [...poolData.tokenMintKeys, poolData.lpMintKey]; + const userAtasForPool = await Promise.all( + poolMints.map(async (mint) => { + const userAta = await getAssociatedTokenAddress( + mint, + swimPayloadMessageData.owner, + ); + const userAtaData = await splToken.account.token.fetchNullable(userAta); + return { + mint, + userAta, + userAtaData, + }; + }), + ); + + const preIxs = userAtasForPool + .filter(({ userAtaData }) => userAtaData === null) + .map(({ mint, userAta }) => { + return createAssociatedTokenAccountInstruction( + propellerProgram.provider.publicKey, + userAta, + swimPayloadMessageData.owner, + mint, + ); + }); + return propellerProgram.methods + .processSwimPayload(toTokenNumber, minOutputAmount) + .accounts({ + propeller, + payer: propellerProgram.provider.publicKey, + claim: wormholeClaim, + swimPayloadMessage, + swimPayloadMessagePayer: swimPayloadMessageData.swimPayloadMessagePayer, + redeemer: propellerRedeemer, + redeemerEscrow: propellerRedeemerEscrowAccount, + // tokenIdMap: ? + pool: tokenNumberMapPool, + poolTokenAccount0: poolData.tokenKeys[0], + poolTokenAccount1: poolData.tokenKeys[1], + lpMint: poolData.lpMintKey, + governanceFee: poolData.governanceFeeKey, + userTokenAccount0: userAtasForPool[0].userAta, + userTokenAccount1: userAtasForPool[1].userAta, + userLpTokenAccount: userAtasForPool[2].userAta, + tokenProgram: splToken.programId, + twoPoolProgram: twoPoolProgram.programId, + systemProgram: web3.SystemProgram.programId, + }) + .preInstructions(preIxs) + .postInstructions(memo ? [createMemoInstruction(memo.toString("hex"))] : []) + .transaction(); +}; + +export const getPropellerCompleteNativeWithPayloadTxn = async ( tokenTransferWithPayloadSignedVaa: Buffer, wormholeAddresses: WormholeAddresses, - propellerEnabled: boolean, memoStr: string | null, propellerProgram: Program, twoPoolProgram: Program, @@ -1133,52 +1350,87 @@ export const getCompleteNativeWithPayloadTxn = async ( const completeNativeWithPayload = await getCompleteNativeWithPayloadAccounts( tokenTransferWithPayloadSignedVaa, - wormholeAddresses, + wormholeAddresses.wormhole, + wormholeAddresses.tokenBridge, + // wormholeAddresses, propellerProgram, ); - if (!propellerEnabled) { - return completeNativeWithPayload - .preInstructions([setComputeUnitLimitIx]) - .postInstructions( - memoStr !== null ? [createMemoInstruction(memoStr)] : [], - ) - .transaction(); - } else { - const completeNativeWithPayloadPubkeys = - await completeNativeWithPayload.pubkeys(); - const [feeTracker] = await getFeeTrackerPda( - swimUsdMint, - propellerProgram.provider.publicKey, - propellerProgram.programId, - ); - const aggregator = propellerData.aggregator; - const marginalPricePool = propellerData.marginalPricePool; - const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( - marginalPricePool, - ); - const marginalPricePoolToken0Account = marginalPricePoolData.tokenKeys[0]; - const marginalPricePoolToken1Account = marginalPricePoolData.tokenKeys[1]; - const marginalPricePoolLpMint = marginalPricePoolData.lpMintKey; + // if (!propellerEnabled) { + // return completeNativeWithPayload + // .preInstructions([setComputeUnitLimitIx]) + // .postInstructions( + // memoStr !== null ? [createMemoInstruction(memoStr)] : [], + // ) + // .transaction(); + // } else { + // const completeNativeWithPayloadPubkeys = + // await completeNativeWithPayload.pubkeys(); + // const [feeTracker] = await getFeeTrackerPda( + // swimUsdMint, + // propellerProgram.provider.publicKey!, + // propellerProgram.programId, + // ); + // const aggregator = propellerData.aggregator; + // const marginalPricePool = propellerData.marginalPricePool; + // const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( + // marginalPricePool, + // ); + // const marginalPricePoolToken0Account = marginalPricePoolData.tokenKeys[0]; + // const marginalPricePoolToken1Account = marginalPricePoolData.tokenKeys[1]; + // const marginalPricePoolLpMint = marginalPricePoolData.lpMintKey; + // + // return propellerProgram.methods + // .propellerCompleteNativeWithPayload() + // .accounts({ + // // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // // @ts-ignore + // completeNativeWithPayload: completeNativeWithPayloadPubkeys, + // feeTracker: feeTracker, + // aggregator, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // memo: MEMO_PROGRAM_ID, + // }) + // .preInstructions([setComputeUnitLimitIx]) + // .transaction(); + // } + const completeNativeWithPayloadPubkeys = + await completeNativeWithPayload.pubkeys(); + const [feeTracker] = await getFeeTrackerPda( + swimUsdMint, + propellerProgram.provider.publicKey!, + propellerProgram.programId, + ); + const aggregator = propellerData.aggregator; + const marginalPricePool = propellerData.marginalPricePool; + const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( + marginalPricePool, + ); + const marginalPricePoolToken0Account = marginalPricePoolData.tokenKeys[0]; + const marginalPricePoolToken1Account = marginalPricePoolData.tokenKeys[1]; + const marginalPricePoolLpMint = marginalPricePoolData.lpMintKey; - return propellerProgram.methods - .propellerCompleteNativeWithPayload() - .accounts({ - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - completeNativeWithPayload: completeNativeWithPayloadPubkeys, - feeTracker: feeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, - memo: MEMO_PROGRAM_ID, - }) - .preInstructions([setComputeUnitLimitIx]) - .transaction(); - } + return propellerProgram.methods + .propellerCompleteNativeWithPayload() + .accounts({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + completeNativeWithPayload: completeNativeWithPayloadPubkeys, + feeTracker: feeTracker, + aggregator, + marginalPricePool: marginalPricePool, + marginalPricePoolToken0Account: marginalPricePoolToken0Account, + marginalPricePoolToken1Account: marginalPricePoolToken1Account, + marginalPricePoolLpMint: marginalPricePoolLpMint, + twoPoolProgram: twoPoolProgram.programId, + memo: MEMO_PROGRAM_ID, + }) + .preInstructions([setComputeUnitLimitIx]) + .transaction(); }; const getMarginalPricePoolInfo = async ( @@ -1273,23 +1525,89 @@ export const getWormholeAddressesForMint = async ( }; }; -export const getOwnerTokenAccountsForPool = async ( - pool: web3.PublicKey, - owner: web3.PublicKey, - twoPoolProgram: Program, -): Promise => { - const tokenIdMapPoolData = await twoPoolProgram.account.twoPool.fetch(pool); - const tokenIdMapPoolInfo = { - pool, - tokenMints: tokenIdMapPoolData.tokenMintKeys, - tokenAccounts: tokenIdMapPoolData.tokenKeys, - lpMint: tokenIdMapPoolData.lpMintKey, - governanceFeeAcct: tokenIdMapPoolData.governanceFeeKey, - }; - const mints = [...tokenIdMapPoolInfo.tokenMints, tokenIdMapPoolInfo.lpMint]; - return await Promise.all( - mints.map(async (mint) => { - return await getAssociatedTokenAddress(mint, owner); - }), +export const postVaaToSolana = async ( + tokenTransferWithPayloadSignedVaa: Buffer, + provider: AnchorProvider, + wormhole: web3.PublicKey, +) => { + await postVaaSolanaWithRetry( + provider.connection, + async (tx) => { + return provider.wallet.signTransaction(tx); + }, + wormhole.toBase58(), + provider.publicKey.toBase58(), + tokenTransferWithPayloadSignedVaa, + 10, ); }; + +export class DummyForeignRoutingProgram { + private _sequence: number; + private readonly _emitterChain: ChainId; + private readonly _emitterAddress: Buffer; + private readonly tokenAddress: Buffer; + private readonly to: web3.PublicKey; + private readonly from: Buffer; + + public constructor( + address: string, + emitterChain: ChainId, + startingSequence = 0, + tokenAddress: Buffer, + to: web3.PublicKey, + from: Buffer, + ) { + this._emitterChain = emitterChain; + this._emitterAddress = Buffer.from( + tryNativeToHexString(address, this._emitterChain), + "hex", + ); + + // uptick this + this._sequence = startingSequence; + this.tokenAddress = tokenAddress; + this.to = to; + this.from = from; + } + + public get emitterChain(): ChainId { + return this._emitterChain; + } + + public get emitterAddress(): Buffer { + return this._emitterAddress; + } + + public get sequence(): number { + return this._sequence; + } + + /** + * It creates a signed token transfer with a swim payload from this to + * solana. + * @param {string} amount - The amount of tokens to transfer. + * @param {Buffer} swimPayload - This is the payload that will be sent to the SWIM server. + * @returns A signed token transfer with a swim payload. + */ + public createSignedTokenTransferWithSwimPayloadVAA( + amount: string, + swimPayload: ParsedSwimPayload, + ) { + return signAndEncodeVaa( + 0, + createNonce().readUInt32LE(0), + this._emitterChain as number, + this._emitterAddress, + BigInt(++this._sequence), + encodeTokenTransferWithPayload( + amount.toString(), + this.tokenAddress, + CHAIN_ID_SOLANA, + this.to, + this.from, + encodeSwimPayload(swimPayload), + ), + ); + } +} diff --git a/packages/solana-contracts/src/__tests__/propeller/tokenBridgeUtils.ts b/packages/solana-contracts/src/__tests__/propeller/tokenBridgeUtils.ts index ab8e83508..a6f82766d 100644 --- a/packages/solana-contracts/src/__tests__/propeller/tokenBridgeUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/tokenBridgeUtils.ts @@ -1,30 +1,22 @@ import type { ChainId } from "@certusone/wormhole-sdk"; -import { - CHAIN_ID_SOLANA, - toChainName, - tryNativeToHexString, - tryUint8ArrayToNative, -} from "@certusone/wormhole-sdk"; +import { CHAIN_ID_SOLANA, toChainName, tryNativeToHexString, tryUint8ArrayToNative } from "@certusone/wormhole-sdk"; import { BN, web3 } from "@project-serum/anchor"; // eslint-disable-next-line import/order import * as byteify from "byteify"; // import { toBigNumberHex } from "./utils"; - import type { BigNumberish } from "ethers"; import { BigNumber } from "ethers"; // import { PostVaaMethod } from "./types"; import keccak256 from "keccak256"; - +import type { ParsedPostedMessage, ParsedVaa } from "./wormholeUtils"; import { - WORMHOLE_TOKEN_BRIDGE, formatParsedVaa, formatPostedMessage, parsePostedMessage, parseVaa, - // signAndEncodeVaa, + WORMHOLE_TOKEN_BRIDGE, } from "./wormholeUtils"; -import type { ParsedPostedMessage, ParsedVaa } from "./wormholeUtils"; export function toBigNumberHex(value: BigNumberish, numBytes: number): string { return BigNumber.from(value) @@ -285,7 +277,6 @@ export const deriveMessagePda = async ( signedVaa: Buffer, programId: web3.PublicKey, ) => { - const hash = hashVaa(signedVaa); // const hexHash = await getSignedVAAHash(signedVaa); // const hash2 = Buffer.from(hexToUint8Array(hexHash)); // console.info(` @@ -302,6 +293,7 @@ export const deriveMessagePda = async ( // hash2: ${hash2} // hash2BufferHex: ${Buffer.from(hash2).toString("hex")} // `); + const hash = hashVaa(signedVaa); return await web3.PublicKey.findProgramAddress( [Buffer.from("PostedVAA"), hash], programId, @@ -402,6 +394,7 @@ export async function parseTokenTransferPostedMessage( postedMessage: Buffer, ): Promise { const parsed = await parsePostedMessage(postedMessage); + console.info(`finished parsePostedMessage`); const data = parsed.data; const tokenTransfer = parseTokenTransfer(data); return { @@ -673,3 +666,4 @@ export async function getMintMetaPdas(mintKey: web3.PublicKey) { // ); // } // } + diff --git a/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts b/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts index 9c935a4ee..ca99bc93f 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts @@ -1,4 +1,4 @@ -import type { BN, Program, SplToken } from "@project-serum/anchor"; +import type { BN, Program, Program, SplToken } from "@project-serum/anchor"; import { web3 } from "@project-serum/anchor"; import { getAssociatedTokenAddress, @@ -6,7 +6,7 @@ import { } from "@solana/spl-token"; import type { Commitment, ConfirmOptions } from "@solana/web3.js"; -import type { TwoPool } from "../../artifacts/two_pool"; +import type { TwoPool, TwoPool } from "../../artifacts/two_pool"; /** * It initializes the mints for the tokens that will be used in the pool, and then *CALCULATES* the pool token accounts and @@ -375,3 +375,101 @@ export function printBeforeAndAfterPoolUserBalances( after: ${previousDepthAfter.toString()} `); } + +export const getPoolTokenKeys = async ( + pool: web3.PublicKey, + twoPoolProgram: Program, +) => { + const poolInfo = await twoPoolProgram.account.twoPool.fetch(pool); + return poolInfo.tokenKeys; +}; + +export const getPoolTokenAccountBalances = async ( + pool: web3.PublicKey, + twoPoolProgram: Program, + splToken: Program, +): Promise => { + const poolTokenKeys = await getPoolTokenKeys(pool, twoPoolProgram); + const poolAtaData = await Promise.all( + poolTokenKeys.map(async (tokenKey) => { + return splToken.account.token.fetch(tokenKey); + }), + ); + return poolAtaData.map((ata) => ata.amount); +}; + +export const getOwnerAtaAddrsForPool = async ( + pool: web3.PublicKey, + owner: web3.PublicKey, + twoPoolProgram: Program, +): Promise => { + const tokenIdMapPoolData = await twoPoolProgram.account.twoPool.fetch(pool); + const tokenIdMapPoolInfo = { + pool, + tokenMints: tokenIdMapPoolData.tokenMintKeys, + tokenAccounts: tokenIdMapPoolData.tokenKeys, + lpMint: tokenIdMapPoolData.lpMintKey, + governanceFeeAcct: tokenIdMapPoolData.governanceFeeKey, + }; + const mints = [...tokenIdMapPoolInfo.tokenMints, tokenIdMapPoolInfo.lpMint]; + return await Promise.all( + mints.map(async (mint) => { + return await getAssociatedTokenAddress(mint, owner); + }), + ); +}; + +export const getUserAtaDataForPool = async ( + user: web3.PublicKey, + pool: web3.PublicKey, + twoPoolProgram: Program, + splToken: Program, +) => { + const userAtaAddrs = await getOwnerAtaAddrsForPool( + pool, + user, + twoPoolProgram, + ); + return await Promise.all( + userAtaAddrs.map(async (ataAddr) => { + return splToken.account.token.fetch(ataAddr); + }), + ); +}; + +export const getNullableUserAtaDataForPool = async ( + user: web3.PublicKey, + pool: web3.PublicKey, + twoPoolProgram: Program, + splToken: Program, +) => { + const userAtaAddrs = await getOwnerAtaAddrsForPool( + pool, + user, + twoPoolProgram, + ); + return await Promise.all( + userAtaAddrs.map(async (ataAddr) => { + const data = await splToken.account.token.fetchNullable(ataAddr); + return { + ataAddr, + data, + }; + }), + ); +}; + +export const getUserAtaBalancesForPool = async ( + user: web3.PublicKey, + pool: web3.PublicKey, + twoPoolProgram: Program, + splToken: Program, +) => { + const userTokenAccounts = await getUserAtaDataForPool( + user, + pool, + twoPoolProgram, + splToken, + ); + return userTokenAccounts.map((ata) => ata.amount); +}; diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index e2c3ebdc4..fdb6483d2 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -64,7 +64,12 @@ "isSigner": false }, { - "name": "admin", + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "pauseKey", "isMut": false, "isSigner": true }, @@ -171,7 +176,79 @@ ] }, { - "name": "createTokenIdMap", + "name": "setPaused", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, + { + "name": "changePauseKey", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "prepareGovernanceTransition", "accounts": [ { "name": "propeller", @@ -194,7 +271,69 @@ } }, { - "name": "admin", + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "enactGovernanceTransition", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "createTokenNumberMap", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -217,12 +356,12 @@ { "kind": "arg", "type": "publicKey", - "path": "pool" + "path": "pool.token_mint_keys [0]" }, { "kind": "arg", "type": "publicKey", - "path": "pool" + "path": "pool.token_mint_keys [1]" }, { "kind": "arg", @@ -238,7 +377,7 @@ } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": true, "isSigner": false, "pda": { @@ -262,7 +401,7 @@ { "kind": "arg", "type": "u16", - "path": "target_token_index" + "path": "to_token_number" } ] } @@ -280,7 +419,7 @@ ], "args": [ { - "name": "targetTokenIndex", + "name": "toTokenNumber", "type": "u16" }, { @@ -296,15 +435,184 @@ "type": "publicKey" }, { - "name": "poolIx", + "name": "toTokenStep", + "type": { + "defined": "ToTokenStep" + } + } + ] + }, + { + "name": "updateTokenNumberMap", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "pool", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenNumberMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "arg", + "type": "u16", + "path": "to_token_number" + } + ] + } + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "toTokenNumber", + "type": "u16" + }, + { + "name": "poolTokenIndex", + "type": "u8" + }, + { + "name": "poolTokenMint", + "type": "publicKey" + }, + { + "name": "toTokenStep", "type": { - "defined": "PoolInstruction" + "defined": "ToTokenStep" + } + } + ] + }, + { + "name": "closeTokenNumberMap", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenNumberMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "arg", + "type": "u16", + "path": "to_token_number" + } + ] } } + ], + "args": [ + { + "name": "toTokenNumber", + "type": "u16" + } ] }, { "name": "createTargetChainMap", + "docs": [ + "Target Chain Map *" + ], "accounts": [ { "name": "propeller", @@ -327,7 +635,7 @@ } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -407,7 +715,7 @@ } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -441,11 +749,6 @@ } ] } - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -460,6 +763,73 @@ } ] }, + { + "name": "targetChainMapSetPaused", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "targetChainMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "TargetChainMap", + "path": "target_chain_map.target_chain" + } + ] + } + } + ], + "args": [ + { + "name": "isPaused", + "type": "bool" + } + ] + }, { "name": "initializeFeeTracker", "accounts": [ @@ -1406,6 +1776,10 @@ } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -1716,6 +2090,10 @@ } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -1796,8 +2174,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1867,13 +2244,53 @@ "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, + { + "name": "swimPayloadMessage", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "swim_payload" + }, + { + "kind": "account", + "type": "publicKey", + "path": "claim" + } + ] + } + }, { "name": "custody", "isMut": true, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { "name": "swimUsdMint", @@ -1883,56 +2300,46 @@ { "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "rent", + "name": "wormhole", "isMut": false, "isSigner": false }, { - "name": "systemProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "wormhole", + "name": "tokenBridge", "isMut": false, "isSigner": false }, { - "name": "tokenProgram", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "tokenBridge", + "name": "rent", "isMut": false, "isSigner": false - }, - { - "name": "swimPayloadMessage", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "swim_payload" - }, - { - "kind": "account", - "type": "publicKey", - "path": "claim" - } - ] - } } ], "args": [] @@ -2083,7 +2490,7 @@ "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -2107,7 +2514,7 @@ { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -2202,7 +2609,7 @@ ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" }, { @@ -2258,8 +2665,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -2329,13 +2735,53 @@ "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, + { + "name": "swimPayloadMessage", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "swim_payload" + }, + { + "kind": "account", + "type": "publicKey", + "path": "claim" + } + ] + } + }, { "name": "custody", "isMut": true, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { "name": "swimUsdMint", @@ -2345,56 +2791,46 @@ { "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "rent", + "name": "wormhole", "isMut": false, "isSigner": false }, { - "name": "systemProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "wormhole", + "name": "tokenBridge", "isMut": false, "isSigner": false }, { - "name": "tokenProgram", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "tokenBridge", + "name": "rent", "isMut": false, "isSigner": false - }, - { - "name": "swimPayloadMessage", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "swim_payload" - }, - { - "kind": "account", - "type": "publicKey", - "path": "claim" - } - ] - } } ] }, @@ -2658,7 +3094,7 @@ } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -2998,7 +3434,7 @@ "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -3022,7 +3458,7 @@ { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -3238,7 +3674,7 @@ ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" } ], @@ -3694,11 +4130,11 @@ "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "docs": [ - "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenNumberMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ], "pda": { @@ -3908,17 +4344,25 @@ 32 ] } + }, + { + "name": "isPaused", + "type": "bool" } ] } }, { - "name": "TokenIdMap", + "name": "TokenNumberMap", "type": { "kind": "struct", "fields": [ { - "name": "outputTokenIndex", + "name": "bump", + "type": "u8" + }, + { + "name": "toTokenNumber", "type": "u16" }, { @@ -3934,14 +4378,10 @@ "type": "publicKey" }, { - "name": "poolIx", + "name": "toTokenStep", "type": { - "defined": "PoolInstruction" + "defined": "ToTokenStep" } - }, - { - "name": "bump", - "type": "u8" } ] } @@ -3956,19 +4396,23 @@ "type": "u8" }, { - "name": "nonce", - "type": "u32" + "name": "isPaused", + "type": "bool" }, { - "name": "admin", + "name": "governanceKey", "type": "publicKey" }, { - "name": "wormhole", + "name": "preparedGovernanceKey", "type": "publicKey" }, { - "name": "tokenBridge", + "name": "governanceTransitionTs", + "type": "i64" + }, + { + "name": "pauseKey", "type": "publicKey" }, { @@ -4489,7 +4933,7 @@ } }, { - "name": "PoolInstruction", + "name": "ToTokenStep", "type": { "kind": "enum", "variants": [ @@ -4505,20 +4949,6 @@ ] } }, - { - "name": "SwimPayloadVersion", - "type": { - "kind": "enum", - "variants": [ - { - "name": "V0" - }, - { - "name": "V1" - } - ] - } - }, { "name": "ConsistencyLevel", "type": { @@ -4685,7 +5115,7 @@ { "code": 6023, "name": "StaleFeed", - "msg": "Switchboard feed has not been updated in 5 minutes" + "msg": "Switchboard feed value is stale " }, { "code": 6024, @@ -4699,133 +5129,163 @@ }, { "code": 6026, - "name": "InvalidClaimData", - "msg": "Invalid claim data" + "name": "InvalidWormholeClaimAccount", + "msg": "Invalid Wormhole Claim Account" }, { "code": 6027, - "name": "ClaimNotClaimed", - "msg": "Claim Account not claimed" + "name": "InvalidClaimData", + "msg": "Invalid claim data" }, { "code": 6028, - "name": "InvalidPropellerAdmin", - "msg": "Invalid Propeller Admin" + "name": "ClaimNotClaimed", + "msg": "Claim Account not claimed" }, { "code": 6029, - "name": "InvalidTokenIdMapPool", - "msg": "Invalid Pool for Token Id Map" + "name": "InvalidPropellerGovernanceKey", + "msg": "Invalid Propeller GovernanceKey" }, { "code": 6030, - "name": "InvalidOutputTokenIndex", - "msg": "Invalid Output Token Index" + "name": "InvalidPropellerPauseKey", + "msg": "Invalid Propeller Pause Key" }, { "code": 6031, - "name": "InvalidTokenIdMapPoolTokenIndex", - "msg": "Invalid Pool Token Index for Token Id Map" + "name": "InvalidTokenNumberMapPool", + "msg": "Invalid Pool for Token Number Map" }, { "code": 6032, - "name": "InvalidTokenIdMapPoolTokenMint", - "msg": "Invalid Pool Token Mint for Token Id Map" + "name": "InvalidOutputTokenIndex", + "msg": "Invalid Output Token Index" }, { "code": 6033, - "name": "InvalidTokenIdMapPoolIx", - "msg": "Invalid Pool Ix for Token Id Map" + "name": "InvalidTokenNumberMapPoolTokenIndex", + "msg": "Invalid Pool Token Index for Token Number Map" }, { "code": 6034, + "name": "InvalidTokenNumberMapPoolTokenMint", + "msg": "Invalid Pool Token Mint for Token Number Map" + }, + { + "code": 6035, + "name": "InvalidTokenNumberMapToTokenStep", + "msg": "Invalid To Token Step for Token Number Map" + }, + { + "code": 6036, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6035, + "code": 6037, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6036, + "code": 6038, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6037, + "code": 6039, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6038, + "code": 6040, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6039, + "code": 6041, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6040, + "code": 6042, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6041, + "code": 6043, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6042, + "code": 6044, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6043, + "code": 6045, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6044, + "code": 6046, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6045, + "code": 6047, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6046, + "code": 6048, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6047, - "name": "TokenIdMapExists", - "msg": "TokenIdMap exists. Please use the correct instruction" - }, - { - "code": 6048, - "name": "InvalidTokenIdMapAccountAddress", - "msg": "Invalid address for TokenIdMap account" + "code": 6049, + "name": "TokenNumberMapExists", + "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6049, + "code": 6050, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6050, + "code": 6051, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6051, + "code": 6052, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" + }, + { + "code": 6053, + "name": "InvalidMemo", + "msg": "Invalid Memo" + }, + { + "code": 6054, + "name": "ToTokenNumberMismatch", + "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" + }, + { + "code": 6055, + "name": "IsPaused", + "msg": "Routing Contract is paused" + }, + { + "code": 6056, + "name": "TargetChainIsPaused", + "msg": "Target Chain is paused" + }, + { + "code": 6057, + "name": "InvalidSwimPayloadMessagePayer", + "msg": "Invalid SwimPayloadMessagePayer" } ] } \ No newline at end of file diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 86a32f67a..68c57e6f7 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -64,7 +64,12 @@ export type Propeller = { "isSigner": false }, { - "name": "admin", + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "pauseKey", "isMut": false, "isSigner": true }, @@ -171,7 +176,141 @@ export type Propeller = { ] }, { - "name": "createTokenIdMap", + "name": "setPaused", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, + { + "name": "changePauseKey", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "prepareGovernanceTransition", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "enactGovernanceTransition", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "createTokenNumberMap", "accounts": [ { "name": "propeller", @@ -194,7 +333,7 @@ export type Propeller = { } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -217,12 +356,12 @@ export type Propeller = { { "kind": "arg", "type": "publicKey", - "path": "pool" + "path": "pool.token_mint_keys [0]" }, { "kind": "arg", "type": "publicKey", - "path": "pool" + "path": "pool.token_mint_keys [1]" }, { "kind": "arg", @@ -238,7 +377,7 @@ export type Propeller = { } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": true, "isSigner": false, "pda": { @@ -262,7 +401,7 @@ export type Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_index" + "path": "to_token_number" } ] } @@ -280,7 +419,7 @@ export type Propeller = { ], "args": [ { - "name": "targetTokenIndex", + "name": "toTokenNumber", "type": "u16" }, { @@ -296,15 +435,15 @@ export type Propeller = { "type": "publicKey" }, { - "name": "poolIx", + "name": "toTokenStep", "type": { - "defined": "PoolInstruction" + "defined": "ToTokenStep" } } ] }, { - "name": "createTargetChainMap", + "name": "updateTokenNumberMap", "accounts": [ { "name": "propeller", @@ -327,7 +466,7 @@ export type Propeller = { } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -337,7 +476,12 @@ export type Propeller = { "isSigner": true }, { - "name": "targetChainMap", + "name": "pool", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenNumberMap", "isMut": true, "isSigner": false, "pda": { @@ -347,6 +491,11 @@ export type Propeller = { "type": "string", "value": "propeller" }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, { "kind": "account", "type": "publicKey", @@ -356,35 +505,40 @@ export type Propeller = { { "kind": "arg", "type": "u16", - "path": "target_chain" + "path": "to_token_number" } ] } }, { - "name": "systemProgram", + "name": "twoPoolProgram", "isMut": false, "isSigner": false } ], "args": [ { - "name": "targetChain", + "name": "toTokenNumber", "type": "u16" }, { - "name": "targetAddress", + "name": "poolTokenIndex", + "type": "u8" + }, + { + "name": "poolTokenMint", + "type": "publicKey" + }, + { + "name": "toTokenStep", "type": { - "array": [ - "u8", - 32 - ] + "defined": "ToTokenStep" } } ] }, { - "name": "updateTargetChainMap", + "name": "closeTokenNumberMap", "accounts": [ { "name": "propeller", @@ -407,7 +561,7 @@ export type Propeller = { } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -417,7 +571,7 @@ export type Propeller = { "isSigner": true }, { - "name": "targetChainMap", + "name": "tokenNumberMap", "isMut": true, "isSigner": false, "pda": { @@ -427,6 +581,11 @@ export type Propeller = { "type": "string", "value": "propeller" }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, { "kind": "account", "type": "publicKey", @@ -434,34 +593,26 @@ export type Propeller = { "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "to_token_number" } ] } - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [ { - "name": "routingContract", - "type": { - "array": [ - "u8", - 32 - ] - } + "name": "toTokenNumber", + "type": "u16" } ] }, { - "name": "initializeFeeTracker", + "name": "createTargetChainMap", + "docs": [ + "Target Chain Map *" + ], "accounts": [ { "name": "propeller", @@ -477,14 +628,24 @@ export type Propeller = { { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "swim_usd_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } }, { - "name": "feeTracker", + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "targetChainMap", "isMut": true, "isSigner": false, "pda": { @@ -494,45 +655,44 @@ export type Propeller = { "type": "string", "value": "propeller" }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "swim_usd_mint" + "account": "Propeller", + "path": "propeller" }, { - "kind": "account", - "type": "publicKey", - "path": "payer" + "kind": "arg", + "type": "u16", + "path": "target_chain" } ] } }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - }, { "name": "systemProgram", "isMut": false, "isSigner": false } ], - "args": [] + "args": [ + { + "name": "targetChain", + "type": "u16" + }, + { + "name": "targetAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] }, { - "name": "claimFees", + "name": "updateTargetChainMap", "accounts": [ { "name": "propeller", @@ -555,7 +715,17 @@ export type Propeller = { } }, { - "name": "feeTracker", + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "targetChainMap", "isMut": true, "isSigner": false, "pda": { @@ -566,7 +736,207 @@ export type Propeller = { "value": "propeller" }, { - "kind": "const", + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "TargetChainMap", + "path": "target_chain_map.target_chain" + } + ] + } + } + ], + "args": [ + { + "name": "routingContract", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "targetChainMapSetPaused", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "targetChainMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "account", + "type": "u16", + "account": "TargetChainMap", + "path": "target_chain_map.target_chain" + } + ] + } + } + ], + "args": [ + { + "name": "isPaused", + "type": "bool" + } + ] + }, + { + "name": "initializeFeeTracker", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ] + } + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "fee" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + }, + { + "kind": "account", + "type": "publicKey", + "path": "payer" + } + ] + } + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "swimUsdMint", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimFees", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", "type": "string", "value": "fee" }, @@ -1406,6 +1776,10 @@ export type Propeller = { } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -1716,6 +2090,10 @@ export type Propeller = { } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -1796,8 +2174,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1867,49 +2244,10 @@ export type Propeller = { "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, - { - "name": "custody", - "isMut": true, - "isSigner": false - }, - { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - }, - { - "name": "custodySigner", - "isMut": false, - "isSigner": false - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "wormhole", - "isMut": false, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "tokenBridge", - "isMut": false, - "isSigner": false - }, { "name": "swimPayloadMessage", "isMut": true, @@ -1933,16 +2271,85 @@ export type Propeller = { } ] } - } - ], - "args": [] - }, - { - "name": "processSwimPayload", - "accounts": [ + }, { - "name": "propeller", - "isMut": false, + "name": "custody", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } + }, + { + "name": "swimUsdMint", + "isMut": false, + "isSigner": false + }, + { + "name": "custodySigner", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } + }, + { + "name": "wormhole", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenBridge", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "processSwimPayload", + "accounts": [ + { + "name": "propeller", + "isMut": false, "isSigner": false, "pda": { "seeds": [ @@ -2083,7 +2490,7 @@ export type Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -2107,7 +2514,7 @@ export type Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -2202,7 +2609,7 @@ export type Propeller = { ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" }, { @@ -2258,8 +2665,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -2329,13 +2735,53 @@ export type Propeller = { "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, + { + "name": "swimPayloadMessage", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "swim_payload" + }, + { + "kind": "account", + "type": "publicKey", + "path": "claim" + } + ] + } + }, { "name": "custody", "isMut": true, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { "name": "swimUsdMint", @@ -2345,56 +2791,46 @@ export type Propeller = { { "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "rent", + "name": "wormhole", "isMut": false, "isSigner": false }, { - "name": "systemProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "wormhole", + "name": "tokenBridge", "isMut": false, "isSigner": false }, { - "name": "tokenProgram", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "tokenBridge", + "name": "rent", "isMut": false, "isSigner": false - }, - { - "name": "swimPayloadMessage", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "swim_payload" - }, - { - "kind": "account", - "type": "publicKey", - "path": "claim" - } - ] - } } ] }, @@ -2658,7 +3094,7 @@ export type Propeller = { } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -2998,7 +3434,7 @@ export type Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -3022,7 +3458,7 @@ export type Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -3238,7 +3674,7 @@ export type Propeller = { ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" } ], @@ -3694,11 +4130,11 @@ export type Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "docs": [ - "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenNumberMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ], "pda": { @@ -3908,17 +4344,25 @@ export type Propeller = { 32 ] } + }, + { + "name": "isPaused", + "type": "bool" } ] } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "type": { "kind": "struct", "fields": [ { - "name": "outputTokenIndex", + "name": "bump", + "type": "u8" + }, + { + "name": "toTokenNumber", "type": "u16" }, { @@ -3934,14 +4378,10 @@ export type Propeller = { "type": "publicKey" }, { - "name": "poolIx", + "name": "toTokenStep", "type": { - "defined": "PoolInstruction" + "defined": "ToTokenStep" } - }, - { - "name": "bump", - "type": "u8" } ] } @@ -3956,19 +4396,23 @@ export type Propeller = { "type": "u8" }, { - "name": "nonce", - "type": "u32" + "name": "isPaused", + "type": "bool" }, { - "name": "admin", + "name": "governanceKey", "type": "publicKey" }, { - "name": "wormhole", + "name": "preparedGovernanceKey", "type": "publicKey" }, { - "name": "tokenBridge", + "name": "governanceTransitionTs", + "type": "i64" + }, + { + "name": "pauseKey", "type": "publicKey" }, { @@ -4489,7 +4933,7 @@ export type Propeller = { } }, { - "name": "PoolInstruction", + "name": "ToTokenStep", "type": { "kind": "enum", "variants": [ @@ -4505,20 +4949,6 @@ export type Propeller = { ] } }, - { - "name": "SwimPayloadVersion", - "type": { - "kind": "enum", - "variants": [ - { - "name": "V0" - }, - { - "name": "V1" - } - ] - } - }, { "name": "ConsistencyLevel", "type": { @@ -4685,7 +5115,7 @@ export type Propeller = { { "code": 6023, "name": "StaleFeed", - "msg": "Switchboard feed has not been updated in 5 minutes" + "msg": "Switchboard feed value is stale " }, { "code": 6024, @@ -4699,137 +5129,167 @@ export type Propeller = { }, { "code": 6026, - "name": "InvalidClaimData", - "msg": "Invalid claim data" + "name": "InvalidWormholeClaimAccount", + "msg": "Invalid Wormhole Claim Account" }, { "code": 6027, - "name": "ClaimNotClaimed", - "msg": "Claim Account not claimed" + "name": "InvalidClaimData", + "msg": "Invalid claim data" }, { "code": 6028, - "name": "InvalidPropellerAdmin", - "msg": "Invalid Propeller Admin" + "name": "ClaimNotClaimed", + "msg": "Claim Account not claimed" }, { "code": 6029, - "name": "InvalidTokenIdMapPool", - "msg": "Invalid Pool for Token Id Map" + "name": "InvalidPropellerGovernanceKey", + "msg": "Invalid Propeller GovernanceKey" }, { "code": 6030, - "name": "InvalidOutputTokenIndex", - "msg": "Invalid Output Token Index" + "name": "InvalidPropellerPauseKey", + "msg": "Invalid Propeller Pause Key" }, { "code": 6031, - "name": "InvalidTokenIdMapPoolTokenIndex", - "msg": "Invalid Pool Token Index for Token Id Map" + "name": "InvalidTokenNumberMapPool", + "msg": "Invalid Pool for Token Number Map" }, { "code": 6032, - "name": "InvalidTokenIdMapPoolTokenMint", - "msg": "Invalid Pool Token Mint for Token Id Map" + "name": "InvalidOutputTokenIndex", + "msg": "Invalid Output Token Index" }, { "code": 6033, - "name": "InvalidTokenIdMapPoolIx", - "msg": "Invalid Pool Ix for Token Id Map" + "name": "InvalidTokenNumberMapPoolTokenIndex", + "msg": "Invalid Pool Token Index for Token Number Map" }, { "code": 6034, + "name": "InvalidTokenNumberMapPoolTokenMint", + "msg": "Invalid Pool Token Mint for Token Number Map" + }, + { + "code": 6035, + "name": "InvalidTokenNumberMapToTokenStep", + "msg": "Invalid To Token Step for Token Number Map" + }, + { + "code": 6036, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6035, + "code": 6037, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6036, + "code": 6038, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6037, + "code": 6039, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6038, + "code": 6040, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6039, + "code": 6041, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6040, + "code": 6042, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6041, + "code": 6043, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6042, + "code": 6044, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6043, + "code": 6045, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6044, + "code": 6046, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6045, + "code": 6047, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6046, + "code": 6048, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6047, - "name": "TokenIdMapExists", - "msg": "TokenIdMap exists. Please use the correct instruction" - }, - { - "code": 6048, - "name": "InvalidTokenIdMapAccountAddress", - "msg": "Invalid address for TokenIdMap account" + "code": 6049, + "name": "TokenNumberMapExists", + "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6049, + "code": 6050, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6050, + "code": 6051, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6051, + "code": 6052, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" - } - ] -}; - + }, + { + "code": 6053, + "name": "InvalidMemo", + "msg": "Invalid Memo" + }, + { + "code": 6054, + "name": "ToTokenNumberMismatch", + "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" + }, + { + "code": 6055, + "name": "IsPaused", + "msg": "Routing Contract is paused" + }, + { + "code": 6056, + "name": "TargetChainIsPaused", + "msg": "Target Chain is paused" + }, + { + "code": 6057, + "name": "InvalidSwimPayloadMessagePayer", + "msg": "Invalid SwimPayloadMessagePayer" + } + ] +}; + export const IDL: Propeller = { "version": "0.1.0", "name": "propeller", @@ -4872,7 +5332,413 @@ export const IDL: Propeller = { } }, { - "name": "propellerRedeemer", + "name": "propellerRedeemer", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "redeemer" + } + ] + } + }, + { + "name": "propellerRedeemerEscrow", + "isMut": true, + "isSigner": false + }, + { + "name": "propellerFeeVault", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + }, + { + "name": "swimUsdMint", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "pool_token_mint_0" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "pool_token_mint_1" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolTokenMint0", + "isMut": false, + "isSigner": false + }, + { + "name": "poolTokenMint1", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeParams" + } + } + ] + }, + { + "name": "setPaused", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, + { + "name": "changePauseKey", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "prepareGovernanceTransition", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "enactGovernanceTransition", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "createTokenNumberMap", + "accounts": [ + { + "name": "propeller", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "pool", + "isMut": false, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "arg", + "type": "publicKey", + "path": "pool.token_mint_keys [0]" + }, + { + "kind": "arg", + "type": "publicKey", + "path": "pool.token_mint_keys [1]" + }, + { + "kind": "arg", + "type": "publicKey", + "path": "pool.lp_mint_key" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "tokenNumberMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "token_id" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + }, + { + "kind": "arg", + "type": "u16", + "path": "to_token_number" + } + ] + } + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "toTokenNumber", + "type": "u16" + }, + { + "name": "pool", + "type": "publicKey" + }, + { + "name": "poolTokenIndex", + "type": "u8" + }, + { + "name": "poolTokenMint", + "type": "publicKey" + }, + { + "name": "toTokenStep", + "type": { + "defined": "ToTokenStep" + } + } + ] + }, + { + "name": "updateTokenNumberMap", + "accounts": [ + { + "name": "propeller", "isMut": false, "isSigner": false, "pda": { @@ -4880,31 +5746,22 @@ export const IDL: Propeller = { { "kind": "const", "type": "string", - "value": "redeemer" + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } }, { - "name": "propellerRedeemerEscrow", - "isMut": true, - "isSigner": false - }, - { - "name": "propellerFeeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, - { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - }, { "name": "payer", "isMut": true, @@ -4912,6 +5769,11 @@ export const IDL: Propeller = { }, { "name": "pool", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenNumberMap", "isMut": true, "isSigner": false, "pda": { @@ -4919,91 +5781,56 @@ export const IDL: Propeller = { { "kind": "const", "type": "string", - "value": "two_pool" + "value": "propeller" }, { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "pool_token_mint_0" + "kind": "const", + "type": "string", + "value": "token_id" }, { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "pool_token_mint_1" + "account": "Propeller", + "path": "propeller" }, { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "kind": "arg", + "type": "u16", + "path": "to_token_number" } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } + ] } }, - { - "name": "poolTokenMint0", - "isMut": false, - "isSigner": false - }, - { - "name": "poolTokenMint1", - "isMut": false, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": false, - "isSigner": false - }, { "name": "twoPoolProgram", "isMut": false, "isSigner": false - }, - { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, + } + ], + "args": [ { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + "name": "toTokenNumber", + "type": "u16" }, { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false + "name": "poolTokenIndex", + "type": "u8" }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + "name": "poolTokenMint", + "type": "publicKey" }, { - "name": "rent", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "params", + "name": "toTokenStep", "type": { - "defined": "InitializeParams" + "defined": "ToTokenStep" } } ] }, { - "name": "createTokenIdMap", + "name": "closeTokenNumberMap", "accounts": [ { "name": "propeller", @@ -5026,7 +5853,7 @@ export const IDL: Propeller = { } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -5036,42 +5863,52 @@ export const IDL: Propeller = { "isSigner": true }, { - "name": "pool", - "isMut": false, + "name": "tokenNumberMap", + "isMut": true, "isSigner": false, "pda": { "seeds": [ { "kind": "const", "type": "string", - "value": "two_pool" + "value": "propeller" }, { - "kind": "arg", - "type": "publicKey", - "path": "pool" + "kind": "const", + "type": "string", + "value": "token_id" }, { - "kind": "arg", + "kind": "account", "type": "publicKey", - "path": "pool" + "account": "Propeller", + "path": "propeller" }, { "kind": "arg", - "type": "publicKey", - "path": "pool.lp_mint_key" + "type": "u16", + "path": "to_token_number" } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } + ] } - }, + } + ], + "args": [ { - "name": "tokenIdMap", - "isMut": true, + "name": "toTokenNumber", + "type": "u16" + } + ] + }, + { + "name": "createTargetChainMap", + "docs": [ + "Target Chain Map *" + ], + "accounts": [ + { + "name": "propeller", + "isMut": false, "isSigner": false, "pda": { "seeds": [ @@ -5080,10 +5917,35 @@ export const IDL: Propeller = { "type": "string", "value": "propeller" }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "targetChainMap", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ { "kind": "const", "type": "string", - "value": "token_id" + "value": "propeller" }, { "kind": "account", @@ -5094,7 +5956,7 @@ export const IDL: Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_index" + "path": "target_chain" } ] } @@ -5103,40 +5965,26 @@ export const IDL: Propeller = { "name": "systemProgram", "isMut": false, "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false } ], "args": [ { - "name": "targetTokenIndex", + "name": "targetChain", "type": "u16" }, { - "name": "pool", - "type": "publicKey" - }, - { - "name": "poolTokenIndex", - "type": "u8" - }, - { - "name": "poolTokenMint", - "type": "publicKey" - }, - { - "name": "poolIx", + "name": "targetAddress", "type": { - "defined": "PoolInstruction" + "array": [ + "u8", + 32 + ] } } ] }, { - "name": "createTargetChainMap", + "name": "updateTargetChainMap", "accounts": [ { "name": "propeller", @@ -5159,7 +6007,7 @@ export const IDL: Propeller = { } }, { - "name": "admin", + "name": "governanceKey", "isMut": false, "isSigner": true }, @@ -5186,26 +6034,18 @@ export const IDL: Propeller = { "path": "propeller" }, { - "kind": "arg", + "kind": "account", "type": "u16", - "path": "target_chain" + "account": "TargetChainMap", + "path": "target_chain_map.target_chain" } ] } - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [ { - "name": "targetChain", - "type": "u16" - }, - { - "name": "targetAddress", + "name": "routingContract", "type": { "array": [ "u8", @@ -5216,7 +6056,7 @@ export const IDL: Propeller = { ] }, { - "name": "updateTargetChainMap", + "name": "targetChainMapSetPaused", "accounts": [ { "name": "propeller", @@ -5239,7 +6079,7 @@ export const IDL: Propeller = { } }, { - "name": "admin", + "name": "pauseKey", "isMut": false, "isSigner": true }, @@ -5273,22 +6113,12 @@ export const IDL: Propeller = { } ] } - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [ { - "name": "routingContract", - "type": { - "array": [ - "u8", - 32 - ] - } + "name": "isPaused", + "type": "bool" } ] }, @@ -6238,6 +7068,10 @@ export const IDL: Propeller = { } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -6548,6 +7382,10 @@ export const IDL: Propeller = { } ], "args": [ + { + "name": "nonce", + "type": "u32" + }, { "name": "amount", "type": "u64" @@ -6628,8 +7466,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -6699,13 +7536,53 @@ export const IDL: Propeller = { "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, + { + "name": "swimPayloadMessage", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "swim_payload" + }, + { + "kind": "account", + "type": "publicKey", + "path": "claim" + } + ] + } + }, { "name": "custody", "isMut": true, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { "name": "swimUsdMint", @@ -6715,56 +7592,46 @@ export const IDL: Propeller = { { "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "rent", + "name": "wormhole", "isMut": false, "isSigner": false }, { - "name": "systemProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "wormhole", + "name": "tokenBridge", "isMut": false, "isSigner": false }, { - "name": "tokenProgram", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "tokenBridge", + "name": "rent", "isMut": false, "isSigner": false - }, - { - "name": "swimPayloadMessage", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "swim_payload" - }, - { - "kind": "account", - "type": "publicKey", - "path": "claim" - } - ] - } } ], "args": [] @@ -6915,7 +7782,7 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -6939,7 +7806,7 @@ export const IDL: Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -7034,7 +7901,7 @@ export const IDL: Propeller = { ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" }, { @@ -7090,8 +7957,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -7161,13 +8027,53 @@ export const IDL: Propeller = { "isSigner": false, "docs": [ "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" + "recipient of fees for executing complete transfer (e.g. relayer)", + "this is only used in `propellerCompleteNativeWithPayload`." ] }, + { + "name": "swimPayloadMessage", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "const", + "type": "string", + "value": "swim_payload" + }, + { + "kind": "account", + "type": "publicKey", + "path": "claim" + } + ] + } + }, { "name": "custody", "isMut": true, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "swim_usd_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { "name": "swimUsdMint", @@ -7177,56 +8083,46 @@ export const IDL: Propeller = { { "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "rent", + "name": "wormhole", "isMut": false, "isSigner": false }, { - "name": "systemProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "wormhole", + "name": "tokenBridge", "isMut": false, "isSigner": false }, { - "name": "tokenProgram", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "tokenBridge", + "name": "rent", "isMut": false, "isSigner": false - }, - { - "name": "swimPayloadMessage", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "swim_payload" - }, - { - "kind": "account", - "type": "publicKey", - "path": "claim" - } - ] - } } ] }, @@ -7490,7 +8386,7 @@ export const IDL: Propeller = { } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -7830,7 +8726,7 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "pda": { @@ -7854,7 +8750,7 @@ export const IDL: Propeller = { { "kind": "arg", "type": "u16", - "path": "target_token_id" + "path": "to_token_number" } ] } @@ -8070,7 +8966,7 @@ export const IDL: Propeller = { ], "args": [ { - "name": "targetTokenId", + "name": "toTokenNumber", "type": "u16" } ], @@ -8526,11 +9422,11 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "isMut": false, "isSigner": false, "docs": [ - "deserialized as a `TokenIdMap`. if it does exist, then engine should have called", + "deserialized as a `TokenNumberMap`. if it does exist, then engine should have called", "propeller_create_owner_token_accounts instead" ], "pda": { @@ -8740,17 +9636,25 @@ export const IDL: Propeller = { 32 ] } + }, + { + "name": "isPaused", + "type": "bool" } ] } }, { - "name": "tokenIdMap", + "name": "tokenNumberMap", "type": { "kind": "struct", "fields": [ { - "name": "outputTokenIndex", + "name": "bump", + "type": "u8" + }, + { + "name": "toTokenNumber", "type": "u16" }, { @@ -8766,14 +9670,10 @@ export const IDL: Propeller = { "type": "publicKey" }, { - "name": "poolIx", + "name": "toTokenStep", "type": { - "defined": "PoolInstruction" + "defined": "ToTokenStep" } - }, - { - "name": "bump", - "type": "u8" } ] } @@ -8788,19 +9688,23 @@ export const IDL: Propeller = { "type": "u8" }, { - "name": "nonce", - "type": "u32" + "name": "isPaused", + "type": "bool" }, { - "name": "admin", + "name": "governanceKey", "type": "publicKey" }, { - "name": "wormhole", + "name": "preparedGovernanceKey", "type": "publicKey" }, { - "name": "tokenBridge", + "name": "governanceTransitionTs", + "type": "i64" + }, + { + "name": "pauseKey", "type": "publicKey" }, { @@ -9321,7 +10225,7 @@ export const IDL: Propeller = { } }, { - "name": "PoolInstruction", + "name": "ToTokenStep", "type": { "kind": "enum", "variants": [ @@ -9337,20 +10241,6 @@ export const IDL: Propeller = { ] } }, - { - "name": "SwimPayloadVersion", - "type": { - "kind": "enum", - "variants": [ - { - "name": "V0" - }, - { - "name": "V1" - } - ] - } - }, { "name": "ConsistencyLevel", "type": { @@ -9517,7 +10407,7 @@ export const IDL: Propeller = { { "code": 6023, "name": "StaleFeed", - "msg": "Switchboard feed has not been updated in 5 minutes" + "msg": "Switchboard feed value is stale " }, { "code": 6024, @@ -9531,133 +10421,163 @@ export const IDL: Propeller = { }, { "code": 6026, - "name": "InvalidClaimData", - "msg": "Invalid claim data" + "name": "InvalidWormholeClaimAccount", + "msg": "Invalid Wormhole Claim Account" }, { "code": 6027, - "name": "ClaimNotClaimed", - "msg": "Claim Account not claimed" + "name": "InvalidClaimData", + "msg": "Invalid claim data" }, { "code": 6028, - "name": "InvalidPropellerAdmin", - "msg": "Invalid Propeller Admin" + "name": "ClaimNotClaimed", + "msg": "Claim Account not claimed" }, { "code": 6029, - "name": "InvalidTokenIdMapPool", - "msg": "Invalid Pool for Token Id Map" + "name": "InvalidPropellerGovernanceKey", + "msg": "Invalid Propeller GovernanceKey" }, { "code": 6030, - "name": "InvalidOutputTokenIndex", - "msg": "Invalid Output Token Index" + "name": "InvalidPropellerPauseKey", + "msg": "Invalid Propeller Pause Key" }, { "code": 6031, - "name": "InvalidTokenIdMapPoolTokenIndex", - "msg": "Invalid Pool Token Index for Token Id Map" + "name": "InvalidTokenNumberMapPool", + "msg": "Invalid Pool for Token Number Map" }, { "code": 6032, - "name": "InvalidTokenIdMapPoolTokenMint", - "msg": "Invalid Pool Token Mint for Token Id Map" + "name": "InvalidOutputTokenIndex", + "msg": "Invalid Output Token Index" }, { "code": 6033, - "name": "InvalidTokenIdMapPoolIx", - "msg": "Invalid Pool Ix for Token Id Map" + "name": "InvalidTokenNumberMapPoolTokenIndex", + "msg": "Invalid Pool Token Index for Token Number Map" }, { "code": 6034, + "name": "InvalidTokenNumberMapPoolTokenMint", + "msg": "Invalid Pool Token Mint for Token Number Map" + }, + { + "code": 6035, + "name": "InvalidTokenNumberMapToTokenStep", + "msg": "Invalid To Token Step for Token Number Map" + }, + { + "code": 6036, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6035, + "code": 6037, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6036, + "code": 6038, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6037, + "code": 6039, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6038, + "code": 6040, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6039, + "code": 6041, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6040, + "code": 6042, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6041, + "code": 6043, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6042, + "code": 6044, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6043, + "code": 6045, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6044, + "code": 6046, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6045, + "code": 6047, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6046, + "code": 6048, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6047, - "name": "TokenIdMapExists", - "msg": "TokenIdMap exists. Please use the correct instruction" - }, - { - "code": 6048, - "name": "InvalidTokenIdMapAccountAddress", - "msg": "Invalid address for TokenIdMap account" + "code": 6049, + "name": "TokenNumberMapExists", + "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6049, + "code": 6050, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6050, + "code": 6051, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6051, + "code": 6052, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" + }, + { + "code": 6053, + "name": "InvalidMemo", + "msg": "Invalid Memo" + }, + { + "code": 6054, + "name": "ToTokenNumberMismatch", + "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" + }, + { + "code": 6055, + "name": "IsPaused", + "msg": "Routing Contract is paused" + }, + { + "code": 6056, + "name": "TargetChainIsPaused", + "msg": "Target Chain is paused" + }, + { + "code": 6057, + "name": "InvalidSwimPayloadMessagePayer", + "msg": "Invalid SwimPayloadMessagePayer" } ] }; From f1fb75b3f8c8ab4270e5355725ee99565814987b Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 19 Oct 2022 08:10:53 -0400 Subject: [PATCH 10/17] refactor: clean up unused test util methods --- .../src/__tests__/propeller/propellerUtils.ts | 189 ------------------ 1 file changed, 189 deletions(-) diff --git a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts index cbf161da1..f5b648323 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts @@ -110,117 +110,6 @@ export const getSwimPayloadMessagePda = async ( propellerProgramId, ); }; -// -// async function addToPool( -// provider: anchor.AnchorProvider, -// pool: web3.PublicKey, -// poolState: SwimPoolState, -// userTokenAccounts: web3.PublicKey[], -// userLpTokenAccount: web3.PublicKey, -// inputAmounts: anchor.BN[], -// minimumMintAmount: anchor.BN, -// tokenAccountOwner: web3.Keypair, -// delegate: web3.PublicKey, -// ): Promise { -// // let userMetapoolTokenAccountAmounts = await Promise.all( -// // userMetapoolTokenAccounts.map(async (account) => { -// // return (await splToken.account.token.fetch(account)).amount; -// // })); -// // console.log(`userMetapoolTokenAccountAmounts: ${userMetapoolTokenAccountAmounts}`) -// // let userMetapoolTokenAccounts0Amount = await splToken.account.token.fetch(userMetapoolTokenAccounts[0]); -// // let inputAmounts = [new anchor.BN(100), new anchor.BN(100)]; -// -// const addMetapoolIx = addToPoolIx( -// { -// provider, -// pool, -// poolState, -// userTokenAccounts, -// userLpTokenAccount, -// inputAmounts, -// minimumMintAmount, -// }); -// const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( -// anchor.BN.max(inputAmounts[0]!, inputAmounts[1]!), -// tokenAccountOwner.publicKey, -// delegate, -// userTokenAccounts -// ); -// const seedMetapoolTxn = new web3.Transaction() -// .add(...approveIxs!) -// .add(addMetapoolIx) -// .add(...revokeIxs!); -// seedMetapoolTxn.recentBlockhash = (await connection.getLatestBlockhash()).blockhash -// return await provider.sendAndConfirm( -// seedMetapoolTxn, -// [dummyUser], -// { -// skipPreflight: true, -// } -// ); -// } -// -// async function createAtaAndMint(mint: web3.PublicKey) { -// const tokenAccount = await getOrCreateAssociatedTokenAccount( -// connection, -// payer, -// mint, -// dummyUser.publicKey, -// false -// ); -// const mintTxn = await mintTo( -// connection, -// payer, -// mint, -// tokenAccount.address, -// payer, -// initialMintAmount, -// ); -// -// await connection.confirmTransaction({ -// signature: mintTxn, -// ...(await connection.getLatestBlockhash()) -// }) -// console.log(`minted to user_token_account: ${tokenAccount.address.toBase58()}`); -// return tokenAccount -// } - -// const parseTokenTransferWithSwimPayloadPostedMessage = async (arr: Buffer) => { -// const {parse_posted_message} = await importCoreWasm(); -// const postedMessage = parse_posted_message(arr); -// const tokenTransfer = parseTransferWithPayload(Buffer.from(postedMessage.payload)); -// // console.log(`swimPayloadRawBufferStr: ${tokenTransfer.payload.toString()}`); -// const swimPayload = parseSwimPayload(tokenTransfer.payload); -// return { -// ...postedMessage, -// vaa_signature_account: new web3.PublicKey(postedMessage.vaa_signature_account).toBase58(), -// // emitter_address: tryHexToNativeAssetString(postedMessage.emitter_address, postedMessage.emitter_chain), -// // emitter_address: new web3.PublicKey(postedMessage.emitter_address).toBase58(), -// emitter_address: tryUint8ArrayToNative(postedMessage.emitter_address, postedMessage.emitter_chain), -// -// payload: { -// ...tokenTransfer, -// amount: tokenTransfer.amount.toString(), -// originAddress: tryHexToNativeAssetString(tokenTransfer.originAddress, tokenTransfer.originChain), -// originChain: toChainName(tokenTransfer.originChain), -// targetAddress: tryHexToNativeAssetString(tokenTransfer.targetAddress, tokenTransfer.targetChain), -// targetChain: toChainName(tokenTransfer.targetChain), -// fromAddress: tryHexToNativeAssetString(tokenTransfer.fromAddress, postedMessage.emitter_chain), -// payload: { -// ...swimPayload, -// minOutputAmount: swimPayload.minOutputAmount.toString(), -// memo: swimPayload.memo.toString(), -// propellerMinThreshold: swimPayload.propellerMinThreshold.toString(), -// // propellerFee: swimPayload.propellerFee.toString(), -// // targetTokenStr: swimPayload.targetToken.toString(), -// // targetTokenHexStr: swimPayload.targetToken.toString("hex"), -// // ownerStr: swimPayload.owner.toString(), -// ownerNativeStr: tryHexToNativeAssetString(swimPayload.owner.toString("hex"), tokenTransfer.targetChain), -// // ownerHexStr: swimPayload.owner.toString("hex"), -// } -// } -// } -// } // 1 byte - swim internal payload version number // 32 bytes - logical owner/recipient (will use ATA of owner and token on Solana) @@ -946,84 +835,6 @@ export const generatePropellerEngineTxns = async ( return txns; }; -export const getCompleteNativeWithPayloadAccounts3 = async ( - tokenTransferWithPayloadSignedVaa: Buffer, - wormholeAddresses: WormholeAddresses, - propellerProgram: Program, -) => { - const { - custody, - custodySigner, - ethEndpointAccount, - tokenBridge, - tokenBridgeConfig, - wormhole, - } = wormholeAddresses; - const [wormholeMessage] = await deriveMessagePda( - tokenTransferWithPayloadSignedVaa, - wormhole, - ); - const wormholeClaim = await getClaimAddressSolana( - tokenBridge.toBase58(), - tokenTransferWithPayloadSignedVaa, - ); - const [swimPayloadMessage] = await getSwimPayloadMessagePda( - wormholeClaim, - propellerProgram.programId, - ); - const { tokenTransferVaa } = parseTokenTransferWithSwimPayloadSignedVaa( - tokenTransferWithPayloadSignedVaa, - ); - - const swimUsdMint = new web3.PublicKey( - tryUint8ArrayToNative( - tokenTransferVaa.tokenTransfer.tokenAddress, - tokenTransferVaa.tokenTransfer.tokenChain, - ), - ); - - const propeller = await getPropellerPda( - swimUsdMint, - propellerProgram.programId, - ); - - const propellerData = await propellerProgram.account.propeller.fetch( - propeller, - ); - const propellerFeeVault = propellerData.feeVault; - - const propellerRedeemer = await getPropellerRedeemerPda( - propellerProgram.programId, - ); - - const propellerRedeemerEscrowAccount = await getAssociatedTokenAddress( - swimUsdMint, - propellerRedeemer, - true, - ); - - return propellerProgram.methods.completeNativeWithPayload().accounts({ - propeller, - payer: propellerProgram.provider.publicKey, - tokenBridgeConfig, - message: wormholeMessage, - claim: wormholeClaim, - swimPayloadMessage: swimPayloadMessage, - endpoint: ethEndpointAccount, - redeemerEscrow: propellerRedeemerEscrowAccount, - redeemer: propellerRedeemer, - feeVault: propellerFeeVault, - custody: custody, - swimUsdMint: swimUsdMint, - custodySigner, - rent: web3.SYSVAR_RENT_PUBKEY, - systemProgram: web3.SystemProgram.programId, - wormhole: wormholeAddresses.wormhole, - tokenProgram: TOKEN_PROGRAM_ID, - tokenBridge: wormholeAddresses.tokenBridge, - }); -}; - export const getCompleteNativeWithPayloadAccounts = async ( tokenTransferWithPayloadSignedVaa: Buffer, wormhole: web3.PublicKey, From d147dfdd345ffbc9461ea5ecba456c3be7e3ee1b Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 25 Oct 2022 07:33:33 -0400 Subject: [PATCH 11/17] refactor(solana-contracts): add feeTracking struct --- .../programs/propeller/src/constants.rs | 22 +- .../programs/propeller/src/error.rs | 21 + .../programs/propeller/src/fees.rs | 136 +- .../create_owner_token_accounts.rs | 294 +- .../src/instructions/governance/gov.rs | 30 +- .../src/instructions/governance/pause.rs | 18 +- .../src/instructions/marginal_price_pool.rs | 133 + .../propeller/src/instructions/mod.rs | 5 +- .../src/instructions/process_swim_payload.rs | 297 +- .../src/instructions/target_chain_map.rs | 20 +- .../src/instructions/two_pool_cpi/add.rs | 100 +- .../two_pool_cpi/init_to_swim_usd.rs | 193 ++ .../src/instructions/two_pool_cpi/mod.rs | 4 +- .../two_pool_cpi/swap_exact_input.rs | 14 +- .../two_pool_cpi/swap_exact_output.rs | 6 +- .../propeller/src/instructions/utils.rs | 190 +- .../wormhole/complete_native_with_payload.rs | 176 +- .../wormhole/transfer_native_with_payload.rs | 56 +- .../programs/propeller/src/lib.rs | 219 +- .../programs/propeller/src/state/propeller.rs | 17 +- .../programs/two-pool/src/instructions/add.rs | 2 +- .../src/instructions/defi/add_or_remove.rs | 282 ++ .../two-pool/src/instructions/defi/mod.rs | 75 + .../governance/enact_governance_transition.rs | 5 +- .../two-pool/src/instructions/initialize.rs | 2 + .../programs/two-pool/src/instructions/mod.rs | 3 +- .../src/instructions/swap_exact_input.rs | 5 - .../programs/two-pool/src/lib.rs | 22 +- .../scripts/initializePropeller.ts | 4 +- packages/solana-contracts/scripts/scratch.ts | 2 +- .../solana-contracts/src/__tests__/consts.ts | 23 +- .../src/__tests__/propeller/engine.test.ts | 535 +-- .../src/__tests__/propeller/propeller.test.ts | 737 ++-- .../src/__tests__/propeller/propellerUtils.ts | 232 +- .../src/__tests__/twoPool/pool.test.ts | 60 +- .../src/__tests__/twoPool/poolTestUtils.ts | 48 + .../src/artifacts/propeller.json | 1564 ++++----- .../src/artifacts/propeller.ts | 3030 +++++++---------- .../src/artifacts/two_pool.json | 143 +- .../src/artifacts/two_pool.ts | 286 +- 40 files changed, 4389 insertions(+), 4622 deletions(-) create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs create mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs create mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs diff --git a/packages/solana-contracts/programs/propeller/src/constants.rs b/packages/solana-contracts/programs/propeller/src/constants.rs index 802141ad7..e7d875977 100644 --- a/packages/solana-contracts/programs/propeller/src/constants.rs +++ b/packages/solana-contracts/programs/propeller/src/constants.rs @@ -2,34 +2,16 @@ use {num_traits::FromPrimitive, rust_decimal::Decimal}; pub const CURRENT_SWIM_PAYLOAD_VERSION: u8 = 1; pub const TOKEN_COUNT: usize = 2; +pub const ENACT_DELAY: i64 = 3 * 86400; -// seed prefixes -// pub const SEED_PREFIX_CUSTODIAN: &str = "icco-custodian"; -// pub const SEED_PREFIX_SALE: &str = "icco-sale"; -// pub const SEED_PREFIX_BUYER: &str = "icco-buyer"; - -pub const CHAIN_ID_SOL: u16 = 1; -pub const CHAIN_ID_ETH: u16 = 2; - -pub const TOKEN_BRIDGE_MINT_OUTPUT_TOKEN_INDEX: usize = 0; -pub const SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX: u8 = 0; +pub const METAPOOL_SWIM_USD_INDEX: u8 = 0; pub const REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX: u8 = 0; pub const SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX: u8 = 1; /// Pool IXs for sending ignore slippage pub const PROPELLER_MINIMUM_OUTPUT_AMOUNT: u64 = 0u64; -// pub const LAMPORTS_PER_SOL_DECIMAL: Decimal = Decimal::from_u64(1_000_000_000u64).unwrap(); pub const LAMPORTS_PER_SOL_DECIMAL: Decimal = Decimal::from_parts(1_000_000_000u32, 0, 0, false, 0u32); -#[cfg(all(feature = "localnet", not(feature = "devnet"), not(feature = "mainnet")))] -pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE"; - -#[cfg(all(feature = "devnet", not(feature = "localnet"), not(feature = "mainnet")))] -pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe"; - -#[cfg(all(feature = "mainnet", not(feature = "localnet"), not(feature = "devnet")))] -pub const TOKEN_BRIDGE_PROGRAM_ID: &str = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb"; - #[cfg(test)] mod test { use super::*; diff --git a/packages/solana-contracts/programs/propeller/src/error.rs b/packages/solana-contracts/programs/propeller/src/error.rs index 91f9135f1..86ad8be8c 100644 --- a/packages/solana-contracts/programs/propeller/src/error.rs +++ b/packages/solana-contracts/programs/propeller/src/error.rs @@ -36,6 +36,9 @@ pub enum PropellerError { #[msg("TransferNotAllowed")] TransferNotAllowed, + #[msg("Invalid Pool for Init To SwimUSD")] + InvalidPoolForInitToSwimUsd, + #[msg("Incorrect ProgramId for CPI return value")] InvalidCpiReturnProgramId, @@ -174,6 +177,24 @@ pub enum PropellerError { #[msg("Target Chain is paused")] TargetChainIsPaused, + #[msg("Invalid Target Chain Map")] + InvalidTargetChainMap, + #[msg("Invalid SwimPayloadMessagePayer")] InvalidSwimPayloadMessagePayer, + + #[msg("Invalid New Pause Key for UpdatePauseKey")] + InvalidNewPauseKey, + + #[msg("Invalid Upcoming Governance Key for Prepare Governance Transition")] + InvalidUpcomingGovernanceKey, + + #[msg("Invalid Enact Governance Transition")] + InvalidEnact, + + #[msg("Insufficient Delay for Enact Governance Transition")] + InsufficientDelay, + + #[msg("Invalid Fee Tracker")] + InvalidFeeTracker, } diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs index ae6ff024e..566dc02ca 100644 --- a/packages/solana-contracts/programs/propeller/src/fees.rs +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -1,9 +1,137 @@ -use {crate::TOKEN_COUNT, anchor_lang::prelude::*, two_pool::BorshDecimal}; +use { + crate::{ + constants::LAMPORTS_PER_SOL_DECIMAL, marginal_price_pool::*, FeeTracker, Propeller, PropellerError, TOKEN_COUNT, + }, + anchor_lang::prelude::*, + anchor_spl::{ + token, + token::{Token, TokenAccount, Transfer}, + }, + num_traits::{FromPrimitive, ToPrimitive}, + rust_decimal::Decimal, + switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, + two_pool::BorshDecimal, +}; pub trait Fees<'info> { /// Calculate the fees, including txn and rent exemptions, in lamports. fn calculate_fees_in_lamports(&self) -> Result; - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]>; - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result; - fn track_and_transfer_fees(&mut self, fees_in_swim_usd: u64) -> Result<()>; + // fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]>; + // fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result; + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()>; +} + +#[derive(Accounts)] +pub struct FeeTracking<'info> { + #[account( + constraint = + *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount, + )] + pub aggregator: AccountLoader<'info, AggregatorAccountData>, + + #[account(mut)] + /// this is "to_fees" + /// recipient of fees for executing complete transfer (e.g. relayer) + pub fee_vault: Box>, + + #[account(mut)] + pub fee_tracker: Box>, + pub marginal_price_pool: MarginalPricePool<'info>, +} + +impl<'info> FeeTracking<'info> { + pub fn validate(&self, propeller: &Propeller, payer: &Pubkey, program_id: &Pubkey) -> Result<()> { + require_keys_eq!( + self.marginal_price_pool.pool.key(), + propeller.marginal_price_pool, + PropellerError::InvalidMarginalPricePool + ); + require_keys_eq!(self.fee_vault.key(), propeller.fee_vault, PropellerError::InvalidFeeVault); + require_keys_eq!(self.aggregator.key(), propeller.aggregator, PropellerError::InvalidAggregator); + let expected_fee_tracker = Pubkey::create_program_address( + &[ + b"propeller".as_ref(), + b"fee".as_ref(), + propeller.swim_usd_mint.as_ref(), + payer.as_ref(), + &[self.fee_tracker.bump], + ], + program_id, + ) + .map_err(|_| PropellerError::InvalidFeeTracker)?; + require_keys_eq!(self.fee_tracker.key(), expected_fee_tracker, PropellerError::InvalidFeeTracker); + msg!("finished fees tracking validation"); + self.marginal_price_pool.validate(propeller) + } + + pub fn two_pool_program_key(&self) -> Pubkey { + self.marginal_price_pool.two_pool_program.key() + } + + pub fn track_fees(&mut self, fees_in_lamports: u64, propeller: &Propeller) -> Result { + let fee_in_swim_usd_atomic = self.convert_fees_to_swim_usd_atomic(fees_in_lamports, propeller)?; + self.update_fee_tracker(fee_in_swim_usd_atomic) + } + + fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64, propeller: &Propeller) -> Result { + let intermediate_token_price_decimal: Decimal = + self.marginal_price_pool.get_marginal_price_decimal(&propeller)?; + + 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 lamports_intermediate_token_price = self.get_lamports_intermediate_token_price(propeller)?; + 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, &self.marginal_price_pool, &marginal_price_pool_lp_mint)?; + let swim_usd_decimals = self.marginal_price_pool.get_swim_usd_mint_decimals(propeller)?; + 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 + ); + Ok(fee_in_swim_usd_atomic) + } + + fn get_lamports_intermediate_token_price(&self, propeller: &Propeller) -> Result { + let feed = self.aggregator.load()?; + feed.check_staleness(Clock::get().unwrap().unix_timestamp, propeller.max_staleness) + .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 sol_usd_price: Decimal = feed.get_result()?.try_into()?; + + 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); + Ok(lamports_usd_price) + // check whether the feed has been updated in the last 300 seconds + } + + fn update_fee_tracker(&mut self, fees_in_swim_usd_atomic: u64) -> Result { + let fee_tracker = &mut self.fee_tracker; + fee_tracker.fees_owed = + fee_tracker.fees_owed.checked_add(fees_in_swim_usd_atomic).ok_or(PropellerError::IntegerOverflow)?; + Ok(fees_in_swim_usd_atomic) + } } 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 52d814e12..a128f759b 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 @@ -1,11 +1,12 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { crate::{ - constants::{LAMPORTS_PER_SOL_DECIMAL, TOKEN_BRIDGE_PROGRAM_ID}, - convert_fees_to_swim_usd_atomic, deserialize_message_payload, + constants::LAMPORTS_PER_SOL_DECIMAL, + deserialize_message_payload, error::*, - get_lamports_intermediate_token_price, get_marginal_price_decimal, get_memo_as_utf8, get_message_data, - get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, + fees::*, + get_memo_as_utf8, get_message_data, get_transfer_with_payload_from_message_account, hash_vaa, + marginal_price_pool::*, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, token_number_map::{ToTokenStep, TokenNumberMap}, @@ -28,8 +29,6 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { #[account( seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = aggregator @ PropellerError::InvalidAggregator, - has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, @@ -50,23 +49,6 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, - #[account( - mut, - address = get_associated_token_address(&propeller.key(), &propeller.swim_usd_mint) - )] - pub fee_vault: Box>, - - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - b"fee".as_ref(), - propeller.swim_usd_mint.as_ref(), - payer.key().as_ref() - ], - bump = fee_tracker.bump - )] - pub fee_tracker: Account<'info, FeeTracker>, #[account( seeds = [ @@ -75,7 +57,7 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { swim_payload_message.vaa_sequence.to_be_bytes().as_ref(), ], bump, - seeds::program = propeller.token_bridge().unwrap(), + seeds::program = propeller.token_bridge(), )] /// CHECK: WH Claim account pub claim: UncheckedAccount<'info>, @@ -113,7 +95,7 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { pool_lp_mint.key().as_ref(), ], bump = pool.bump, - seeds::program = two_pool_program.key() + seeds::program = fee_tracking.two_pool_program_key(), )] pub pool: Box>, #[account(address = pool.token_mint_keys[0])] @@ -147,33 +129,7 @@ pub struct PropellerCreateOwnerTokenAccounts<'info> { pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, - /* for sol -> token_bridge_mint conversion */ - #[account( - constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount - )] - pub aggregator: AccountLoader<'info, AggregatorAccountData>, - - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - marginal_price_pool_token_0_account.mint.as_ref(), - marginal_price_pool_token_1_account.mint.as_ref(), - marginal_price_pool_lp_mint.key().as_ref(), - ], - bump = marginal_price_pool.bump, - 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>, + pub fee_tracking: FeeTracking<'info>, #[account(executable, address = spl_memo::id())] ///CHECK: memo program pub memo: UncheckedAccount<'info>, @@ -184,11 +140,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_number_map.pool); let propeller = &ctx.accounts.propeller; - validate_marginal_prices_pool_accounts( - &propeller, - &ctx.accounts.marginal_price_pool, - &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], - )?; + let payer = &ctx.accounts.payer.key(); + ctx.accounts.fee_tracking.validate(propeller, payer, ctx.program_id)?; + // ctx.accounts.marginal_price_pool.validate(&propeller)?; + // validate_marginal_prices_pool_accounts( + // &propeller, + // &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(()) } @@ -276,76 +235,13 @@ impl<'info> Fees<'info> for PropellerCreateOwnerTokenAccounts<'info> { Ok(create_owner_token_account_total_fees_in_lamports) } - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = two_pool::cpi::marginal_prices(CpiContext::new( - self.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(), - }, - ))?; - Ok(result.get()) - } - - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - - let propeller = &self.propeller; - let max_staleness = propeller.max_staleness; - 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( - &self.marginal_price_pool, - &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 - ); - Ok(fee_in_swim_usd_atomic) - } - - 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)?; - + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()> { 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(), + to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], @@ -361,8 +257,8 @@ impl<'info> Fees<'info> for 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 create_owner_token_account_total_fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; - if create_owner_token_account_total_fees_in_lamports == 0 { + let create_owner_atas_total_fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + if create_owner_atas_total_fees_in_lamports == 0 { //TODO: log memo still? msg!("No accounts need to be initialized. Returning early"); ctx.accounts.log_memo()?; @@ -372,20 +268,21 @@ pub fn handle_propeller_create_owner_token_accounts(ctx: Context { seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, - has_one = aggregator @ PropellerError::InvalidAggregator, - has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, @@ -423,23 +318,6 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { address = get_associated_token_address(&redeemer.key(), &propeller.swim_usd_mint) )] pub redeemer_escrow: Box>, - #[account( - mut, - address = get_associated_token_address(&propeller.key(), &propeller.swim_usd_mint) - )] - pub fee_vault: Box>, - - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - b"fee".as_ref(), - propeller.swim_usd_mint.as_ref(), - payer.key().as_ref() - ], - bump = fee_tracker.bump - )] - pub fee_tracker: Account<'info, FeeTracker>, #[account( seeds = [ @@ -448,7 +326,7 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { swim_payload_message.vaa_sequence.to_be_bytes().as_ref(), ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge() )] /// CHECK: WH Claim account pub claim: UncheckedAccount<'info>, @@ -493,33 +371,8 @@ pub struct PropellerCreateOwnerSwimUsdAta<'info> { pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, - /* for sol -> token_bridge_mint conversion */ - #[account( - constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount - )] - pub aggregator: AccountLoader<'info, AggregatorAccountData>, + pub fee_tracking: FeeTracking<'info>, - // pub marginal_price_pool: MarginalPricePool<'info>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - marginal_price_pool_token_0_account.mint.as_ref(), - marginal_price_pool_token_1_account.mint.as_ref(), - marginal_price_pool_lp_mint.key().as_ref(), - ], - bump = marginal_price_pool.bump, - 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())] ///CHECK: memo program pub memo: UncheckedAccount<'info>, @@ -533,11 +386,8 @@ impl<'info> PropellerCreateOwnerSwimUsdAta<'info> { require_keys_eq!(ctx.accounts.owner.key(), ctx.accounts.swim_payload_message.owner); TokenNumberMap::assert_is_invalid(&ctx.accounts.token_id_map.to_account_info())?; let propeller = &ctx.accounts.propeller; - validate_marginal_prices_pool_accounts( - &propeller, - &ctx.accounts.marginal_price_pool, - &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], - )?; + let payer = &ctx.accounts.payer.key(); + ctx.accounts.fee_tracking.validate(propeller, payer, ctx.program_id)?; msg!("Passed PropellerCreateOwnerTokenAccounts::accounts() check"); Ok(()) } @@ -561,76 +411,13 @@ impl<'info> Fees<'info> for PropellerCreateOwnerSwimUsdAta<'info> { Ok(fees_in_lamports) } - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = two_pool::cpi::marginal_prices(CpiContext::new( - self.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(), - }, - ))?; - Ok(result.get()) - } - - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - - let propeller = &self.propeller; - let max_staleness = propeller.max_staleness; - 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( - &self.marginal_price_pool, - &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 - ); - Ok(fee_in_swim_usd_atomic) - } - - 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)?; - + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()> { 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(), + to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], @@ -641,24 +428,25 @@ impl<'info> Fees<'info> for PropellerCreateOwnerSwimUsdAta<'info> { } pub fn handle_propeller_create_owner_swim_usd_ata(ctx: Context) -> Result<()> { - let create_user_swim_usd_ata_fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; + let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; let swim_payload_owner = ctx.accounts.swim_payload_message.owner; if swim_payload_owner != ctx.accounts.payer.key() { - let create_user_swim_usd_ata_fees_in_swim_usd_atomic = - ctx.accounts.convert_fees_to_swim_usd_atomic(create_user_swim_usd_ata_fees_in_lamports)?; + // let create_user_swim_usd_ata_fees_in_swim_usd_atomic = + // ctx.accounts.convert_fees_to_swim_usd_atomic(create_user_swim_usd_ata_fees_in_lamports)?; + let propeller = &ctx.accounts.propeller; + let fees_in_swim_usd_atomic = ctx.accounts.fee_tracking.track_fees(fees_in_lamports, propeller)?; - ctx.accounts.track_and_transfer_fees(create_user_swim_usd_ata_fees_in_swim_usd_atomic)?; + ctx.accounts.transfer_fees_to_vault(fees_in_swim_usd_atomic)?; let transfer_amount = ctx.accounts.swim_payload_message.transfer_amount; - let new_transfer_amount = transfer_amount - .checked_sub(create_user_swim_usd_ata_fees_in_swim_usd_atomic) - .ok_or(error!(PropellerError::InsufficientFunds))?; + let new_transfer_amount = + transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; msg!( "transfer_amount: {} - fees_in_swim_usd: {} = {}", transfer_amount, - create_user_swim_usd_ata_fees_in_swim_usd_atomic, + fees_in_swim_usd_atomic, new_transfer_amount ); ctx.accounts.swim_payload_message.transfer_amount = new_transfer_amount; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs index 481254a30..5108d60d0 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs @@ -1,10 +1,12 @@ use { - crate::{error::*, Propeller}, + crate::{constants::ENACT_DELAY, error::*, Propeller}, anchor_lang::prelude::*, }; + #[derive(Accounts)] pub struct Governance<'info> { #[account( + mut, seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref(), @@ -14,10 +16,32 @@ pub struct Governance<'info> { )] pub propeller: Account<'info, Propeller>, pub governance_key: Signer<'info>, + pub upcoming_governance_key: Signer<'info>, +} + +pub fn handle_prepare_governance_transition(ctx: Context, upcoming_governance_key: Pubkey) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + require_keys_neq!(upcoming_governance_key, Pubkey::default(), PropellerError::InvalidUpcomingGovernanceKey); + propeller.prepared_governance_key = upcoming_governance_key; + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64); + propeller.governance_transition_ts = current_ts + ENACT_DELAY; + Ok(()) } -pub fn handle_prepare_governance_change(ctx: Context) -> Result<()> { +pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { let propeller = &mut ctx.accounts.propeller; - propeller.governance_key = *ctx.accounts.governance_key.key; + require_neq!(propeller.governance_transition_ts, 0i64, PropellerError::InvalidEnact); + require_keys_neq!(propeller.prepared_governance_key, Pubkey::default(), PropellerError::InvalidEnact); + + let current_ts = Clock::get()?.unix_timestamp; + + require_gt!(current_ts, 0i64); + require_gt!(current_ts, propeller.governance_transition_ts, PropellerError::InsufficientDelay); + + propeller.governance_key = propeller.prepared_governance_key; + propeller.prepared_governance_key = Pubkey::default(); + propeller.governance_transition_ts = 0i64; + Ok(()) } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs index f48a405f9..95c0f0489 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs @@ -19,8 +19,14 @@ pub struct SetPaused<'info> { pub pause_key: Signer<'info>, } +pub fn handle_set_paused(ctx: Context, is_paused: bool) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + propeller.is_paused = is_paused; + Ok(()) +} + #[derive(Accounts)] -pub struct ChangePauseKey<'info> { +pub struct UpdatePauseKey<'info> { #[account( mut, seeds = [ @@ -35,13 +41,9 @@ pub struct ChangePauseKey<'info> { pub new_pause_key: Signer<'info>, } -pub fn handle_set_paused(ctx: Context, is_paused: bool) -> Result<()> { - let propeller = &mut ctx.accounts.propeller; - propeller.is_paused = is_paused; - Ok(()) -} - -pub fn handle_change_pause_key(ctx: Context) -> Result<()> { +pub fn handle_change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { + require_keys_eq!(new_pause_key, ctx.accounts.new_pause_key.key()); + require_keys_neq!(new_pause_key, Pubkey::default(), PropellerError::InvalidNewPauseKey); let propeller = &mut ctx.accounts.propeller; propeller.pause_key = ctx.accounts.new_pause_key.key(); Ok(()) diff --git a/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs new file mode 100644 index 000000000..e5a38f1e4 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs @@ -0,0 +1,133 @@ +use crate::{get_memo_as_utf8, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees}; +use { + crate::{ + constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, get_message_data, + get_transfer_with_payload_from_message_account, hash_vaa, instructions::fee_tracker::FeeTracker, + state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, PayloadTransferWithPayload, PostVAAData, + PostedVAAData, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, + }, + anchor_lang::{ + prelude::*, + solana_program::{instruction::Instruction, program::invoke_signed, system_program, sysvar::SysvarId}, + }, + anchor_spl::{ + associated_token::get_associated_token_address, + token, + token::{Mint, Token, TokenAccount, Transfer}, + }, + byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, + num_traits::{FromPrimitive, ToPrimitive}, + // primitive_types::U256, + rust_decimal::Decimal, + solana_program::program::invoke, + switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, + two_pool::{state::TwoPool, BorshDecimal}, +}; + +#[derive(Accounts)] +pub struct MarginalPricePool<'info> { + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool_token_0_account.mint.as_ref(), + pool_token_1_account.mint.as_ref(), + lp_mint.key().as_ref(), + ], + bump = pool.bump, + seeds::program = two_pool_program.key() + )] + pub pool: Box>, + #[account( + address = pool.token_keys[0], + )] + pub pool_token_0_account: Box>, + #[account( + address = pool.token_keys[1], + )] + pub pool_token_1_account: Box>, + #[account( + address = pool.lp_mint_key, + )] + pub lp_mint: Box>, + pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +} + +impl<'info> MarginalPricePool<'info> { + pub fn validate(&self, propeller: &Propeller) -> Result<()> { + let marginal_price_pool = &self.pool; + require_keys_eq!( + marginal_price_pool.key(), + propeller.marginal_price_pool, + PropellerError::InvalidMarginalPricePool + ); + let pool_token_index = propeller.marginal_price_pool_token_index as usize; + let marginal_price_pool_token_accounts = [&self.pool_token_0_account, &self.pool_token_1_account]; + 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); + require_keys_eq!( + marginal_price_pool.token_mint_keys[pool_token_index], + propeller.marginal_price_pool_token_mint + ); + require_keys_eq!(pool_token_account.key(), marginal_price_pool_token_accounts[pool_token_index].key()); + msg!("finished marginal price pool validation"); + Ok(()) + } + + fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { + let result = two_pool::cpi::marginal_prices(CpiContext::new( + self.two_pool_program.to_account_info(), + two_pool::cpi::accounts::MarginalPrices { + pool: self.pool.to_account_info(), + pool_token_account_0: self.pool_token_0_account.to_account_info(), + pool_token_account_1: self.pool_token_1_account.to_account_info(), + lp_mint: self.lp_mint.to_account_info(), + }, + ))?; + Ok(result.get()) + } + + pub fn get_marginal_price_decimal(&self, propeller: &Propeller) -> Result { + let marginal_prices = self.get_marginal_prices()?; + let marginal_price_pool = &self.pool; + let marginal_price_pool_lp_mint = &self.lp_mint; + let marginal_price_pool_token_index = propeller.marginal_price_pool_token_index; + let swim_usd_mint = propeller.swim_usd_mint; + let mut marginal_price: Decimal = marginal_prices[marginal_price_pool_token_index as usize] + .try_into() + .map_err(|_| error!(PropellerError::ConversionError))?; + if marginal_price_pool_lp_mint.key() != swim_usd_mint { + require_keys_eq!( + marginal_price_pool.token_mint_keys[0], + swim_usd_mint, + PropellerError::InvalidMetapoolTokenMint, + ); + let swim_usd_marginal_price: Decimal = + marginal_prices[0].try_into().map_err(|_| error!(PropellerError::ConversionError))?; + marginal_price = + marginal_price.checked_div(swim_usd_marginal_price).ok_or(error!(PropellerError::IntegerOverflow))?; + } + Ok(marginal_price) + } + + pub fn get_swim_usd_mint_decimals(&self, propeller: &Propeller) -> Result { + let swim_usd_mint = propeller.swim_usd_mint; + let marginal_price_pool = &self.pool; + let marginal_price_pool_lp_mint = &self.lp_mint; + if swim_usd_mint == marginal_price_pool_lp_mint.key() { + return Ok(marginal_price_pool_lp_mint.decimals); + } + let marginal_price_pool_lp_mint_decimals = marginal_price_pool_lp_mint.decimals; + if swim_usd_mint == marginal_price_pool.lp_mint_key { + // Ok(marginal_price_pool_lp_mint_decimals) + Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.lp_decimal_equalizer) + } else if swim_usd_mint == marginal_price_pool.token_mint_keys[0] { + Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.token_decimal_equalizers[0]) + } else if swim_usd_mint == marginal_price_pool.token_mint_keys[1] { + Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.token_decimal_equalizers[1]) + } else { + return err!(PropellerError::UnableToRetrieveSwimUsdMintDecimals); + } + } +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/mod.rs index 02ebebf75..ecd4ce866 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/mod.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/mod.rs @@ -1,6 +1,6 @@ pub use { - create_owner_token_accounts::*, fee_tracker::*, governance::*, initialize::*, process_swim_payload::*, - target_chain_map::*, token_number_map::*, utils::*, wormhole::*, + create_owner_token_accounts::*, fee_tracker::*, governance::*, initialize::*, marginal_price_pool::*, + process_swim_payload::*, target_chain_map::*, token_number_map::*, utils::*, wormhole::*, }; pub mod process_swim_payload; @@ -10,6 +10,7 @@ pub mod initialize; pub mod create_owner_token_accounts; pub mod fee_tracker; pub mod governance; +pub mod marginal_price_pool; pub mod target_chain_map; pub mod token_number_map; pub mod two_pool_cpi; 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 790fb4337..c04070f2c 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 @@ -1,9 +1,6 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { - crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, convert_fees_to_swim_usd_atomic, get_marginal_price_decimal, - get_swim_usd_mint_decimals, FeeTracker, - }, + crate::{constants::LAMPORTS_PER_SOL_DECIMAL, FeeTracker}, crate::{ deserialize_message_payload, // env::*, @@ -11,6 +8,7 @@ use { get_message_data, get_transfer_with_payload_from_message_account, hash_vaa, + marginal_price_pool::*, state::{SwimClaim, SwimPayloadMessage, *}, token_bridge::TokenBridge, token_number_map::{ToTokenStep, TokenNumberMap}, @@ -37,7 +35,7 @@ use { two_pool::state::TwoPool, }; use { - crate::{get_lamports_intermediate_token_price, get_memo_as_utf8, Fees}, + crate::{fees::*, get_memo_as_utf8}, two_pool::BorshDecimal, }; @@ -62,7 +60,7 @@ pub struct ProcessSwimPayload<'info> { swim_payload_message.vaa_sequence.to_be_bytes().as_ref(), ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge() )] /// CHECK: WH Claim account pub claim: UncheckedAccount<'info>, @@ -197,14 +195,6 @@ impl<'info> ProcessSwimPayload<'info> { Ok(()) } - pub fn validate(&self) -> Result<()> { - // verify claim - // verify message - require_keys_eq!(self.swim_payload_message.claim.key(), self.claim.key()); - require_keys_eq!(self.pool.key(), self.token_number_map.pool, PropellerError::InvalidTokenNumberMapPool); - Ok(()) - } - pub fn transfer_tokens(&self, to_token_number: u16, transfer_amount: u64, min_output_amount: u64) -> Result { let token_id_mapping = &self.token_number_map; let to_token_step = &token_id_mapping.to_token_step; @@ -293,12 +283,12 @@ impl<'info> ProcessSwimPayload<'info> { } ToTokenStep::Transfer => { require_eq!(output_token_index, SWIM_USD_TO_TOKEN_NUMBER, PropellerError::InvalidOutputTokenIndex); - self.transfer_swim_usd_tokens(transfer_amount, user_transfer_authority, signer_seeds) + self.transfer_swim_usd_to_owner(transfer_amount, user_transfer_authority, signer_seeds) } } } - fn transfer_swim_usd_tokens( + fn transfer_swim_usd_to_owner( &self, transfer_amount: u64, user_transfer_authority: &AccountInfo<'info>, @@ -359,68 +349,8 @@ pub fn handle_process_swim_payload( pub struct PropellerProcessSwimPayload<'info> { pub process_swim_payload: ProcessSwimPayload<'info>, - // #[account(mut)] - // pub token_bridge_mint: Box>, - /// Assuming that USD:USDC 1:1 - ///CHECK: account for getting gas -> USD price - #[account( - constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount, - address = process_swim_payload.propeller.aggregator @ PropellerError::InvalidAggregator - )] - pub aggregator: AccountLoader<'info, AggregatorAccountData>, - - #[account( - mut, - address = process_swim_payload.propeller.fee_vault @ PropellerError::InvalidFeeVault - )] - /// this is "to_fees" - /// recipient of fees for executing complete transfer (e.g. relayer) - pub fee_vault: Box>, - - // Note: anchor 0.25.0 still has some issues auto deriving recursive - // seeds. Seems to be mostly fixed in new version. - // #[account( - // mut, - // seeds = [ - // b"propeller".as_ref(), - // b"fee".as_ref(), - // process_swim_payload.propeller.token_bridge_mint, - // process_swim_payload.payer.key().as_ref() - // ], - // bump = fee_tracker.bump - // )] - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - b"fee".as_ref(), - process_swim_payload.get_swim_usd_mint().as_ref(), - process_swim_payload.payer.key().as_ref() - ], - bump = fee_tracker.bump - )] - pub fee_tracker: Box>, + pub fee_tracking: FeeTracking<'info>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - marginal_price_pool_token_0_account.mint.as_ref(), - marginal_price_pool_token_1_account.mint.as_ref(), - marginal_price_pool_lp_mint.key().as_ref(), - ], - bump = marginal_price_pool.bump, - seeds::program = process_swim_payload.two_pool_program.key(), - address = process_swim_payload.propeller.marginal_price_pool @ PropellerError::InvalidMarginalPricePool - )] - 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>, /// This is for transferring lamports for kickstart /// TODO: force this to be system account? #[account(mut, address = process_swim_payload.swim_payload_message.owner)] @@ -443,7 +373,7 @@ impl<'info> PropellerProcessSwimPayload<'info> { ); require_keys_eq!( ctx.accounts.process_swim_payload.propeller.aggregator, - ctx.accounts.aggregator.key(), + ctx.accounts.fee_tracking.aggregator.key(), PropellerError::InvalidAggregator ); require_eq!( @@ -452,11 +382,9 @@ impl<'info> PropellerProcessSwimPayload<'info> { PropellerError::ToTokenNumberMismatch ); let propeller = &ctx.accounts.process_swim_payload.propeller; - validate_marginal_prices_pool_accounts( - &propeller, - &ctx.accounts.marginal_price_pool, - &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], - )?; + let payer = &ctx.accounts.process_swim_payload.payer.key(); + ctx.accounts.fee_tracking.validate(propeller, payer, ctx.program_id)?; + // ctx.accounts.marginal_price_pool.validate(&propeller)?; msg!("Finished PropellerProcessSwimPayload::accounts()"); Ok(()) } @@ -528,76 +456,13 @@ impl<'info> Fees<'info> for PropellerProcessSwimPayload<'info> { Ok(fee_in_lamports) } - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = 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(), - }, - ))?; - Ok(result.get()) - } - - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - let propeller = &self.process_swim_payload.propeller; - - let max_staleness = propeller.max_staleness; - 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( - &self.marginal_price_pool, - &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 - ); - Ok(fee_in_swim_usd_atomic) - } - - 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)?; - + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()> { token::transfer( CpiContext::new_with_signer( self.process_swim_payload.token_program.to_account_info(), Transfer { from: self.process_swim_payload.redeemer_escrow.to_account_info(), - to: self.fee_vault.to_account_info(), + to: self.fee_tracking.fee_vault.to_account_info(), authority: self.process_swim_payload.redeemer.to_account_info(), }, &[&[&b"redeemer".as_ref(), &[self.process_swim_payload.propeller.redeemer_bump]]], @@ -646,8 +511,9 @@ pub fn handle_propeller_process_swim_payload( msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.process_swim_payload.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; - let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; - ctx.accounts.track_and_transfer_fees(fees_in_swim_usd_atomic)?; + let fees_in_swim_usd_atomic = ctx.accounts.fee_tracking.track_fees(fees_in_lamports, propeller)?; + // let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; + ctx.accounts.transfer_fees_to_vault(fees_in_swim_usd_atomic)?; msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); if is_gas_kickstart { ctx.accounts.transfer_gas_kickstart()?; @@ -674,9 +540,7 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { #[account( seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], bump = propeller.bump, - has_one = marginal_price_pool @ PropellerError::InvalidMarginalPricePool, - has_one = aggregator @ PropellerError::InvalidAggregator, - has_one = fee_vault @ PropellerError::InvalidFeeVault, + constraint = !propeller.is_paused @ PropellerError::IsPaused, )] pub propeller: Box>, #[account(mut)] @@ -689,7 +553,7 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { swim_payload_message.vaa_sequence.to_be_bytes().as_ref(), ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge() )] /// CHECK: WH Claim account pub claim: UncheckedAccount<'info>, @@ -760,56 +624,12 @@ pub struct PropellerProcessSwimPayloadFallback<'info> { pub user_swim_usd_ata: Box>, pub token_program: Program<'info, Token>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, #[account(executable, address = spl_memo::id())] ///CHECK: memo program pub memo: UncheckedAccount<'info>, pub system_program: Program<'info, System>, - #[account( - constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount - )] - pub aggregator: AccountLoader<'info, AggregatorAccountData>, - - #[account( - mut, - associated_token::mint = propeller.swim_usd_mint, - associated_token::authority = propeller, - )] - /// this is "to_fees" - /// recipient of fees for executing complete transfer (e.g. relayer) - pub fee_vault: Box>, - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - b"fee".as_ref(), - propeller.swim_usd_mint.as_ref(), - payer.key().as_ref() - ], - bump = fee_tracker.bump - )] - pub fee_tracker: Box>, - - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - marginal_price_pool_token_0_account.mint.as_ref(), - marginal_price_pool_token_1_account.mint.as_ref(), - marginal_price_pool_lp_mint.key().as_ref(), - ], - bump = marginal_price_pool.bump, - 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 fee_tracking: FeeTracking<'info>, /// This is for transferring lamports for kickstart #[account(mut)] pub owner: SystemAccount<'info>, @@ -818,11 +638,9 @@ 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); - validate_marginal_prices_pool_accounts( - &ctx.accounts.propeller, - &ctx.accounts.marginal_price_pool, - &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], - )?; + let propeller = &ctx.accounts.propeller; + let payer = &ctx.accounts.payer.key(); + ctx.accounts.fee_tracking.validate(propeller, payer, ctx.program_id)?; msg!("Passed PropellerProcessSwimPayloadFallback::accounts() check"); Ok(()) } @@ -916,75 +734,13 @@ impl<'info> Fees<'info> for PropellerProcessSwimPayloadFallback<'info> { Ok(fee_in_lamports) } - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = two_pool::cpi::marginal_prices(CpiContext::new( - self.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(), - }, - ))?; - Ok(result.get()) - } - - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - - let max_staleness = self.propeller.max_staleness; - 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, - &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 - ); - Ok(fee_in_swim_usd_atomic) - } - - 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)?; - + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()> { 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(), + to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], @@ -1015,8 +771,9 @@ pub fn handle_propeller_process_swim_payload_fallback( msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; - let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; - ctx.accounts.track_and_transfer_fees(fees_in_swim_usd_atomic)?; + // let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; + let fees_in_swim_usd_atomic = ctx.accounts.fee_tracking.track_fees(fees_in_lamports, propeller)?; + ctx.accounts.transfer_fees_to_vault(fees_in_swim_usd_atomic)?; msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); if is_gas_kickstart { ctx.accounts.transfer_gas_kickstart()?; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs index e0afe3c85..31df74648 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs @@ -64,6 +64,7 @@ pub fn handle_create_target_chain_map( } #[derive(Accounts)] +#[instruction(target_chain: u16)] pub struct UpdateTargetChainMap<'info> { #[account( seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], @@ -81,15 +82,20 @@ pub struct UpdateTargetChainMap<'info> { seeds = [ b"propeller".as_ref(), propeller.key().as_ref(), - &target_chain_map.target_chain.to_le_bytes() + &target_chain.to_le_bytes() ], bump = target_chain_map.bump, )] pub target_chain_map: Account<'info, TargetChainMap>, } -pub fn handle_update_target_chain_map(ctx: Context, routing_contract: [u8; 32]) -> Result<()> { +pub fn handle_update_target_chain_map( + ctx: Context, + target_chain: u16, + routing_contract: [u8; 32], +) -> Result<()> { let target_chain_map = &mut ctx.accounts.target_chain_map; + require_eq!(target_chain, target_chain_map.target_chain, PropellerError::InvalidTargetChainMap); target_chain_map.target_address = routing_contract; Ok(()) } @@ -99,6 +105,7 @@ pub fn handle_close_target_chain_map() -> Result<()> { } #[derive(Accounts)] +#[instruction(target_chain: u16)] pub struct TargetChainMapSetPaused<'info> { #[account( seeds = [b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], @@ -117,15 +124,20 @@ pub struct TargetChainMapSetPaused<'info> { seeds = [ b"propeller".as_ref(), propeller.key().as_ref(), - &target_chain_map.target_chain.to_le_bytes() + &target_chain.to_le_bytes() ], bump = target_chain_map.bump, )] pub target_chain_map: Account<'info, TargetChainMap>, } -pub fn handle_target_chain_map_set_paused(ctx: Context, is_paused: bool) -> Result<()> { +pub fn handle_target_chain_map_set_paused( + ctx: Context, + target_chain: u16, + is_paused: bool, +) -> Result<()> { let target_chain_map = &mut ctx.accounts.target_chain_map; + require_eq!(target_chain, target_chain_map.target_chain, PropellerError::InvalidTargetChainMap); target_chain_map.is_paused = is_paused; Ok(()) } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs index 081e46525..3e23e8800 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs @@ -27,7 +27,7 @@ pub struct Add<'info> { bump = pool.bump, seeds::program = two_pool_program.key() )] - pub pool: Account<'info, TwoPool>, + pub pool: Box>, // /// TODO: could be removed if initialized with pool_v2 // /// CHECK: checked in CPI // pub pool_auth: UncheckedAccount<'info>, @@ -125,52 +125,52 @@ impl<'info> Add<'info> { // Ok(return_val) // } -pub fn handle_cross_chain_add( - ctx: Context, - input_amounts: [u64; TOKEN_COUNT], - minimum_mint_amount: u64, -) -> Result { - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::Add { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; - let return_val = result.get(); - anchor_lang::prelude::msg!("cross_chain_add return_val: {:?}", return_val); - Ok(return_val) -} - -pub fn handle_propeller_add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], max_fee: u64) -> Result { - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::Add { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let result = two_pool::cpi::add(cpi_ctx, input_amounts, PROPELLER_MINIMUM_OUTPUT_AMOUNT)?; - let output_amount = result.get(); - anchor_lang::prelude::msg!("propeller_add output_amount: {:?}", output_amount); - require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); - Ok(output_amount) -} +// pub fn handle_cross_chain_add( +// ctx: Context, +// input_amounts: [u64; TOKEN_COUNT], +// minimum_mint_amount: u64, +// ) -> Result { +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::Add { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; +// let return_val = result.get(); +// anchor_lang::prelude::msg!("cross_chain_add return_val: {:?}", return_val); +// Ok(return_val) +// } +// +// pub fn handle_propeller_add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], max_fee: u64) -> Result { +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::Add { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let result = two_pool::cpi::add(cpi_ctx, input_amounts, PROPELLER_MINIMUM_OUTPUT_AMOUNT)?; +// let output_amount = result.get(); +// anchor_lang::prelude::msg!("propeller_add output_amount: {:?}", output_amount); +// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); +// Ok(output_amount) +// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs new file mode 100644 index 000000000..30e9170f6 --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs @@ -0,0 +1,193 @@ +use { + crate::{ + constants::{METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT}, + error::*, + Propeller, TOKEN_COUNT, + }, + anchor_lang::{prelude::*, solana_program::program::invoke}, + anchor_spl::{ + associated_token::get_associated_token_address, + token::{Mint, Token, TokenAccount}, + }, + two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool}, +}; + +#[derive(Accounts)] +pub struct InitToSwimUsd<'info> { + #[account( + seeds = [ b"propeller".as_ref(), propeller.swim_usd_mint.as_ref()], + bump = propeller.bump, + constraint = !propeller.is_paused @ PropellerError::IsPaused, + )] + pub propeller: Box>, + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool_token_account_0.mint.as_ref(), + pool_token_account_1.mint.as_ref(), + lp_mint.key().as_ref(), + ], + bump = pool.bump, + seeds::program = two_pool_program.key() + )] + pub pool: Box>, + // /// TODO: could be removed if initialized with pool_v2 + // /// CHECK: checked in CPI + // 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], + )] + 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], + )] + pub pool_token_account_1: Box>, + #[account( + mut, + address = pool.lp_mint_key, + )] + pub lp_mint: Box>, + #[account( + mut, + token::mint = lp_mint, + address = pool.governance_fee_key, + )] + pub governance_fee: Box>, + ///CHECK: checked in CPI + pub user_transfer_authority: Signer<'info>, + #[account( + mut, + token::mint = pool_token_account_0.mint, + )] + pub user_token_account_0: Box>, + #[account( + mut, + token::mint = pool_token_account_1.mint, + )] + pub user_token_account_1: Box>, + + #[account(mut)] + /// CHECK: leaving as unchecked account since it's not needed if invoking swap_exact_input + /// validation will be checked in the pool CPI call anyways + pub user_lp_token_account: UncheckedAccount<'info>, + + pub token_program: Program<'info, Token>, + + pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +} + +pub enum ToSwimUsdStep { + Add, + SwapExactInput, +} + +impl<'info> InitToSwimUsd<'info> { + fn determine_to_swim_usd_step(&self) -> Result { + let pool = &self.pool; + let swim_usd_mint = self.propeller.swim_usd_mint; + return if pool.lp_mint_key == swim_usd_mint { + Ok(ToSwimUsdStep::Add) + } else if pool.token_mint_keys[0] == swim_usd_mint { + Ok(ToSwimUsdStep::SwapExactInput) + } else { + err!(PropellerError::InvalidPoolForInitToSwimUsd) + }; + } + + fn invoke_pool_ix_for_swim_usd( + &self, + input_amounts: [u64; TOKEN_COUNT], + minimum_output_amount: u64, + ) -> Result { + let to_swim_usd_step = self.determine_to_swim_usd_step()?; + let output_amount = match to_swim_usd_step { + ToSwimUsdStep::Add => self.invoke_add(input_amounts, minimum_output_amount)?, + ToSwimUsdStep::SwapExactInput => self.invoke_swap_exact_input(input_amounts, minimum_output_amount)?, + }; + Ok(output_amount) + } + + fn invoke_swap_exact_input( + &self, + exact_input_amounts: [u64; TOKEN_COUNT], + minimum_output_amount: u64, + ) -> Result { + require_eq!( + exact_input_amounts[METAPOOL_SWIM_USD_INDEX as usize], + 0u64, + PropellerError::InvalidSwapExactInputInputAmount + ); + let cpi_ctx = CpiContext::new( + self.two_pool_program.to_account_info(), + two_pool::cpi::accounts::SwapExactInput { + pool: self.pool.to_account_info(), + pool_token_account_0: self.pool_token_account_0.to_account_info(), + pool_token_account_1: self.pool_token_account_1.to_account_info(), + lp_mint: self.lp_mint.to_account_info(), + governance_fee: self.governance_fee.to_account_info(), + user_transfer_authority: self.user_transfer_authority.to_account_info(), + user_token_account_0: self.user_token_account_0.to_account_info(), + user_token_account_1: self.user_token_account_1.to_account_info(), + token_program: self.token_program.to_account_info(), + }, + ); + + let result = two_pool::cpi::swap_exact_input( + cpi_ctx, + exact_input_amounts, + METAPOOL_SWIM_USD_INDEX, + minimum_output_amount, + )?; + let output_amount = result.get(); + msg!("ToSwimUsd[swap_exact_input] - output_amount: {}", output_amount); + Ok(output_amount) + } + + fn invoke_add(&self, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { + let cpi_ctx = CpiContext::new( + self.two_pool_program.to_account_info(), + two_pool::cpi::accounts::AddOrRemove { + swap: two_pool::cpi::accounts::Swap { + pool: self.pool.to_account_info(), + pool_token_account_0: self.pool_token_account_0.to_account_info(), + pool_token_account_1: self.pool_token_account_1.to_account_info(), + lp_mint: self.lp_mint.to_account_info(), + governance_fee: self.governance_fee.to_account_info(), + user_transfer_authority: self.user_transfer_authority.to_account_info(), + user_token_account_0: self.user_token_account_0.to_account_info(), + user_token_account_1: self.user_token_account_1.to_account_info(), + token_program: self.token_program.to_account_info(), + }, + user_lp_token_account: self.user_lp_token_account.to_account_info(), + }, + ); + let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; + let output_amount = result.get(); + msg!("ToSwimUsd(add) - output_amount: {}", output_amount); + Ok(output_amount) + } +} + +pub fn handle_cross_chain_init_to_swim_usd( + ctx: Context, + input_amounts: [u64; TOKEN_COUNT], + minimum_output_amount: u64, +) -> Result { + let output_amount = ctx.accounts.invoke_pool_ix_for_swim_usd(input_amounts, minimum_output_amount)?; + Ok(output_amount) +} + +pub fn handle_propeller_init_to_swim_usd( + ctx: Context, + input_amounts: [u64; TOKEN_COUNT], + max_fee: u64, +) -> Result { + let output_amount = handle_cross_chain_init_to_swim_usd(ctx, input_amounts, PROPELLER_MINIMUM_OUTPUT_AMOUNT)?; + require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); + Ok(output_amount) +} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs index f918d23e5..be7dd1f43 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs @@ -4,5 +4,5 @@ pub mod remove_exact_output; pub mod remove_uniform; pub mod swap_exact_input; pub mod swap_exact_output; - -pub const TOKEN_COUNT: usize = 2; +// pub mod to_swim_usd; +pub mod init_to_swim_usd; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs index 091f88e29..f2ce57c2c 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs @@ -1,6 +1,6 @@ use { crate::{ - constants::{PROPELLER_MINIMUM_OUTPUT_AMOUNT, SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX}, + constants::{METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT}, Propeller, PropellerError, }, anchor_lang::{prelude::*, solana_program::program::invoke}, @@ -31,7 +31,7 @@ pub struct SwapExactInput<'info> { bump = pool.bump, seeds::program = two_pool_program.key() )] - pub pool: Account<'info, TwoPool>, + pub pool: Box>, #[account( mut, token::mint = pool.token_mint_keys[0], @@ -145,12 +145,8 @@ pub fn handle_cross_chain_swap_exact_input( }, ); - let result = two_pool::cpi::swap_exact_input( - cpi_ctx, - exact_input_amounts, - SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX, - minimum_output_amount, - )?; + let result = + two_pool::cpi::swap_exact_input(cpi_ctx, exact_input_amounts, METAPOOL_SWIM_USD_INDEX, minimum_output_amount)?; let return_val = result.get(); anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); Ok(return_val) @@ -181,7 +177,7 @@ pub fn handle_propeller_swap_exact_input( let result = two_pool::cpi::swap_exact_input( cpi_ctx, exact_input_amounts, - SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX, + METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT, )?; let output_amount = result.get(); diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs index aae4ba2e0..e2c79d93e 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs @@ -1,9 +1,5 @@ use { - crate::{ - constants::{SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX, TOKEN_BRIDGE_MINT_OUTPUT_TOKEN_INDEX}, - error::*, - Propeller, - }, + crate::{constants::SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX, error::*, Propeller}, anchor_lang::{prelude::*, solana_program::program::invoke}, anchor_spl::token::{Mint, Token, TokenAccount}, two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, diff --git a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs index 7c216ac31..9268cc80b 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/utils.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/utils.rs @@ -1,192 +1,4 @@ -use { - crate::{constants::LAMPORTS_PER_SOL_DECIMAL, error::*, Propeller, TOKEN_COUNT}, - anchor_lang::prelude::*, - anchor_spl::token::{Mint, TokenAccount}, - num_traits::{FromPrimitive, ToPrimitive}, - rust_decimal::Decimal, - switchboard_v2::AggregatorAccountData, - two_pool::{state::TwoPool, BorshDecimal}, -}; - -pub fn get_marginal_prices<'info>( - cpi_ctx: CpiContext<'_, '_, '_, 'info, two_pool::cpi::accounts::MarginalPrices<'info>>, -) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = two_pool::cpi::marginal_prices(cpi_ctx)?; - Ok(result.get()) -} - -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, - 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 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, - marginal_price_pool_lp_mint: &Mint, -) -> Result { - let marginal_price_pool_lp_mint_decimals = marginal_price_pool_lp_mint.decimals; - if *swim_usd_mint == marginal_price_pool.lp_mint_key { - Ok(marginal_price_pool_lp_mint_decimals) - } else if *swim_usd_mint == marginal_price_pool.token_mint_keys[0] { - Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.token_decimal_equalizers[0]) - } else if *swim_usd_mint == marginal_price_pool.token_mint_keys[1] { - Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.token_decimal_equalizers[1]) - } else { - return err!(PropellerError::UnableToRetrieveSwimUsdMintDecimals); - } -} - -pub fn get_marginal_price_decimal( - marginal_price_pool: &TwoPool, - marginal_prices: &[BorshDecimal; TOKEN_COUNT], - propeller: &Propeller, - marginal_price_pool_lp_mint: &Pubkey, -) -> Result { - let marginal_price_pool_token_index = propeller.marginal_price_pool_token_index; - let swim_usd_mint = &propeller.swim_usd_mint; - let mut marginal_price: Decimal = marginal_prices[marginal_price_pool_token_index as usize] - .try_into() - .map_err(|_| error!(PropellerError::ConversionError))?; - if *marginal_price_pool_lp_mint != *swim_usd_mint { - require_keys_eq!( - marginal_price_pool.token_mint_keys[0], - *swim_usd_mint, - PropellerError::InvalidMetapoolTokenMint, - ); - let swim_usd_marginal_price: Decimal = - marginal_prices[0].try_into().map_err(|_| error!(PropellerError::ConversionError))?; - marginal_price = - marginal_price.checked_div(swim_usd_marginal_price).ok_or(error!(PropellerError::IntegerOverflow))?; - } - Ok(marginal_price) -} - -pub fn get_lamports_intermediate_token_price( - aggregator: &AccountLoader, - max_staleness: i64, -) -> Result { - let feed = aggregator.load()?; - feed.check_staleness(Clock::get().unwrap().unix_timestamp, max_staleness) - .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 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); - Ok(lamports_usd_price) - // check whether the feed has been updated in the last 300 seconds -} +use {crate::error::*, anchor_lang::prelude::*}; pub fn get_memo_as_utf8(memo: [u8; 16]) -> Result { String::from_utf8(hex::encode(memo).into_bytes()).map_err(|_| error!(PropellerError::InvalidMemo)) 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 ba015eb9c..898875eea 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 @@ -1,12 +1,12 @@ -use crate::{get_memo_as_utf8, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees}; +use crate::{ + get_memo_as_utf8, marginal_price_pool::*, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees, +}; use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, - get_lamports_intermediate_token_price, get_marginal_price_decimal, get_marginal_prices, get_message_data, - get_swim_usd_mint_decimals, get_transfer_with_payload_from_message_account, hash_vaa, - instructions::fee_tracker::FeeTracker, state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, - PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, TokenBridge, Wormhole, - COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, + constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, fees::*, get_message_data, + get_transfer_with_payload_from_message_account, hash_vaa, instructions::fee_tracker::FeeTracker, + state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, PayloadTransferWithPayload, PostVAAData, + PostedVAAData, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, }, anchor_lang::{ prelude::*, @@ -75,7 +75,7 @@ pub struct CompleteNativeWithPayload<'info> { // hash_vaa(&vaa).as_ref() // ], // bump, - // seeds::program = propeller.wormhole()? + // seeds::program = propeller.wormhole() // )] // pub message: Box>, #[account( @@ -103,7 +103,7 @@ pub struct CompleteNativeWithPayload<'info> { // vaa.sequence.to_be_bytes().as_ref(), // ], // bump, - // seeds::program = propeller.wormhole()? + // seeds::program = propeller.wormhole() // )] #[account(mut)] /// CHECK: wormhole claim account to prevent double spending @@ -131,10 +131,7 @@ pub struct CompleteNativeWithPayload<'info> { /// and that the `redeemer` account will be the PDA derived from ["redeemer"], seeds::program = propeller::id() pub redeemer: SystemAccount<'info>, - #[account( - mut, - token::mint = propeller.swim_usd_mint, - )] + #[account(mut)] /// this is "to_fees" /// recipient of fees for executing complete transfer (e.g. relayer) /// this is only used in `propellerCompleteNativeWithPayload`. @@ -264,33 +261,6 @@ impl<'info> CompleteNativeWithPayload<'info> { Ok(transfer_with_payload) } - // fn write_swim_payload_message( - // &mut self, - // bump: u8, - // message_data: &MessageData, - // transfer_amount: u64, - // swim_payload: &RawSwimPayload, - // ) -> Result<()> { - // let swim_payload_message = &mut self.swim_payload_message; - // swim_payload_message.bump = bump; - // swim_payload_message.claim = self.claim.key(); - // // swim_payload_message.claim_bump = *ctx.bumps.get("claim").unwrap(); - // swim_payload_message.swim_payload_message_payer = self.payer.key(); - // // swim_payload_message.wh_message_bump = *ctx.bumps.get("message").unwrap(); - // swim_payload_message.vaa_emitter_address = message_data.emitter_address; - // swim_payload_message.vaa_emitter_chain = message_data.emitter_chain; - // swim_payload_message.vaa_sequence = message_data.sequence; - // swim_payload_message.transfer_amount = transfer_amount; - // swim_payload_message.swim_payload_version = swim_payload.swim_payload_version; - // swim_payload_message.max_fee = swim_payload.max_fee; - // swim_payload_message.target_token_id = swim_payload.target_token_id; - // swim_payload_message.owner = Pubkey::new_from_array(swim_payload.owner); - // swim_payload_message.memo = swim_payload.memo; - // swim_payload_message.propeller_enabled = swim_payload.propeller_enabled; - // swim_payload_message.gas_kickstart = swim_payload.gas_kickstart; - // Ok(()) - // } - fn write_swim_payload_message( &mut self, bump: u8, @@ -357,50 +327,9 @@ pub fn handle_complete_native_with_payload(ctx: Context { pub complete_native_with_payload: CompleteNativeWithPayload<'info>, - // pub marginal_price_pool: MarginalPricePool<'info>, - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - b"fee".as_ref(), - complete_native_with_payload.swim_usd_mint.key().as_ref(), - complete_native_with_payload.payer.key().as_ref() - ], - bump = fee_tracker.bump - )] - pub fee_tracker: Account<'info, FeeTracker>, - - #[account( - constraint = - *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ PropellerError::InvalidSwitchboardAccount - )] - pub aggregator: AccountLoader<'info, AggregatorAccountData>, + // note - fee_vault is repeated in here but txn size-wise it should only take an additional byte not 32. + pub fee_tracking: FeeTracking<'info>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - marginal_price_pool_token_0_account.mint.as_ref(), - marginal_price_pool_token_1_account.mint.as_ref(), - marginal_price_pool_lp_mint.key().as_ref(), - ], - bump = marginal_price_pool.bump, - 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())] ///CHECK: memo program pub memo: UncheckedAccount<'info>, @@ -409,14 +338,7 @@ pub struct PropellerCompleteNativeWithPayload<'info> { impl<'info> PropellerCompleteNativeWithPayload<'info> { pub fn accounts(ctx: &Context) -> Result<()> { let propeller = &ctx.accounts.complete_native_with_payload.propeller; - validate_marginal_prices_pool_accounts( - &propeller, - &ctx.accounts.marginal_price_pool, - &[&ctx.accounts.marginal_price_pool_token_0_account, &ctx.accounts.marginal_price_pool_token_1_account], - )?; - require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.key(), propeller.fee_vault); - require_keys_eq!(ctx.accounts.complete_native_with_payload.fee_vault.owner, propeller.key()); - require_keys_eq!(ctx.accounts.aggregator.key(), propeller.aggregator, PropellerError::InvalidAggregator); + ctx.accounts.fee_tracking.marginal_price_pool.validate(&propeller)?; Ok(()) } @@ -470,70 +392,7 @@ impl<'info> Fees<'info> for PropellerCompleteNativeWithPayload<'info> { Ok(fee_in_lamports) } - fn get_marginal_prices(&self) -> Result<[BorshDecimal; TOKEN_COUNT]> { - let result = two_pool::cpi::marginal_prices(CpiContext::new( - self.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(), - }, - ))?; - Ok(result.get()) - } - - fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64) -> Result { - msg!("fee_in_lamports: {:?}", fee_in_lamports); - let marginal_price_pool_lp_mint = &self.marginal_price_pool_lp_mint; - - let propeller = &self.complete_native_with_payload.propeller; - let max_staleness = propeller.max_staleness; - 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( - &self.marginal_price_pool, - &self.get_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 lamports_intermediate_token_price = get_lamports_intermediate_token_price(&self.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, &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 - ); - Ok(fee_in_swim_usd_atomic) - } - - 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)?; - + fn transfer_fees_to_vault(&mut self, fees_in_swim_usd: u64) -> Result<()> { token::transfer( CpiContext::new_with_signer( self.complete_native_with_payload.token_program.to_account_info(), @@ -582,13 +441,14 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context swimUSD if the payer isn't the actual logical owner. // This is for if the propeller engine is unavailable and the user is manually calling // this ix. They should use the `CompleteNativeWithPayload` ix instead but adding this just in case.\ - // TODO: if swim payload owner calling though they will need a fee tracker account already. + // if swim payload owner calling though they will need a fee tracker account already. let swim_payload_owner = Pubkey::new_from_array(swim_payload.owner); let token_program = &ctx.accounts.complete_native_with_payload.token_program; if swim_payload_owner != ctx.accounts.complete_native_with_payload.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; - let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; - ctx.accounts.track_and_transfer_fees(fees_in_swim_usd_atomic)?; + // let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; + let fees_in_swim_usd_atomic = ctx.accounts.fee_tracking.track_fees(fees_in_lamports, propeller)?; + ctx.accounts.transfer_fees_to_vault(fees_in_swim_usd_atomic)?; msg!("fees_in_swim_usd_atomic: {:?}", fees_in_swim_usd_atomic); transfer_amount = transfer_amount.checked_sub(fees_in_swim_usd_atomic).ok_or(error!(PropellerError::InsufficientFunds))?; 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 1b5297f45..536c95749 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 @@ -43,10 +43,10 @@ pub struct TransferNativeWithPayload<'info> { mut, seeds = [ b"config".as_ref() ], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge() )] /// CHECK: Token Bridge Config - pub token_bridge_config: AccountInfo<'info>, + pub token_bridge_config: UncheckedAccount<'info>, #[account( mut, @@ -67,7 +67,6 @@ pub struct TransferNativeWithPayload<'info> { /// CHECK: Will either be token bridge custody account or wrapped meta account pub custody: UncheckedAccount<'info>, - #[account(executable, address = propeller.token_bridge()?)] pub token_bridge: Program<'info, TokenBridge>, #[account( @@ -90,7 +89,7 @@ pub struct TransferNativeWithPayload<'info> { mut, seeds = [b"Bridge".as_ref()], bump, - seeds::program = propeller.wormhole().unwrap() + seeds::program = propeller.wormhole() )] /// CHECK: Wormhole Config pub wormhole_config: AccountInfo<'info>, @@ -113,10 +112,10 @@ pub struct TransferNativeWithPayload<'info> { mut, seeds = [b"emitter".as_ref()], bump, - seeds::program = propeller.token_bridge().unwrap() + seeds::program = propeller.token_bridge() )] /// CHECK: Wormhole Emitter is PDA representing the Token Bridge Program - pub wormhole_emitter: AccountInfo<'info>, + pub wormhole_emitter: UncheckedAccount<'info>, #[account( mut, @@ -125,19 +124,19 @@ pub struct TransferNativeWithPayload<'info> { wormhole_emitter.key().as_ref() ], bump, - seeds::program = propeller.wormhole().unwrap() + seeds::program = propeller.wormhole() )] /// CHECK: Wormhole Sequence Number - pub wormhole_sequence: AccountInfo<'info>, + pub wormhole_sequence: UncheckedAccount<'info>, #[account( mut, seeds = [b"fee_collector".as_ref()], bump, - seeds::program = propeller.wormhole().unwrap() + seeds::program = propeller.wormhole() )] /// CHECK: Wormhole Fee Collector. leaving as UncheckedAccount since it could be uninitialized for the first transfer. - pub wormhole_fee_collector: AccountInfo<'info>, + pub wormhole_fee_collector: UncheckedAccount<'info>, /// Transfers with payload also include the address of the account or contract /// that sent the transfer. Semantically this is identical to "msg.sender" on @@ -219,25 +218,24 @@ impl<'info> TransferNativeWithPayload<'info> { fn invoke_transfer_native_with_payload(&self, transfer_with_payload_data: TransferWithPayloadData) -> Result<()> { let wh_token_transfer_acct_infos = vec![ - self.payer.to_account_info().clone(), - self.token_bridge_config.to_account_info().clone(), - // ctx.accounts.token_bridge.to_account_info().clone(), - self.user_swim_usd_ata.to_account_info().clone(), - self.swim_usd_mint.to_account_info().clone(), - self.custody.to_account_info().clone(), - self.authority_signer.to_account_info().clone(), - self.custody_signer.to_account_info().clone(), - self.wormhole_config.to_account_info().clone(), - self.wormhole_message.to_account_info().clone(), - self.wormhole_emitter.to_account_info().clone(), - self.wormhole_sequence.to_account_info().clone(), - self.wormhole_fee_collector.to_account_info().clone(), - self.clock.to_account_info().clone(), - self.sender.to_account_info().clone(), - self.rent.to_account_info().clone(), - self.system_program.to_account_info().clone(), - self.wormhole.to_account_info().clone(), - self.token_program.to_account_info().clone(), + self.payer.to_account_info(), + self.token_bridge_config.to_account_info(), + self.user_swim_usd_ata.to_account_info(), + self.swim_usd_mint.to_account_info(), + self.custody.to_account_info(), + self.authority_signer.to_account_info(), + self.custody_signer.to_account_info(), + self.wormhole_config.to_account_info(), + self.wormhole_message.to_account_info(), + self.wormhole_emitter.to_account_info(), + self.wormhole_sequence.to_account_info(), + self.wormhole_fee_collector.to_account_info(), + self.clock.to_account_info(), + self.sender.to_account_info(), + self.rent.to_account_info(), + self.system_program.to_account_info(), + self.wormhole.to_account_info(), + self.token_program.to_account_info(), ]; invoke_signed( diff --git a/packages/solana-contracts/programs/propeller/src/lib.rs b/packages/solana-contracts/programs/propeller/src/lib.rs index 29e0959bf..13e4bd250 100644 --- a/packages/solana-contracts/programs/propeller/src/lib.rs +++ b/packages/solana-contracts/programs/propeller/src/lib.rs @@ -1,6 +1,7 @@ use { crate::two_pool_cpi::{ add::*, + init_to_swim_usd::*, swap_exact_input::*, // remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_output::*, }, @@ -40,18 +41,21 @@ pub mod propeller { handle_set_paused(ctx, paused) } - pub fn change_pause_key(ctx: Context) -> Result<()> { - handle_change_pause_key(ctx) + pub fn change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { + handle_change_pause_key(ctx, new_pause_key) } - pub fn prepare_governance_transition(ctx: Context) -> Result<()> { - Ok(()) + pub fn prepare_governance_transition(ctx: Context, upcoming_governance_key: Pubkey) -> Result<()> { + handle_prepare_governance_transition(ctx, upcoming_governance_key) } pub fn enact_governance_transition(ctx: Context) -> Result<()> { Ok(()) } + // pub fn prepare_fee_change(ctx: Context, fee_updates: FeeUpdates) -> Result<()> {} + // pub fn enact_fee_change(ctx: Context) -> Result<()> {} + #[inline(never)] #[access_control( CreateTokenNumberMap::accounts( @@ -99,12 +103,20 @@ pub mod propeller { } //TODO: pass in `target_chain` as input parameter for these? - pub fn update_target_chain_map(ctx: Context, routing_contract: [u8; 32]) -> Result<()> { - handle_update_target_chain_map(ctx, routing_contract) + pub fn update_target_chain_map( + ctx: Context, + target_chain: u16, + routing_contract: [u8; 32], + ) -> Result<()> { + handle_update_target_chain_map(ctx, target_chain, routing_contract) } - pub fn target_chain_map_set_paused(ctx: Context, is_paused: bool) -> Result<()> { - handle_target_chain_map_set_paused(ctx, is_paused) + pub fn target_chain_map_set_paused( + ctx: Context, + target_chain: u16, + is_paused: bool, + ) -> Result<()> { + handle_target_chain_map_set_paused(ctx, target_chain, is_paused) } #[inline(never)] @@ -118,186 +130,23 @@ pub mod propeller { handle_claim_fees(ctx) } - // #[access_control(Add::accounts(&ctx))] - // pub fn add( - // ctx: Context, - // input_amounts: [u64; TOKEN_COUNT], - // minimum_mint_amount: u64, - // memo: Vec, - // propeller_enabled: bool, - // target_chain: u16, - // ) -> Result { - // handle_add(ctx, input_amounts, minimum_mint_amount, memo.as_slice(), propeller_enabled, target_chain) - // } - - #[access_control(Add::accounts(&ctx))] - pub fn cross_chain_add( - ctx: Context, + /** Sending */ + pub fn cross_chain_init_to_swim_usd( + ctx: Context, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64, ) -> Result { - handle_cross_chain_add(ctx, input_amounts, minimum_mint_amount) - } - - #[access_control(Add::accounts(&ctx))] - pub fn propeller_add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], max_fee: u64) -> Result { - handle_propeller_add(ctx, input_amounts, max_fee) - } - - // pub fn swap_exact_input( - // ctx: Context, - // exact_input_amount: u64, - // minimum_output_amount: u64, - // memo: Vec, - // propeller_enabled: bool, - // target_chain: u16, - // ) -> Result { - // handle_swap_exact_input( - // ctx, - // exact_input_amount, - // minimum_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - - /* For metapools */ - - pub fn cross_chain_swap_exact_input( - ctx: Context, - exact_input_amount: u64, - minimum_output_amount: u64, - ) -> Result { - handle_cross_chain_swap_exact_input(ctx, exact_input_amount, minimum_output_amount) + handle_cross_chain_init_to_swim_usd(ctx, input_amounts, minimum_mint_amount) } - pub fn propeller_swap_exact_input( - ctx: Context, - exact_input_amount: u64, + pub fn propeller_init_to_swim_usd( + ctx: Context, + input_amounts: [u64; TOKEN_COUNT], max_fee: u64, ) -> Result { - handle_propeller_swap_exact_input(ctx, exact_input_amount, max_fee) + handle_propeller_init_to_swim_usd(ctx, input_amounts, max_fee) } - /* - // pub fn swap_exact_output( - // ctx: Context, - // maximum_input_amount: u64, - // exact_output_amount: u64, // params: SwapExactOutputParams, - // memo: Vec, - // propeller_enabled: bool, - // target_chain: u16, - // ) -> Result> { - // handle_swap_exact_output( - // ctx, - // maximum_input_amount, - // exact_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - - // pub fn cross_chain_swap_exact_output( - // ctx: Context, - // maximum_input_amount: u64, - // exact_output_amount: u64, // params: SwapExactOutputParams, - // memo: Vec, - // ) -> Result> { - // handle_cross_chain_swap_exact_output( - // ctx, - // maximum_input_amount, - // exact_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - // - // pub fn propeller_swap_exact_output( - // ctx: Context, - // maximum_input_amount: u64, - // memo: Vec, - // max_fee: u64, - // ) -> Result> { - // handle_propeller_swap_exact_output( - // ctx, - // maximum_input_amount, - // exact_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - - // pub fn remove_uniform( - // ctx: Context, - // exact_burn_amount: u64, - // minimum_output_amounts: [u64; TOKEN_COUNT], - // memo: Vec, - // ) -> Result> { - // handle_remove_uniform(ctx, exact_burn_amount, minimum_output_amounts, memo.as_slice()) - // } - - // pub fn remove_exact_burn( - // ctx: Context, - // exact_burn_amount: u64, - // minimum_output_amount: u64, - // memo: Vec, - // propeller_enabled: bool, - // target_chain: u16, - // ) -> Result { - // handle_remove_exact_burn( - // ctx, - // exact_burn_amount, - // minimum_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - */ - - //TODO: does remove_exact_burn make sense for metapools? - // burn metapool lp token to get token_bridge_mint - - // pub fn cross_chain_remove_exact_burn( - // ctx: Context, - // exact_burn_amount: u64, - // minimum_output_amount: u64, - // memo: Vec, - // ) -> Result { - // handle_cross_chain_remove_exact_burn(ctx, exact_burn_amount, minimum_output_amount, memo.as_slice()) - // } - // - // pub fn propeller_remove_exact_burn( - // ctx: Context, - // exact_burn_amount: u64, - // memo: Vec, - // max_fee: u64, - // ) -> Result { - // handle_propeller_remove_exact_burn(ctx, exact_burn_amount, memo.as_slice(), max_fee) - // } - - // pub fn remove_exact_output( - // ctx: Context, - // maximum_burn_amount: u64, - // exact_output_amount: u64, - // memo: Vec, - // propeller_enabled: bool, - // target_chain: u16, - // ) -> Result> { - // handle_remove_exact_output( - // ctx, - // maximum_burn_amount, - // exact_output_amount, - // memo.as_slice(), - // propeller_enabled, - // target_chain, - // ) - // } - #[inline(never)] #[access_control(TransferNativeWithPayload::accounts(&ctx))] pub fn cross_chain_transfer_native_with_payload( @@ -336,6 +185,8 @@ pub mod propeller { ) } + /** Receiving */ + #[inline(never)] #[access_control(CompleteNativeWithPayload::accounts(&ctx))] pub fn complete_native_with_payload(ctx: Context) -> Result<()> { @@ -525,7 +376,7 @@ pub mod propeller { // mut, // seeds = [ b"config".as_ref() ], // bump, -// seeds::program = propeller.token_bridge().unwrap() +// seeds::program = propeller.token_bridge() // )] // /// CHECK: Token Bridge Config // pub token_bridge_config: AccountInfo<'info>, @@ -573,7 +424,7 @@ pub mod propeller { // mut, // seeds = [b"Bridge".as_ref()], // bump, -// seeds::program = propeller.wormhole().unwrap() +// seeds::program = propeller.wormhole() // )] // /// CHECK: Wormhole Config // pub wormhole_config: AccountInfo<'info>, @@ -596,7 +447,7 @@ pub mod propeller { // mut, // seeds = [b"emitter".as_ref()], // bump, -// seeds::program = propeller.token_bridge().unwrap() +// seeds::program = propeller.token_bridge() // )] // /// CHECK: Wormhole Emitter is PDA representing the Token Bridge Program // pub wormhole_emitter: AccountInfo<'info>, @@ -608,7 +459,7 @@ pub mod propeller { // wormhole_emitter.key().as_ref() // ], // bump, -// seeds::program = propeller.wormhole().unwrap() +// seeds::program = propeller.wormhole() // )] // /// CHECK: Wormhole Sequence Number // pub wormhole_sequence: AccountInfo<'info>, @@ -617,7 +468,7 @@ pub mod propeller { // mut, // seeds = [b"fee_collector".as_ref()], // bump, -// seeds::program = propeller.wormhole().unwrap() +// seeds::program = propeller.wormhole() // )] // /// CHECK: Wormhole Fee Collector. leaving as UncheckedAccount since it could be uninitialized for the first transfer. // pub wormhole_fee_collector: AccountInfo<'info>, diff --git a/packages/solana-contracts/programs/propeller/src/state/propeller.rs b/packages/solana-contracts/programs/propeller/src/state/propeller.rs index d01751ca6..063508d52 100644 --- a/packages/solana-contracts/programs/propeller/src/state/propeller.rs +++ b/packages/solana-contracts/programs/propeller/src/state/propeller.rs @@ -51,8 +51,10 @@ pub struct Propeller { // pub evm_routing_contract_address: [u8; 32], pub fee_vault: Pubkey, //32 + /** switchboard **/ pub aggregator: Pubkey, //32 pub max_staleness: i64, //8 + // pub max_confidence_interval: i64, //8 //TODO: add this? // pub fallback_oracle: Pubkey, //32 @@ -90,19 +92,12 @@ impl Propeller { 8; //max_staleness // 32; // evm_routing_contract_address - pub fn wormhole(&self) -> Result { - // let pubkey = Pubkey::from_str(CORE_BRIDGE_ADDRESS) - // .map_err(|_| PropellerError::InvalidWormholeAddress)?; - // let pubkey = CORE_BRIDGE_ID; - let pubkey = crate::Wormhole::id(); - Ok(pubkey) + pub fn wormhole(&self) -> Pubkey { + crate::Wormhole::id() } - pub fn token_bridge(&self) -> Result { - // let pubkey = Pubkey::from_str(TOKEN_BRIDGE_ADDRESS) - // .map_err(|_| PropellerError::InvalidWormholeAddress)?; - let pubkey = crate::TokenBridge::id(); - Ok(pubkey) + pub fn token_bridge(&self) -> Pubkey { + crate::TokenBridge::id() } pub fn get_complete_native_with_payload_fee(&self) -> u64 { 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 1ec0e709c..b2d74cef7 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs @@ -75,7 +75,7 @@ impl<'info> Add<'info> { } // -pub fn handle_add( +pub fn handle_add_old( ctx: Context, params: AddParams, // input_amounts: [u64; TOKEN_COUNT], diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs new file mode 100644 index 000000000..a6b368a55 --- /dev/null +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs @@ -0,0 +1,282 @@ +use { + crate::{ + common::{self, array_equalize, result_from_equalized, to_equalized}, + defi::*, + error::*, + gen_pool_signer_seeds, get_current_ts, + invariant::Invariant, + AddParams, Swap, TwoPool, TOKEN_COUNT, + }, + anchor_lang::prelude::*, + anchor_spl::{ + associated_token::get_associated_token_address, + token::{self, Mint, Token, TokenAccount}, + }, + std::iter::zip, +}; +// +// #[derive(Accounts)] +// pub struct AddOrRemove<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Box>, +// #[account( +// mut, +// address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), +// constraint = pool_token_account_0.key() == 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] @ PoolError::PoolTokenAccountExpected, +// )] +// pub pool_token_account_1: Box>, +// +// #[account(mut, address = pool.lp_mint_key @ PoolError::InvalidMintAccount)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint, +// address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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>, +// } +// pub fn handle_add( +// ctx: Context, +// params: AddParams, +// // input_amounts: [u64; TOKEN_COUNT], +// // minimum_mint_amount: u64, +// ) -> Result { +// let pool_state = &ctx.accounts.pool; +// require!(!pool_state.is_paused, PoolError::PoolIsPaused); +// +// let input_amounts = params.input_amounts; +// let minimum_mint_amount = params.minimum_mint_amount; +// require!(input_amounts.iter().any(|&x| x > 0), PoolError::AddRequiresAtLeastOneToken); +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// //initial add to pool must add all tokens +// if lp_total_supply == 0 { +// require!(input_amounts.iter().all(|&x| x > 0), PoolError::InitialAddRequiresAllTokens); +// } +// +// let pool = &ctx.accounts.pool; +// let user_token_accounts = [&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; +// let pool_token_accounts = [&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// let current_ts = Clock::get()?.unix_timestamp; +// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); +// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::add( +// &common::array_equalize(input_amounts, pool.token_decimal_equalizers), +// &common::array_equalize(pool_balances, pool.token_decimal_equalizers), +// pool.amp_factor.get(current_ts), +// pool.lp_fee.get(), +// pool.governance_fee.get(), +// common::to_equalized(lp_total_supply, pool.lp_decimal_equalizer), +// pool.previous_depth.into(), +// )?; +// let (mint_amount, governance_mint_amount, latest_depth) = common::result_from_equalized( +// user_amount, +// pool.lp_decimal_equalizer, +// governance_mint_amount, +// pool.lp_decimal_equalizer, +// latest_depth, +// ); +// require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); +// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// for input_amount in input_amounts.iter().take(TOKEN_COUNT) { +// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); +// if *input_amount > 0u64 { +// let pool_token_account = pool_token_account.to_account_info(); +// let user_token_account = user_token_account.to_account_info(); +// let user_transfer_authority = ctx.accounts.user_transfer_authority.to_account_info(); +// token::transfer( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// from: user_token_account.clone(), +// to: pool_token_account.clone(), +// authority: user_transfer_authority.clone(), +// }, +// ), +// *input_amount, +// )?; +// } +// } +// +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.user_lp_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// mint_amount, +// )?; +// +// if governance_mint_amount > 0 { +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.governance_fee.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// governance_mint_amount, +// )?; +// } +// +// let pool_state = &mut ctx.accounts.pool; +// pool_state.previous_depth = latest_depth; +// Ok(mint_amount) +// } + +#[derive(Accounts)] +pub struct AddOrRemove<'info> { + pub swap: Swap<'info>, + + #[account( + mut, + token::mint = swap.lp_mint, + )] + pub user_lp_token_account: Box>, +} + +pub fn handle_add( + ctx: Context, + params: AddParams, + // input_amounts: [u64; TOKEN_COUNT], + // minimum_mint_amount: u64, +) -> Result { + let pool_state = &ctx.accounts.swap.pool; + require!(!pool_state.is_paused, PoolError::PoolIsPaused); + + let input_amounts = params.input_amounts; + let minimum_mint_amount = params.minimum_mint_amount; + require!(input_amounts.iter().any(|&x| x > 0), PoolError::AddRequiresAtLeastOneToken); + let lp_total_supply = ctx.accounts.swap.lp_mint.supply; + //initial add to pool must add all tokens + if lp_total_supply == 0 { + require!(input_amounts.iter().all(|&x| x > 0), PoolError::InitialAddRequiresAllTokens); + } + + let pool = &ctx.accounts.swap.pool; + let user_token_accounts = [&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; + let pool_token_accounts = [&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; + let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); + let (user_amount, governance_mint_amount, latest_depth) = Invariant::::add( + &common::array_equalize(input_amounts, pool.token_decimal_equalizers), + &common::array_equalize(pool_balances, pool.token_decimal_equalizers), + pool.amp_factor.get(current_ts), + pool.lp_fee.get(), + pool.governance_fee.get(), + common::to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + pool.previous_depth.into(), + )?; + let (mint_amount, governance_mint_amount, latest_depth) = common::result_from_equalized( + user_amount, + pool.lp_decimal_equalizer, + governance_mint_amount, + pool.lp_decimal_equalizer, + latest_depth, + ); + require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); + let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + for input_amount in input_amounts.iter().take(TOKEN_COUNT) { + let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); + if *input_amount > 0u64 { + let pool_token_account = pool_token_account.to_account_info(); + let user_token_account = user_token_account.to_account_info(); + let user_transfer_authority = ctx.accounts.swap.user_transfer_authority.to_account_info(); + token::transfer( + CpiContext::new( + ctx.accounts.swap.token_program.to_account_info(), + token::Transfer { + from: user_token_account.clone(), + to: pool_token_account.clone(), + authority: user_transfer_authority.clone(), + }, + ), + *input_amount, + )?; + } + } + + token::mint_to( + CpiContext::new_with_signer( + ctx.accounts.swap.token_program.to_account_info(), + token::MintTo { + // source + mint: ctx.accounts.swap.lp_mint.to_account_info(), + to: ctx.accounts.user_lp_token_account.to_account_info(), + authority: ctx.accounts.swap.pool.to_account_info(), + }, + &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], + ), + mint_amount, + )?; + + if governance_mint_amount > 0 { + token::mint_to( + CpiContext::new_with_signer( + ctx.accounts.swap.token_program.to_account_info(), + token::MintTo { + // source + mint: ctx.accounts.swap.lp_mint.to_account_info(), + to: ctx.accounts.swap.governance_fee.to_account_info(), + authority: ctx.accounts.swap.pool.to_account_info(), + }, + &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], + ), + governance_mint_amount, + )?; + } + + let pool_state = &mut ctx.accounts.swap.pool; + pool_state.previous_depth = latest_depth; + Ok(mint_amount) +} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs new file mode 100644 index 000000000..c32222ee3 --- /dev/null +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs @@ -0,0 +1,75 @@ +pub use add_or_remove::*; +pub mod add_or_remove; + +use { + crate::{ + common::{self, array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, get_current_ts, + invariant::Invariant, + AddParams, TwoPool, TOKEN_COUNT, + }, + anchor_lang::prelude::*, + anchor_spl::{ + associated_token::get_associated_token_address, + token::{self, Mint, Token, TokenAccount}, + }, + std::iter::zip, +}; + +#[derive(Accounts)] +pub struct Swap<'info> { + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool_token_account_0.mint.as_ref(), + pool_token_account_1.mint.as_ref(), + lp_mint.key().as_ref(), + ], + bump = pool.bump + )] + pub pool: Box>, + #[account( + mut, + address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), + constraint = pool_token_account_0.key() == 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] @ PoolError::PoolTokenAccountExpected, + )] + pub pool_token_account_1: Box>, + + #[account(mut, address = pool.lp_mint_key @ PoolError::InvalidMintAccount)] + pub lp_mint: Box>, + #[account( + mut, + token::mint = lp_mint, + address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, + )] + pub governance_fee: Box>, + + pub user_transfer_authority: Signer<'info>, + + #[account( + mut, + token::mint = pool_token_account_0.mint, + )] + pub user_token_account_0: Box>, + + #[account( + mut, + token::mint = pool_token_account_1.mint, + )] + pub user_token_account_1: 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>, +} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs index d00a7621b..329fed2de 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs @@ -1,7 +1,5 @@ use { - crate::{ - common_governance::*, error::*, get_current_ts, - }, + crate::{common_governance::*, error::*, get_current_ts}, anchor_lang::prelude::*, }; @@ -20,6 +18,7 @@ impl<'info> EnactGovernanceTransition<'info> { pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { let pool = &mut ctx.accounts.common_governance.pool; require_neq!(pool.governance_transition_ts, 0i64, PoolError::InvalidEnact); + require_keys_neq!(pool.prepared_governance_key, Pubkey::default(), PoolError::InvalidEnact); let current_ts = get_current_ts()?; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs index 88b564592..a3070b220 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/initialize.rs @@ -67,6 +67,7 @@ pub struct Initialize<'info> { payer = payer, associated_token::mint = lp_mint, associated_token::authority = governance_account, + address = get_associated_token_address(&governance_account.key(), &lp_mint.key()), )] pub governance_fee_account: Box>, @@ -77,6 +78,7 @@ pub struct Initialize<'info> { pub system_program: Program<'info, System>, //explicitly needed for initializing associated token accounts + // setting it last so it can be removed once version after 0.25.0 is released pub rent: Sysvar<'info, Rent>, } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs index 19dc73588..6f8ecfeee 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs @@ -3,7 +3,7 @@ use { anchor_lang::{prelude::*, require_gt, solana_program::clock::UnixTimestamp}, }; pub use { - add::*, governance::*, initialize::*, marginal_prices::*, remove_exact_burn::*, remove_exact_output::*, + add::*, defi::*, governance::*, initialize::*, marginal_prices::*, remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_input::*, swap_exact_output::*, }; @@ -16,6 +16,7 @@ pub mod remove_uniform; pub mod swap_exact_input; pub mod swap_exact_output; +pub mod defi; pub mod governance; pub fn get_current_ts() -> Result { diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs index dff2fadd6..f91f13e1f 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs @@ -73,11 +73,6 @@ pub struct SwapExactInput<'info> { )] pub user_token_account_1: 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>, } diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index 05e6e433b..e95d02d3a 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -60,7 +60,7 @@ solana_security_txt::security_txt! { #[program] pub mod two_pool { - use super::*; + use {super::*, crate::instructions::defi::add_or_remove::AddOrRemove}; #[access_control(Initialize::accounts(&ctx))] pub fn initialize( @@ -72,13 +72,19 @@ pub mod two_pool { handle_initialize(ctx, amp_factor, lp_fee, governance_fee) } - #[access_control(Add::accounts(&ctx))] - pub fn add( - ctx: Context, - input_amounts: [u64; TOKEN_COUNT], - minimum_mint_amount: u64, - // params: AddParams - ) -> Result { + // #[access_control(Add::accounts(&ctx))] + // pub fn add( + // ctx: Context, + // input_amounts: [u64; TOKEN_COUNT], + // minimum_mint_amount: u64, + // // params: AddParams + // ) -> Result { + // let params = AddParams { input_amounts, minimum_mint_amount }; + // handle_add_old(ctx, params) + // // handle_add(ctx, input_amounts, minimum_mint_amount) + // } + + pub fn add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { let params = AddParams { input_amounts, minimum_mint_amount }; handle_add(ctx, params) // handle_add(ctx, input_amounts, minimum_mint_amount) diff --git a/packages/solana-contracts/scripts/initializePropeller.ts b/packages/solana-contracts/scripts/initializePropeller.ts index b97e791ab..dad22b9ab 100644 --- a/packages/solana-contracts/scripts/initializePropeller.ts +++ b/packages/solana-contracts/scripts/initializePropeller.ts @@ -41,7 +41,7 @@ import { import { getPropellerPda, getPropellerRedeemerPda, - getTargetChainIdMapAddr, + getTargetChainMapAddr, getToTokenNumberMapAddr, } from "../src/__tests__/propeller/propellerUtils"; @@ -461,7 +461,7 @@ async function createTargetChainMaps() { tryNativeToHexString(targetAddress, wormholeChainId as ChainId), "hex", ); - const [targetChainMapAddr] = await getTargetChainIdMapAddr( + const [targetChainMapAddr] = await getTargetChainMapAddr( propellerInfo.address, wormholeChainId, propellerProgram.programId, diff --git a/packages/solana-contracts/scripts/scratch.ts b/packages/solana-contracts/scripts/scratch.ts index 37ab10c67..6cdcf9b4c 100644 --- a/packages/solana-contracts/scripts/scratch.ts +++ b/packages/solana-contracts/scripts/scratch.ts @@ -30,7 +30,7 @@ import { import { getPropellerPda, getPropellerRedeemerPda, - getTargetChainIdMapAddr, + getTargetChainMapAddr, getToTokenNumberMapAddr, } from "../src/__tests__/propeller/propellerUtils"; import type { Propeller } from "../src/artifacts/propeller"; diff --git a/packages/solana-contracts/src/__tests__/consts.ts b/packages/solana-contracts/src/__tests__/consts.ts index 27a3c0391..af5c9be5a 100644 --- a/packages/solana-contracts/src/__tests__/consts.ts +++ b/packages/solana-contracts/src/__tests__/consts.ts @@ -14,7 +14,8 @@ export const rpcCommitmentConfig = { skipPreflight: true, }; -export const ethTokenBridgeNativeStr = "0x0290FB167208Af455bB137780163b7B7a9a10C16"; +export const ethTokenBridgeNativeStr = + "0x0290FB167208Af455bB137780163b7B7a9a10C16"; //0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16 const ethTokenBridgeEthHexStr = tryNativeToHexString( ethTokenBridgeNativeStr, @@ -28,10 +29,12 @@ const bscTokenBridgeBscHexStr = tryNativeToHexString( bscTokenBridgeStr, CHAIN_ID_BSC, ); + export const bscTokenBridge = Buffer.from(bscTokenBridgeBscHexStr, "hex"); -const ethRoutingContractStr = "0x0290FB167208Af455bB137780163b7B7a9a10C17"; +const evmRoutingContractNativeStr = + "0x280999aB9aBfDe9DC5CE7aFB25497d6BB3e8bDD4"; // const ethRoutingContractEthUint8Arr = tryNativeToUint8Array( -// ethRoutingContractStr, +// evmRoutingContractNativeStr, // CHAIN_ID_ETH, // ); // console.info(` @@ -40,17 +43,17 @@ const ethRoutingContractStr = "0x0290FB167208Af455bB137780163b7B7a9a10C17"; // ethRoutingContractEthUint8Arr, // )} // `); -export const ethRoutingContractEthHexStr = tryNativeToHexString( - ethRoutingContractStr, +export const evmRoutingContractHexStr = tryNativeToHexString( + evmRoutingContractNativeStr, CHAIN_ID_ETH, ); -export const ethRoutingContract = Buffer.from( - ethRoutingContractEthHexStr, +export const evmRoutingContractBuffer = Buffer.from( + evmRoutingContractHexStr, "hex", ); export const routingContracts = [ - { targetChainId: CHAIN_ID_ETH, address: ethRoutingContract }, - { targetChainId: CHAIN_ID_BSC, address: ethRoutingContract }, + { targetChainId: CHAIN_ID_ETH, address: evmRoutingContractBuffer }, + { targetChainId: CHAIN_ID_BSC, address: evmRoutingContractBuffer }, ]; //TODO: figure out actual value for compute budget export const setComputeUnitLimitIx: web3.TransactionInstruction = @@ -97,3 +100,5 @@ export const TWO_POOL_PID = new web3.PublicKey( export const PROPELLER_PID = new web3.PublicKey( "9z6G41AyXk73r1E4nTv81drQPtEqupCSAnsLdGV5WGfK", ); + +export const SWIM_MEMO_LENGTH = 16; diff --git a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts index 304062baf..2a0aec056 100644 --- a/packages/solana-contracts/src/__tests__/propeller/engine.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/engine.test.ts @@ -52,9 +52,9 @@ import { bscTokenBridge, commitment, completeWithPayloadFee, - ethRoutingContract, ethTokenBridge, evmOwner, + evmRoutingContractBuffer, gasKickstartAmount, governanceFee, initAtaFee, @@ -75,6 +75,7 @@ import { usdtPoolTokenIndex, } from "../consts"; import { + getAddOrRemoveAccounts, getOwnerAtaAddrsForPool, getPoolUserBalances, printPoolUserBalances, @@ -82,11 +83,12 @@ import { setupUserAssociatedTokenAccts, } from "../twoPool/poolTestUtils"; -import type { WormholeAddresses } from "./propellerUtils"; +import type { FeeTrackingAccounts, WormholeAddresses } from "./propellerUtils"; import { encodeSwimPayload, generatePropellerEngineTxns, getFeeTrackerPda, + getFeeTrackingAccounts, getPropellerPda, getPropellerRedeemerPda, getSwimClaimPda, @@ -191,7 +193,7 @@ let userUsdcAtaAddr: web3.PublicKey; let userUsdtAtaAddr: web3.PublicKey; let userSwimUsdAtaAddr: web3.PublicKey; -let flagshipPool: web3.PublicKey; +let swimUsdPool: web3.PublicKey; // let flagshipPoolData: SwimPoolState; // let poolAuth: web3.PublicKey; const swimUsdMint: web3.PublicKey = swimUsdKeypair.publicKey; @@ -202,7 +204,7 @@ const metapoolMint1Authority = userKeypair; const metapoolMint1Decimal = 8; const metapoolMintKeypairs = [metapoolMint0Keypair, metapoolMint1Keypair]; const metapoolMintDecimals = [mintDecimal, metapoolMint1Decimal]; -// const metapoolMintAuthorities = [flagshipPool, metapoolMint1Authority]; +// const metapoolMintAuthorities = [swimUsdPool, metapoolMint1Authority]; const metapoolLpMintKeypair = web3.Keypair.generate(); // const metapoolLpMint = metapoolLpMintKeypair.publicKey; @@ -257,6 +259,7 @@ let propellerEngineSwimUsdFeeAccount: web3.PublicKey; let aggregatorAccount: AggregatorAccount; let aggregator: PublicKey; +let feeTrackingAccts: FeeTrackingAccounts; describe("propeller", () => { beforeAll(async () => { @@ -281,7 +284,7 @@ describe("propeller", () => { console.info(`initializing two pool v2`); ({ - poolPubkey: flagshipPool, + poolPubkey: swimUsdPool, poolTokenAccounts: [poolUsdcAtaAddr, poolUsdtAtaAddr], governanceFeeAccount: flagshipPoolGovernanceFeeAcct, } = await setupPoolPrereqs( @@ -320,10 +323,10 @@ describe("propeller", () => { } const pool = pubkeys.pool; console.info( - `poolKey: ${pool.toBase58()}, expected: ${flagshipPool.toBase58()}`, + `poolKey: ${pool.toBase58()}, expected: ${swimUsdPool.toBase58()}`, ); - // expect(pool.toBase58()).toEqual(flagshipPool.toBase58()); + // expect(pool.toBase58()).toEqual(swimUsdPool.toBase58()); const initFlagshipPoolTxnSig: string = await initFlagshipPoolTxn.rpc( rpcCommitmentConfig, ); @@ -335,7 +338,7 @@ describe("propeller", () => { `flagshipPoolData: ${JSON.stringify(flagshipPoolData, null, 2)}`, ); - marginalPricePool = flagshipPool; + marginalPricePool = swimUsdPool; // const calculatedSwimPoolPda = await web3.PublicKey.createProgramAddress( // [ @@ -346,7 +349,7 @@ describe("propeller", () => { // ], // twoPoolProgram.programId, // ); - // expect(flagshipPool.toBase58()).toEqual(calculatedSwimPoolPda.toBase58()); + // expect(swimUsdPool.toBase58()).toEqual(calculatedSwimPoolPda.toBase58()); console.info(`setting up user token accounts for flagship pool`); ({ @@ -377,7 +380,7 @@ describe("propeller", () => { } `); - const seedFlagshipPoolAmounts = [ + const seedSwimUsdPoolAmounts = [ new BN(50_000_000_000_000), new BN(50_000_000_000_000), ]; @@ -387,30 +390,26 @@ describe("propeller", () => { // inputAmounts, // minimumMintAmount, // }; - const [flagshipPoolAddApproveIxs, flagshipPoolAddRevokeIxs] = + const [seedSwimUsdPoolApproveIxs, seedSwimUsdPoolRevokeIxs] = await getApproveAndRevokeIxs( splToken, [userUsdcAtaAddr, userUsdtAtaAddr], - seedFlagshipPoolAmounts, + seedSwimUsdPoolAmounts, userTransferAuthority.publicKey, payer, ); + const seedFlagshipAccts = await getAddOrRemoveAccounts( + swimUsdPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const addTxn = twoPoolProgram.methods - .add(seedFlagshipPoolAmounts, minimumMintAmount) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: flagshipPoolGovernanceFeeAcct, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userUsdcAtaAddr, - userTokenAccount1: userUsdtAtaAddr, - userLpTokenAccount: userSwimUsdAtaAddr, - tokenProgram: splToken.programId, - }) - .preInstructions([...flagshipPoolAddApproveIxs]) - .postInstructions([...flagshipPoolAddRevokeIxs]) + .add(seedSwimUsdPoolAmounts, minimumMintAmount) + .accounts(seedFlagshipAccts) + .preInstructions([...seedSwimUsdPoolApproveIxs]) + .postInstructions([...seedSwimUsdPoolRevokeIxs]) .signers([userTransferAuthority]); // .rpc(rpcCommitmentConfig); @@ -421,7 +420,7 @@ describe("propeller", () => { console.info(`addTxSig: ${addTxnSig}`); - marginalPricePool = flagshipPool; + marginalPricePool = swimUsdPool; marginalPricePoolToken0Account = poolUsdcAtaAddr; marginalPricePoolToken1Account = poolUsdtAtaAddr; marginalPricePoolLpMint = swimUsdKeypair.publicKey; @@ -446,7 +445,7 @@ describe("propeller", () => { splToken, metapoolMintKeypairs, metapoolMintDecimals, - [flagshipPool, metapoolMint1Authority.publicKey], + [swimUsdPool, metapoolMint1Authority.publicKey], // [metapoolMint1Keypair], // [metapoolMint1Decimal], // [metapoolMint1Authority.publicKey], @@ -588,20 +587,15 @@ describe("propeller", () => { userTransferAuthority.publicKey, payer, ); + const seedMetapoolAccts = await getAddOrRemoveAccounts( + metapool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const seedMetapoolTxn = await twoPoolProgram.methods .add(inputAmounts, minimumMintAmount) - .accounts({ - // propeller: propeller, - poolTokenAccount0: metapoolPoolToken0Ata, - poolTokenAccount1: metapoolPoolToken1Ata, - lpMint: metapoolLpMintKeypair.publicKey, - governanceFee: metapoolGovernanceFeeAta, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userMetapoolTokenAccount0, - userTokenAccount1: userMetapoolTokenAccount1, - userLpTokenAccount: userMetapoolLpTokenAccount, - tokenProgram: splToken.programId, - }) + .accounts(seedMetapoolAccts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -827,7 +821,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -926,22 +920,24 @@ describe("propeller", () => { tokenProgram: splToken.programId, tokenBridge, }, - feeTracker: propellerEngineFeeTracker, - aggregator, + feeTracking: feeTrackingAccts, + // feeTracker: propellerEngineFeeTracker, + // aggregator, // marginalPricePool: { // pool: marginalPricePool, // poolToken0Account: marginalPricePoolToken0Account, // poolToken1Account: marginalPricePoolToken1Account, // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, // }, // twoPoolProgram: twoPoolProgram.programId, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]); @@ -1153,7 +1149,7 @@ describe("propeller", () => { }); it("creates owner token accounts(no-op)", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolToken0Mint = usdcKeypair.publicKey; const poolToken1Mint = usdtKeypair.publicKey; const lpMint = swimUsdMint; @@ -1178,8 +1174,7 @@ describe("propeller", () => { payer: propellerEngineKeypair.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, // tokenIdMap: ? @@ -1195,12 +1190,22 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // // marginalPricePool: marginalPricePool, + // // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // // marginalPricePoolLpMint: marginalPricePoolLpMint, + // // twoPoolProgram: twoPoolProgram.programId, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, }) .preInstructions([setComputeUnitLimitIx]) .rpc(); @@ -1225,7 +1230,7 @@ describe("propeller", () => { }); it("processes swim payload", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolTokenAccount0 = poolUsdcAtaAddr; const poolTokenAccount1 = poolUsdtAtaAddr; const lpMint = swimUsdMint; @@ -1308,15 +1313,35 @@ describe("propeller", () => { ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + feeTracking: feeTrackingAccts, + // fees: { + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, owner, memo: MEMO_PROGRAM_ID, }) @@ -1521,7 +1546,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -1610,22 +1635,24 @@ describe("propeller", () => { tokenProgram: splToken.programId, tokenBridge, }, - feeTracker: propellerEngineFeeTracker, - aggregator, + feeTracking: feeTrackingAccts, + // feeTracker: propellerEngineFeeTracker, + // aggregator, // marginalPricePool: { // pool: marginalPricePool, // poolToken0Account: marginalPricePoolToken0Account, // poolToken1Account: marginalPricePoolToken1Account, // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, // }, // twoPoolProgram: twoPoolProgram.programId, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -1833,7 +1860,7 @@ describe("propeller", () => { }); it("creates owner token accounts", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolToken0Mint = usdcKeypair.publicKey; const poolToken1Mint = usdtKeypair.publicKey; const lpMint = swimUsdMint; @@ -1877,8 +1904,7 @@ describe("propeller", () => { payer: propellerEngineKeypair.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, // tokenIdMap: ? @@ -1897,12 +1923,22 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) .rpc(); @@ -1996,7 +2032,7 @@ describe("propeller", () => { }); it("processes swim payload", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolTokenAccount0 = poolUsdcAtaAddr; const poolTokenAccount1 = poolUsdtAtaAddr; const lpMint = swimUsdMint; @@ -2115,15 +2151,35 @@ describe("propeller", () => { // systemProgram: web3.SystemProgram.programId, // }, processSwimPayload: processSwimPayloadPubkeys, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, + feeTracking: feeTrackingAccts, + // fees: { + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // }, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, owner, memo: MEMO_PROGRAM_ID, }) @@ -2386,7 +2442,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -2467,14 +2523,21 @@ describe("propeller", () => { tokenProgram: splToken.programId, tokenBridge, }, - feeTracker: propellerEngineFeeTracker, - aggregator, - - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -2687,8 +2750,7 @@ describe("propeller", () => { payer: propellerEngineKeypair.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, tokenIdMap: invalidTokenIdMapAddr, @@ -2699,12 +2761,15 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, rent: web3.SYSVAR_RENT_PUBKEY, }) .preInstructions([setComputeUnitLimitIx]) @@ -2778,15 +2843,18 @@ describe("propeller", () => { userSwimUsdAta: ownerSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - twoPoolProgram: twoPoolProgram.programId, + systemProgram: web3.SystemProgram.programId, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, + feeTracking: feeTrackingAccts, + + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, owner, }) .preInstructions([setComputeUnitLimitIx]) @@ -2998,7 +3066,7 @@ describe("propeller", () => { // swimUsdKeypair.publicKey.toBuffer(), // CHAIN_ID_SOLANA, // propellerProgram.programId, - // ethRoutingContract, + // evmRoutingContractBuffer, // encodeSwimPayload(swimPayload), // ), // ); @@ -3190,7 +3258,7 @@ describe("propeller", () => { // // eslint-disable-next-line jest/no-commented-out-tests // it("processes swim payload", async () => { - // const pool = flagshipPool; + // const pool = swimUsdPool; // const poolTokenAccount0 = poolUsdcAtaAddr; // const poolTokenAccount1 = poolUsdtAtaAddr; // const lpMint = swimUsdMint; @@ -3414,7 +3482,7 @@ describe("propeller", () => { // swimUsdKeypair.publicKey.toBuffer(), // CHAIN_ID_SOLANA, // propellerProgram.programId, - // ethRoutingContract, + // evmRoutingContractBuffer, // encodeSwimPayload(swimPayload), // ), // ); @@ -3828,7 +3896,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -3927,22 +3995,24 @@ describe("propeller", () => { tokenProgram: splToken.programId, tokenBridge, }, - feeTracker: propellerEngineFeeTracker, - aggregator, + feeTracking: feeTrackingAccts, + // aggregator, + // feeTracker: propellerEngineFeeTracker, // marginalPricePool: { // pool: marginalPricePool, // poolToken0Account: marginalPricePoolToken0Account, // poolToken1Account: marginalPricePoolToken1Account, // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, // }, // twoPoolProgram: twoPoolProgram.programId, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -4152,7 +4222,7 @@ describe("propeller", () => { }); it("creates owner token accounts", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolToken0Mint = usdcKeypair.publicKey; const poolToken1Mint = usdtKeypair.publicKey; const lpMint = swimUsdMint; @@ -4180,8 +4250,7 @@ describe("propeller", () => { payer: propellerEngineKeypair.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, // tokenIdMap: ? @@ -4200,12 +4269,22 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) .rpc(); @@ -4251,7 +4330,7 @@ describe("propeller", () => { }); it("processes swim payload", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolTokenAccount0 = poolUsdcAtaAddr; const poolTokenAccount1 = poolUsdtAtaAddr; const lpMint = swimUsdMint; @@ -4326,15 +4405,35 @@ describe("propeller", () => { ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, + feeTracking: feeTrackingAccts, + // fees: { + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // }, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, owner, memo: MEMO_PROGRAM_ID, }) @@ -4613,7 +4712,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -4900,7 +4999,7 @@ describe("propeller", () => { // getAssociatedTokenAddress(swimUsdKeypair.publicKey, owner), // ]); const userPoolAtas = await getOwnerAtaAddrsForPool( - flagshipPool, + swimUsdPool, owner, twoPoolProgram, ); @@ -4965,7 +5064,7 @@ describe("propeller", () => { ); const userBalanceBefore = await connection.getBalance(owner); const userPoolAtas = await getOwnerAtaAddrsForPool( - flagshipPool, + swimUsdPool, owner, twoPoolProgram, ); @@ -5170,7 +5269,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -5723,7 +5822,7 @@ describe("propeller", () => { swimUsdKeypair.publicKey.toBuffer(), CHAIN_ID_SOLANA, propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, encodeSwimPayload(swimPayload), ), ); @@ -5811,16 +5910,23 @@ describe("propeller", () => { tokenProgram: splToken.programId, tokenBridge, }, - feeTracker: propellerEngineFeeTracker, - aggregator, - - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -6019,7 +6125,7 @@ describe("propeller", () => { }); it("creates owner token accounts", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolToken0Mint = usdcKeypair.publicKey; const poolToken1Mint = usdtKeypair.publicKey; const lpMint = swimUsdMint; @@ -6048,8 +6154,7 @@ describe("propeller", () => { payer: propellerEngineKeypair.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, // tokenIdMap: ? @@ -6068,14 +6173,24 @@ describe("propeller", () => { systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) .rpc(); @@ -6122,7 +6237,7 @@ describe("propeller", () => { }); it("processes swim payload", async () => { - const pool = flagshipPool; + const pool = swimUsdPool; const poolTokenAccount0 = poolUsdcAtaAddr; const poolTokenAccount1 = poolUsdtAtaAddr; const lpMint = swimUsdMint; @@ -6200,15 +6315,25 @@ describe("propeller", () => { ) .accounts({ processSwimPayload: processSwimPayloadPubkeys, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: - marginalPricePoolToken0Account, - marginalPricePoolToken1Account: - marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, + feeTracking: feeTrackingAccts, + // fees: { + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: + // marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: + // marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, owner, memo: MEMO_PROGRAM_ID, }) @@ -6554,7 +6679,7 @@ describe("propeller", () => { // // const setupFlagshipPool = async () => { // ({ -// poolPubkey: flagshipPool, +// poolPubkey: swimUsdPool, // poolTokenAccounts: [poolUsdcAtaAddr, poolUsdtAtaAddr], // governanceFeeAccount: flagshipPoolGovernanceFeeAcct, // } = await setupPoolPrereqs( @@ -6594,10 +6719,10 @@ describe("propeller", () => { // } // const pool = pubkeys.pool; // console.info( -// `poolKey: ${pool.toBase58()}, expected: ${flagshipPool.toBase58()}`, +// `poolKey: ${pool.toBase58()}, expected: ${swimUsdPool.toBase58()}`, // ); // -// expect(pool.toBase58()).toBe(flagshipPool.toBase58()); +// expect(pool.toBase58()).toBe(swimUsdPool.toBase58()); // const initFlagshipPoolTxnSig = await initFlagshipPoolTxn.rpc( // rpcCommitmentConfig, // ); @@ -6609,7 +6734,7 @@ describe("propeller", () => { // `flagshipPoolData: ${JSON.stringify(flagshipPoolData, null, 2)}`, // ); // -// marginalPricePool = flagshipPool; +// marginalPricePool = swimUsdPool; // marginalPricePoolToken0Account = poolUsdcAtaAddr; // marginalPricePoolToken1Account = poolUsdtAtaAddr; // marginalPricePoolLpMint = swimUsdKeypair.publicKey; @@ -6623,7 +6748,7 @@ describe("propeller", () => { // ], // twoPoolProgram.programId, // ); -// expect(flagshipPool.toBase58()).toBe(calculatedSwimPoolPda.toBase58()); +// expect(swimUsdPool.toBase58()).toBe(calculatedSwimPoolPda.toBase58()); // // console.info(`setting up user token accounts for flagship pool`); // ({ @@ -6646,7 +6771,7 @@ describe("propeller", () => { // `done setting up flagship pool and relevant user token accounts`, // ); // console.info(` -// flagshipPool: ${JSON.stringify(flagshipPoolData, null, 2)} +// swimUsdPool: ${JSON.stringify(flagshipPoolData, null, 2)} // user: { // userUsdcAtaAddr: ${userUsdcAtaAddr.toBase58()} // userUsdtAtaAddr: ${userUsdtAtaAddr.toBase58()} @@ -6717,7 +6842,7 @@ describe("propeller", () => { // splToken, // metapoolMintKeypairs, // metapoolMintDecimals, -// [flagshipPool, metapoolMint1Authority.publicKey], +// [swimUsdPool, metapoolMint1Authority.publicKey], // // [metapoolMintKeypair1], // // [metapoolMint1Decimal], // // [metapoolMint1Authority.publicKey], @@ -6911,7 +7036,7 @@ const initializePropeller = async () => { associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, systemProgram: web3.SystemProgram.programId, rent: web3.SYSVAR_RENT_PUBKEY, - pool: flagshipPool, + pool: swimUsdPool, poolTokenMint0: usdcKeypair.publicKey, poolTokenMint1: usdtKeypair.publicKey, lpMint: swimUsdKeypair.publicKey, @@ -6972,23 +7097,29 @@ const initializePropeller = async () => { propellerRedeemer: ${propellerRedeemer.toBase58()} propellerRedeemerEscrowAccount: ${propellerRedeemerEscrowAccount.toBase58()} `); + feeTrackingAccts = await getFeeTrackingAccounts( + propeller, + propellerEngineKeypair.publicKey, + propellerEnginePropellerProgram, + twoPoolProgram, + ); }; const createTokenIdMaps = async () => { const swimUsdTokenNumberMap = { - pool: flagshipPool, + pool: swimUsdPool, poolTokenIndex: 0, poolTokenMint: swimUsdKeypair.publicKey, toTokenStep: { transfer: {} }, }; const usdcTokenNumberMap = { - pool: flagshipPool, + pool: swimUsdPool, poolTokenIndex: usdcPoolTokenIndex, poolTokenMint: usdcKeypair.publicKey, toTokenStep: { removeExactBurn: {} }, }; const usdtTokenNumberMap = { - pool: flagshipPool, + pool: swimUsdPool, poolTokenIndex: usdtPoolTokenIndex, poolTokenMint: usdtKeypair.publicKey, toTokenStep: { removeExactBurn: {} }, diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index 6a2c799d0..2da65c512 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -7,6 +7,7 @@ import { getClaimAddressSolana, postVaaSolanaWithRetry, setDefaultWasm, + tryNativeToHexString, uint8ArrayToHex, } from "@certusone/wormhole-sdk"; import { parseUnits } from "@ethersproject/units"; @@ -38,6 +39,7 @@ import { getApproveAndRevokeIxs, idl } from "../../index"; import { DEFAULT_SOL_USD_FEED, PROPELLER_PID, + SWIM_MEMO_LENGTH, SWIM_USD_TO_TOKEN_NUMBER, TWO_POOL_PID, USDC_TO_TOKEN_NUMBER, @@ -46,11 +48,11 @@ import { bscTokenBridge, commitment, completeWithPayloadFee, - ethRoutingContract, - ethRoutingContractEthHexStr, ethTokenBridge, ethTokenBridgeNativeStr, evmOwner, + evmRoutingContractBuffer, + evmRoutingContractHexStr, evmTargetTokenId, gasKickstartAmount, governanceFee, @@ -72,6 +74,7 @@ import { usdtPoolTokenIndex, } from "../consts"; import { + getAddOrRemoveAccounts, getPoolTokenAccountBalances, getPoolUserBalances, getUserAtaBalancesForPool, @@ -93,6 +96,7 @@ import { getPropellerSenderPda, getSwimClaimPda, getSwimPayloadMessagePda, + getTargetChainMapAddr, getToTokenNumberMapAddr, getWormholeAddressesForMint, parseTokenTransferWithSwimPayloadPostedMessage, @@ -110,7 +114,6 @@ import { signAndEncodeVaa, } from "./wormholeUtils"; - setDefaultWasm("node"); const envProvider = AnchorProvider.env(); @@ -253,7 +256,7 @@ const dummyEthTokenBridge: DummyForeignRoutingProgram = ethTokenBridgeSequence, swimUsdMint.toBuffer(), propellerProgram.programId, - ethRoutingContract, + evmRoutingContractBuffer, ); describe("propeller", () => { @@ -549,7 +552,7 @@ describe("propeller", () => { marginalPricePoolTokenIndex, marginalPricePoolTokenMint, maxStaleness, - // evmRoutingContractAddress: ethRoutingContract, + // evmRoutingContractAddress: evmRoutingContractBuffer, // evmRoutingContractAddress: ethRoutingContractEthUint8Arr }; const tx = propellerProgram.methods @@ -783,47 +786,96 @@ describe("propeller", () => { } }); - it("Creates target chain maps", async () => { - const targetChainMaps = await Promise.all( - routingContracts.map(async ({ targetChainId, address }) => { - const createTargetChainMap = propellerProgram.methods - .createTargetChainMap(targetChainId, address) - .accounts({ - propeller, - governanceKey: propellerGovernanceKey.publicKey, - payer: payer.publicKey, - systemProgram: web3.SystemProgram.programId, - // rent: web3.SYSVAR_RENT_PUBKEY, - }) - .signers([propellerGovernanceKey]); - - const createTargetChainMapPubkeys = - await createTargetChainMap.pubkeys(); - await createTargetChainMap.rpc(); - const targetChainMapData = - await propellerProgram.account.targetChainMap.fetch( - createTargetChainMapPubkeys.targetChainMap, + describe("Target Chain Maps", () => { + it("Creates target chain maps", async () => { + const targetChainMaps = await Promise.all( + routingContracts.map(async ({ targetChainId, address }) => { + const createTargetChainMap = propellerProgram.methods + .createTargetChainMap(targetChainId, address) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + systemProgram: web3.SystemProgram.programId, + // rent: web3.SYSVAR_RENT_PUBKEY, + }) + .signers([propellerGovernanceKey]); + + const createTargetChainMapPubkeys = + await createTargetChainMap.pubkeys(); + await createTargetChainMap.rpc(); + const targetChainMapData = + await propellerProgram.account.targetChainMap.fetch( + createTargetChainMapPubkeys.targetChainMap, + ); + return { + targetChainId, + targetAddress: address, + targetChainMapData, + }; + }), + ); + targetChainMaps.forEach( + ({ targetChainId, targetAddress, targetChainMapData }) => { + expect(targetChainMapData.targetChain).toEqual(targetChainId); + expect(Buffer.from(targetChainMapData.targetAddress)).toEqual( + targetAddress, ); - return { - targetChainId, - targetAddress: address, - targetChainMapData, - }; - }), - ); - targetChainMaps.forEach( - ({ targetChainId, targetAddress, targetChainMapData }) => { - expect(targetChainMapData.targetChain).toEqual(targetChainId); - expect(Buffer.from(targetChainMapData.targetAddress)).toEqual( - targetAddress, - ); - }, - ); + }, + ); + }); + it("Updates target chain maps", async () => { + const targetChain = CHAIN_ID_ETH; + const [targetChainMapAddr] = await getTargetChainMapAddr( + propeller, + targetChain, + propellerProgram.programId, + ); + const newTargetAddressNativeStr = + "0x280999aB9aBfDe9DC5CE7aFB25497d6BB3e8bDD5"; + const newTargetAddress = Buffer.from( + tryNativeToHexString(newTargetAddressNativeStr, targetChain), + "hex", + ); + await propellerProgram.methods + .updateTargetChainMap(targetChain, newTargetAddress) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + targetChainMap: targetChainMapAddr, + }) + .signers([propellerGovernanceKey]) + .rpc(); + + const targetChainMapDataAfter = + await propellerProgram.account.targetChainMap.fetch(targetChainMapAddr); + expect(Buffer.from(targetChainMapDataAfter.targetAddress)).toEqual( + newTargetAddress, + ); + + await propellerProgram.methods + .updateTargetChainMap(targetChain, evmRoutingContractBuffer) + .accounts({ + propeller, + governanceKey: propellerGovernanceKey.publicKey, + payer: payer.publicKey, + targetChainMap: targetChainMapAddr, + }) + .signers([propellerGovernanceKey]) + .rpc(); + + const targetChainMapDataAfter2 = + await propellerProgram.account.targetChainMap.fetch(targetChainMapAddr); + expect(Buffer.from(targetChainMapDataAfter2.targetAddress)).toEqual( + evmRoutingContractBuffer, + ); + }); }); - describe("Propeller Pool Ixs", () => { - describe("Propeller Flagship Pool ixs", () => { - it("Cross Chain Add", async () => { + describe("InitToSwimUSD", () => { + describe("for swimUSD pool", () => { + it("crossChainInitToSwimUsd", async () => { const poolUserBalancesBefore = await getPoolUserBalances( splToken, twoPoolProgram, @@ -857,7 +909,7 @@ describe("propeller", () => { const memoStr = createMemoId(); const addTxn = propellerProgram.methods - .crossChainAdd(inputAmounts, minimumMintAmount) + .crossChainInitToSwimUsd(inputAmounts, minimumMintAmount) .accounts({ propeller: propeller, poolTokenAccount0: poolUsdcAtaAddr, @@ -946,7 +998,7 @@ describe("propeller", () => { expect(previousDepthAfter.gt(previousDepthBefore)).toEqual(true); await checkTxnLogsForMemo(addTxnSig, memoStr); }); - describe("Propeller Add", () => { + describe("propellerInitToSwimUsd", () => { it("executes successfully", async () => { const poolUserBalancesBefore = await getPoolUserBalances( splToken, @@ -974,7 +1026,7 @@ describe("propeller", () => { const maxFee = new BN(100); const addTxn = propellerProgram.methods - .propellerAdd(inputAmounts, maxFee) + .propellerInitToSwimUsd(inputAmounts, maxFee) .accounts({ propeller: propeller, poolTokenAccount0: poolUsdcAtaAddr, @@ -1086,7 +1138,7 @@ describe("propeller", () => { const maxFee = new BN(50_000_000_000); await expect(() => { return propellerProgram.methods - .propellerAdd(inputAmounts, maxFee) + .propellerInitToSwimUsd(inputAmounts, maxFee) .accounts({ propeller: propeller, poolTokenAccount0: poolUsdcAtaAddr, @@ -1111,8 +1163,7 @@ describe("propeller", () => { }); }); }); - - describe("Propeller Metapool Pool ixs", () => { + describe("for metapool", () => { beforeAll(async () => { console.info("seeding metapool"); const poolUserBalancesBefore = await getPoolUserBalances( @@ -1162,10 +1213,68 @@ describe("propeller", () => { userTransferAuthority.publicKey, payer, ); + const seedMetapoolAccts = await getAddOrRemoveAccounts( + metapool, + payer.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const seedMetapoolTxn = await twoPoolProgram.methods .add(inputAmounts, minimumMintAmount) + .accounts(seedMetapoolAccts) + .preInstructions([...approveIxs]) + .postInstructions([...revokeIxs]) + .signers([userTransferAuthority]) + .rpc(); + + console.info(`seedMetapoolTxn: ${seedMetapoolTxn}`); + const poolUserBalancesAfter = await getPoolUserBalances( + splToken, + twoPoolProgram, + metapoolPoolToken0Ata, + metapoolPoolToken1Ata, + metapoolGovernanceFeeAta, + userMetapoolTokenAccount0, + userMetapoolTokenAccount1, + userMetapoolLpTokenAccount, + metapool, + metapoolLpMintKeypair.publicKey, + ); + printBeforeAndAfterPoolUserBalances("seeding metapool", [ + poolUserBalancesBefore, + poolUserBalancesAfter, + ]); + }); + it("crossChainInitToSwimUsd", async () => { + const poolUserBalancesBefore = await getPoolUserBalances( + splToken, + twoPoolProgram, + metapoolPoolToken0Ata, + metapoolPoolToken1Ata, + metapoolGovernanceFeeAta, + userMetapoolTokenAccount0, + userMetapoolTokenAccount1, + userMetapoolLpTokenAccount, + metapool, + metapoolLpMintKeypair.publicKey, + ); + printPoolUserBalances("poolUserBalancesBefore", poolUserBalancesBefore); + const exactInputAmounts = [new BN(0), new BN(100_000)]; + const minimumOutputAmount = new BN(0); + const userTransferAuthority = web3.Keypair.generate(); + const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( + splToken, + [userMetapoolTokenAccount0, userMetapoolTokenAccount1], + exactInputAmounts, + userTransferAuthority.publicKey, + payer, + ); + const memoStr = createMemoId(); + + const swapExactInputTxnSig = await propellerProgram.methods + .crossChainInitToSwimUsd(exactInputAmounts, minimumOutputAmount) .accounts({ - // propeller: propeller, + propeller, poolTokenAccount0: metapoolPoolToken0Ata, poolTokenAccount1: metapoolPoolToken1Ata, lpMint: metapoolLpMintKeypair.publicKey, @@ -1175,13 +1284,19 @@ describe("propeller", () => { userTokenAccount1: userMetapoolTokenAccount1, userLpTokenAccount: userMetapoolLpTokenAccount, tokenProgram: splToken.programId, + twoPoolProgram: twoPoolProgram.programId, }) .preInstructions([...approveIxs]) - .postInstructions([...revokeIxs]) + .postInstructions([ + ...revokeIxs, + createMemoInstruction(memoStr.toString("hex")), + ]) .signers([userTransferAuthority]) - .rpc(); + .rpc(rpcCommitmentConfig); + + console.info(`swapExactInputTxnSig: ${swapExactInputTxnSig}`); + await checkTxnLogsForMemo(swapExactInputTxnSig, memoStr); - console.info(`seedMetapoolTxn: ${seedMetapoolTxn}`); const poolUserBalancesAfter = await getPoolUserBalances( splToken, twoPoolProgram, @@ -1194,13 +1309,65 @@ describe("propeller", () => { metapool, metapoolLpMintKeypair.publicKey, ); - printBeforeAndAfterPoolUserBalances("seeding metapool", [ - poolUserBalancesBefore, - poolUserBalancesAfter, - ]); + console.info(`swapExactInput (non propeller-enabled) balances`); + printBeforeAndAfterPoolUserBalances( + "swapExactInput (non propeller-enabled) balances", + [poolUserBalancesBefore, poolUserBalancesAfter], + ); + + const { + poolTokenBalances: [ + poolToken0AtaBalanceBefore, + poolToken1AtaBalanceBefore, + ], + governanceFeeBalance: governanceFeeBalanceBefore, + userTokenBalances: [ + userToken0AtaBalanceBefore, + userToken1AtaBalanceBefore, + ], + userLpTokenBalance: userLpTokenBalanceBefore, + previousDepth: previousDepthBefore, + } = poolUserBalancesBefore; + + const { + poolTokenBalances: [ + poolToken0AtaBalanceAfter, + poolToken1AtaBalanceAfter, + ], + governanceFeeBalance: governanceFeeBalanceAfter, + userTokenBalances: [ + userToken0AtaBalanceAfter, + userToken1AtaBalanceAfter, + ], + userLpTokenBalance: userLpTokenBalanceAfter, + previousDepth: previousDepthAfter, + } = poolUserBalancesAfter; + + expect( + poolToken0AtaBalanceAfter.lt(poolToken0AtaBalanceBefore), + ).toEqual(true); + expect( + poolToken1AtaBalanceAfter.gt(poolToken1AtaBalanceBefore), + ).toEqual(true); + + expect( + governanceFeeBalanceAfter.gt(governanceFeeBalanceBefore), + ).toEqual(true); + expect( + userToken0AtaBalanceAfter.gt(userToken0AtaBalanceBefore), + ).toEqual(true); + expect( + userToken1AtaBalanceAfter.eq( + userToken1AtaBalanceBefore.sub(exactInputAmounts[1]), + ), + ).toEqual(true); + expect(userLpTokenBalanceAfter.eq(userLpTokenBalanceBefore)).toEqual( + true, + ); + expect(!previousDepthAfter.eq(previousDepthBefore)).toBeTruthy(); }); - describe("Swap Exact Input", () => { - it("CrossChainSwapExactInput", async () => { + describe("propellerInitToSwimUsd", () => { + it("executes successfully", async () => { const poolUserBalancesBefore = await getPoolUserBalances( splToken, twoPoolProgram, @@ -1217,21 +1384,23 @@ describe("propeller", () => { "poolUserBalancesBefore", poolUserBalancesBefore, ); - const exactInputAmount = new BN(100_000); - const minimumOutputAmount = new BN(0); + const exactInputAmounts = [new BN(0), new BN(100_000)]; + const maxFee = new BN(0); const userTransferAuthority = web3.Keypair.generate(); const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( splToken, - [userMetapoolTokenAccount1], - [exactInputAmount], + [userMetapoolTokenAccount0, userMetapoolTokenAccount1], + exactInputAmounts, userTransferAuthority.publicKey, payer, ); + const memoStr = createMemoId(); const swapExactInputTxn = propellerProgram.methods - .crossChainSwapExactInput(exactInputAmount, minimumOutputAmount) + .propellerInitToSwimUsd(exactInputAmounts, maxFee) .accounts({ + propeller, poolTokenAccount0: metapoolPoolToken0Ata, poolTokenAccount1: metapoolPoolToken1Ata, lpMint: metapoolLpMintKeypair.publicKey, @@ -1239,9 +1408,9 @@ describe("propeller", () => { userTransferAuthority: userTransferAuthority.publicKey, userTokenAccount0: userMetapoolTokenAccount0, userTokenAccount1: userMetapoolTokenAccount1, + userLpTokenAccount: userMetapoolLpTokenAccount, tokenProgram: splToken.programId, twoPoolProgram: twoPoolProgram.programId, - swimUsdMint: swimUsdMint, }) .preInstructions([...approveIxs]) .postInstructions([ @@ -1327,7 +1496,7 @@ describe("propeller", () => { ).toEqual(true); expect( userToken1AtaBalanceAfter.eq( - userToken1AtaBalanceBefore.sub(exactInputAmount), + userToken1AtaBalanceBefore.sub(exactInputAmounts[1]), ), ).toEqual(true); expect(userLpTokenBalanceAfter.eq(userLpTokenBalanceBefore)).toEqual( @@ -1335,179 +1504,43 @@ describe("propeller", () => { ); expect(!previousDepthAfter.eq(previousDepthBefore)).toBeTruthy(); }); - describe("PropellerSwapExactInput", () => { - it("executes successfully", async () => { - const poolUserBalancesBefore = await getPoolUserBalances( - splToken, - twoPoolProgram, - metapoolPoolToken0Ata, - metapoolPoolToken1Ata, - metapoolGovernanceFeeAta, - userMetapoolTokenAccount0, - userMetapoolTokenAccount1, - userMetapoolLpTokenAccount, - metapool, - metapoolLpMintKeypair.publicKey, - ); - printPoolUserBalances( - "poolUserBalancesBefore", - poolUserBalancesBefore, - ); - const exactInputAmount = new BN(100_000); - const maxFee = new BN(0); - const userTransferAuthority = web3.Keypair.generate(); - const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( - splToken, - [userMetapoolTokenAccount1], - [exactInputAmount], - userTransferAuthority.publicKey, - payer, - ); - const memoStr = createMemoId(); - - const swapExactInputTxn = propellerProgram.methods - .propellerSwapExactInput(exactInputAmount, maxFee) - .accounts({ - poolTokenAccount0: metapoolPoolToken0Ata, - poolTokenAccount1: metapoolPoolToken1Ata, - lpMint: metapoolLpMintKeypair.publicKey, - governanceFee: metapoolGovernanceFeeAta, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userMetapoolTokenAccount0, - userTokenAccount1: userMetapoolTokenAccount1, - tokenProgram: splToken.programId, - twoPoolProgram: twoPoolProgram.programId, - swimUsdMint: swimUsdMint, - }) - .preInstructions([...approveIxs]) - .postInstructions([ - ...revokeIxs, - createMemoInstruction(memoStr.toString("hex")), - ]) - .signers([userTransferAuthority]); - // .rpc(rpcCommitmentConfig); - - const swapExactInputTxnPubkeys = await swapExactInputTxn.pubkeys(); - console.info( - `swapExactInputTxPubkeys: ${JSON.stringify( - swapExactInputTxnPubkeys, - null, - 2, - )}`, - ); - - const swapExactInputTxnSig = await swapExactInputTxn.rpc( - rpcCommitmentConfig, - ); - console.info(`swapExactInputTxnSig: ${swapExactInputTxnSig}`); - await checkTxnLogsForMemo(swapExactInputTxnSig, memoStr); - - const poolUserBalancesAfter = await getPoolUserBalances( - splToken, - twoPoolProgram, - metapoolPoolToken0Ata, - metapoolPoolToken1Ata, - metapoolGovernanceFeeAta, - userMetapoolTokenAccount0, - userMetapoolTokenAccount1, - userMetapoolLpTokenAccount, - metapool, - metapoolLpMintKeypair.publicKey, - ); - console.info(`swapExactInput (non propeller-enabled) balances`); - printBeforeAndAfterPoolUserBalances( - "swapExactInput (non propeller-enabled) balances", - [poolUserBalancesBefore, poolUserBalancesAfter], - ); - - const { - poolTokenBalances: [ - poolToken0AtaBalanceBefore, - poolToken1AtaBalanceBefore, - ], - governanceFeeBalance: governanceFeeBalanceBefore, - userTokenBalances: [ - userToken0AtaBalanceBefore, - userToken1AtaBalanceBefore, - ], - userLpTokenBalance: userLpTokenBalanceBefore, - previousDepth: previousDepthBefore, - } = poolUserBalancesBefore; - - const { - poolTokenBalances: [ - poolToken0AtaBalanceAfter, - poolToken1AtaBalanceAfter, - ], - governanceFeeBalance: governanceFeeBalanceAfter, - userTokenBalances: [ - userToken0AtaBalanceAfter, - userToken1AtaBalanceAfter, - ], - userLpTokenBalance: userLpTokenBalanceAfter, - previousDepth: previousDepthAfter, - } = poolUserBalancesAfter; - - expect( - poolToken0AtaBalanceAfter.lt(poolToken0AtaBalanceBefore), - ).toEqual(true); - expect( - poolToken1AtaBalanceAfter.gt(poolToken1AtaBalanceBefore), - ).toEqual(true); - - expect( - governanceFeeBalanceAfter.gt(governanceFeeBalanceBefore), - ).toEqual(true); - expect( - userToken0AtaBalanceAfter.gt(userToken0AtaBalanceBefore), - ).toEqual(true); - expect( - userToken1AtaBalanceAfter.eq( - userToken1AtaBalanceBefore.sub(exactInputAmount), - ), - ).toEqual(true); - expect( - userLpTokenBalanceAfter.eq(userLpTokenBalanceBefore), - ).toEqual(true); - expect(!previousDepthAfter.eq(previousDepthBefore)).toBeTruthy(); - }); - it("fails if output amount < max fee", async () => { - const exactInputAmount = new BN(100_000); - const maxFee = new BN(100_000_000_000); - const userTransferAuthority = web3.Keypair.generate(); - const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( - splToken, - [userMetapoolTokenAccount1], - [exactInputAmount], - userTransferAuthority.publicKey, - payer, - ); - const memoStr = createMemoId(); + it("fails if output amount < max fee", async () => { + const exactInputAmounts = [new BN(0), new BN(100_000_000)]; + const maxFee = new BN(100_000_000_000); + const userTransferAuthority = web3.Keypair.generate(); + const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( + splToken, + [userMetapoolTokenAccount0, userMetapoolTokenAccount1], + exactInputAmounts, + userTransferAuthority.publicKey, + payer, + ); + const memoStr = createMemoId(); - const swapExactInputTxn = propellerProgram.methods - .propellerSwapExactInput(exactInputAmount, maxFee) - .accounts({ - poolTokenAccount0: metapoolPoolToken0Ata, - poolTokenAccount1: metapoolPoolToken1Ata, - lpMint: metapoolLpMintKeypair.publicKey, - governanceFee: metapoolGovernanceFeeAta, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userMetapoolTokenAccount0, - userTokenAccount1: userMetapoolTokenAccount1, - tokenProgram: splToken.programId, - twoPoolProgram: twoPoolProgram.programId, - swimUsdMint: swimUsdMint, - }) - .preInstructions([...approveIxs]) - .postInstructions([ - ...revokeIxs, - createMemoInstruction(memoStr.toString("hex")), - ]) - .signers([userTransferAuthority]); - await expect(swapExactInputTxn.rpc()).rejects.toThrow( - "Insufficient Amount being transferred", - ); - }); + const swapExactInputTxn = propellerProgram.methods + .propellerInitToSwimUsd(exactInputAmounts, maxFee) + .accounts({ + propeller, + poolTokenAccount0: metapoolPoolToken0Ata, + poolTokenAccount1: metapoolPoolToken1Ata, + lpMint: metapoolLpMintKeypair.publicKey, + governanceFee: metapoolGovernanceFeeAta, + userTransferAuthority: userTransferAuthority.publicKey, + userTokenAccount0: userMetapoolTokenAccount0, + userTokenAccount1: userMetapoolTokenAccount1, + userLpTokenAccount: userMetapoolLpTokenAccount, + tokenProgram: splToken.programId, + twoPoolProgram: twoPoolProgram.programId, + }) + .preInstructions([...approveIxs]) + .postInstructions([ + ...revokeIxs, + createMemoInstruction(memoStr.toString("hex")), + ]) + .signers([userTransferAuthority]); + await expect(swapExactInputTxn.rpc()).rejects.toThrow( + "Insufficient Amount being transferred", + ); }); }); }); @@ -1631,7 +1664,7 @@ describe("propeller", () => { const tokenTransferTo = tokenTransferMessage.tokenTransfer.to; expect(uint8ArrayToHex(tokenTransferTo)).toEqual( - ethRoutingContractEthHexStr, + evmRoutingContractHexStr, ); const formattedTokenTransferMessage = formatParsedTokenTransferPostedMessage(tokenTransferMessage); @@ -1776,7 +1809,7 @@ describe("propeller", () => { expect(swimPayload.maxFee.eq(maxFee)).toBeTruthy(); const tokenTransferTo = tokenTransferMessage.tokenTransfer.to; expect(uint8ArrayToHex(tokenTransferTo)).toEqual( - ethRoutingContractEthHexStr, + evmRoutingContractHexStr, ); const formattedTokenTransferMessage = formatParsedTokenTransferPostedMessage(tokenTransferMessage); @@ -1920,7 +1953,7 @@ describe("propeller", () => { expect(swimPayload.maxFee.eq(maxFee)).toBeTruthy(); const tokenTransferTo = tokenTransferMessage.tokenTransfer.to; expect(uint8ArrayToHex(tokenTransferTo)).toEqual( - ethRoutingContractEthHexStr, + evmRoutingContractHexStr, ); const formattedTokenTransferMessage = formatParsedTokenTransferPostedMessage(tokenTransferMessage); @@ -1940,19 +1973,191 @@ describe("propeller", () => { await checkTxnLogsForMemo(transferNativeTxnSig, memo, false); }); - it("Fails propellerTransferNativeWithPayload if transferAmount <= maxFee for targetChain", async () => { - const transferAmount = new BN(100_000_000); + describe("error cases", () => { + it("Fails propellerTransferNativeWithPayload if transferAmount <= maxFee for targetChain", async () => { + const transferAmount = new BN(100_000_000); + + const wormholeMessage = web3.Keypair.generate(); + const gasKickstart = false; + const maxFee = transferAmount.add(new BN(1)); + const nonce = createNonce().readUInt32LE(0); + await expect(() => { + return propellerProgram.methods + .propellerTransferNativeWithPayload( + nonce, + transferAmount, + CHAIN_ID_ETH, + evmOwner, + gasKickstart, + maxFee, + evmTargetTokenId, + null, + ) + .accounts({ + propeller, + payer: payer.publicKey, + tokenBridgeConfig, + userSwimUsdAta: userSwimUsdAtaAddr, + swimUsdMint: swimUsdMint, + custody, + tokenBridge, + custodySigner, + authoritySigner, + wormholeConfig, + wormholeMessage: wormholeMessage.publicKey, + wormholeEmitter, + wormholeSequence, + wormholeFeeCollector, + clock: web3.SYSVAR_CLOCK_PUBKEY, + // autoderived + // sender + rent: web3.SYSVAR_RENT_PUBKEY, + // autoderived + // systemProgram, + wormhole, + tokenProgram: splToken.programId, + }) + .signers([wormholeMessage]) + .preInstructions([setComputeUnitLimitIx]) + .rpc(); + }).rejects.toThrow("Insufficient Amount being transferred"); + }); + it("fails if targetChain is paused", async () => { + const targetChain = CHAIN_ID_ETH; + let isPaused = true; + const [targetChainMapAddr] = await getTargetChainMapAddr( + propeller, + targetChain, + propellerProgram.programId, + ); + await propellerProgram.methods + .targetChainMapSetPaused(targetChain, isPaused) + .accounts({ + propeller, + pauseKey: propellerPauseKey.publicKey, + payer: payer.publicKey, + targetChainMap: targetChainMapAddr, + }) + .signers([propellerPauseKey]) + .rpc(); - const wormholeMessage = web3.Keypair.generate(); - const gasKickstart = false; - const maxFee = transferAmount.add(new BN(1)); - const nonce = createNonce().readUInt32LE(0); - await expect(() => { - return propellerProgram.methods + const targetChainMapData = + await propellerProgram.account.targetChainMap.fetch( + targetChainMapAddr, + ); + expect(targetChainMapData.isPaused).toEqual(isPaused); + const transferAmount = new BN(100_000_000); + + const memo = createMemoId(); + let wormholeMessage = web3.Keypair.generate(); + + const nonce = createNonce().readUInt32LE(0); + await expect(() => { + return propellerProgram.methods + .crossChainTransferNativeWithPayload( + nonce, + transferAmount, + targetChain, + evmOwner, + ) + .accounts({ + propeller, + payer: payer.publicKey, + tokenBridgeConfig, + userSwimUsdAta: userSwimUsdAtaAddr, + swimUsdMint: swimUsdMint, + custody, + tokenBridge, + custodySigner, + authoritySigner, + wormholeConfig, + wormholeMessage: wormholeMessage.publicKey, + wormholeEmitter, + wormholeSequence, + wormholeFeeCollector, + clock: web3.SYSVAR_CLOCK_PUBKEY, + // autoderived + // sender + rent: web3.SYSVAR_RENT_PUBKEY, + // autoderived + // systemProgram, + wormhole, + tokenProgram: splToken.programId, + }) + .preInstructions([setComputeUnitLimitIx]) + .postInstructions([createMemoInstruction(memo.toString("hex"))]) + .signers([wormholeMessage]) + .rpc(); + }).rejects.toThrow("Target Chain is paused"); + + wormholeMessage = web3.Keypair.generate(); + const gasKickstart = false; + const maxFee = new BN(100_000); + + await expect(() => { + return propellerProgram.methods + .propellerTransferNativeWithPayload( + nonce, + transferAmount, + targetChain, + evmOwner, + gasKickstart, + maxFee, + evmTargetTokenId, + null, + ) + .accounts({ + propeller, + payer: payer.publicKey, + tokenBridgeConfig, + userSwimUsdAta: userSwimUsdAtaAddr, + swimUsdMint: swimUsdMint, + custody, + tokenBridge, + custodySigner, + authoritySigner, + wormholeConfig, + wormholeMessage: wormholeMessage.publicKey, + wormholeEmitter, + wormholeSequence, + wormholeFeeCollector, + clock: web3.SYSVAR_CLOCK_PUBKEY, + // autoderived + // sender + rent: web3.SYSVAR_RENT_PUBKEY, + // autoderived + // systemProgram, + wormhole, + tokenProgram: splToken.programId, + }) + .preInstructions([setComputeUnitLimitIx]) + .signers([wormholeMessage]) + .rpc(); + }).rejects.toThrow("Target Chain is paused"); + + isPaused = false; + await propellerProgram.methods + .targetChainMapSetPaused(targetChain, isPaused) + .accounts({ + propeller, + pauseKey: propellerPauseKey.publicKey, + payer: payer.publicKey, + targetChainMap: targetChainMapAddr, + }) + .signers([propellerPauseKey]) + .rpc(); + + const targetChainMapDataAfter = + await propellerProgram.account.targetChainMap.fetch( + targetChainMapAddr, + ); + expect(targetChainMapDataAfter.isPaused).toEqual(isPaused); + + await propellerProgram.methods .propellerTransferNativeWithPayload( nonce, transferAmount, - CHAIN_ID_ETH, + targetChain, evmOwner, gasKickstart, maxFee, @@ -1983,10 +2188,10 @@ describe("propeller", () => { wormhole, tokenProgram: splToken.programId, }) - .signers([wormholeMessage]) .preInstructions([setComputeUnitLimitIx]) + .signers([wormholeMessage]) .rpc(); - }).rejects.toThrow("Insufficient Amount being transferred"); + }); }); describe("User submitted CompleteWithPayload and ProcessSwimPayload", () => { @@ -3109,7 +3314,7 @@ describe("propeller", () => { // swimUsdKeypair.publicKey.toBuffer(), // CHAIN_ID_SOLANA, // propellerProgram.programId, - // ethRoutingContract, + // evmRoutingContractBuffer, // encodeSwimPayload(swimPayload), // ), // ); @@ -3497,7 +3702,7 @@ describe("propeller", () => { // swimUsdKeypair.publicKey.toBuffer(), // CHAIN_ID_SOLANA, // propellerProgram.programId, - // ethRoutingContract, + // evmRoutingContractBuffer, // encodeSwimPayload(swimPayload), // ), // ); @@ -3941,20 +4146,15 @@ describe("propeller", () => { userTransferAuthority.publicKey, payer, ); + const seedNewMetapoolAccts = await getAddOrRemoveAccounts( + newMetapool, + dummyUser.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const seedNewMetapoolTxn = await twoPoolProgram.methods .add(inputAmounts, minimumMintAmount) - .accounts({ - // propeller: propeller, - poolTokenAccount0: newMetapoolToken0Ata, - poolTokenAccount1: newMetapoolToken1Ata, - lpMint: newMetapoolLpMintKeypair.publicKey, - governanceFee: newMetapoolGovernanceFeeAta, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userMetapoolTokenAccount0, - userTokenAccount1: userMetapoolTokenAccount1, - userLpTokenAccount: userNewMetapoolLpTokenAta, - tokenProgram: splToken.programId, - }) + .accounts(seedNewMetapoolAccts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -4065,7 +4265,7 @@ describe("propeller", () => { // swimUsdKeypair.publicKey.toBuffer(), // CHAIN_ID_SOLANA, // propellerProgram.programId, - // ethRoutingContract, + // evmRoutingContractBuffer, // encodeSwimPayload(swimPayload), // ), // ); @@ -4390,6 +4590,8 @@ describe("propeller", () => { }); // end of close/recreate token number map test }); + describe("Updating fees & oracles", () => {}); + async function checkTxnLogsForMemo( txSig: string, memoBuffer: Buffer, @@ -4420,7 +4622,6 @@ describe("propeller", () => { } function createMemoId() { - const SWIM_MEMO_LENGTH = 16; // NOTE: Please always use random bytes to avoid conflicts with other users return crypto.randomBytes(SWIM_MEMO_LENGTH); // return (++memoId).toString().padStart(16, "0"); diff --git a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts index f5b648323..bd703d084 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propellerUtils.ts @@ -9,6 +9,7 @@ import { tryNativeToHexString, tryUint8ArrayToNative, } from "@certusone/wormhole-sdk"; +import { uint8ArrayToHex } from "@certusone/wormhole-sdk/lib/cjs/utils/array"; import type { AnchorProvider, Program, SplToken } from "@project-serum/anchor"; import { BN, web3 } from "@project-serum/anchor"; import { MEMO_PROGRAM_ID, createMemoInstruction } from "@solana/spl-memo"; @@ -333,16 +334,16 @@ export const formatSwimPayload = ( ...swimPayload, owner: tryUint8ArrayToNative(swimPayload.owner, chain), }; - const formattedMemo = swimPayload.memo - ? { memo: swimPayload.memo.toString() } - : {}; const formattedMaxFee = swimPayload.maxFee ? { maxFee: swimPayload.maxFee.toString() } : {}; + const formattedMemo = swimPayload.memo + ? { memo: uint8ArrayToHex(swimPayload.memo) } + : {}; return { ...formattedBaseSwimPayload, - ...formattedMemo, ...formattedMaxFee, + ...formattedMemo, }; }; @@ -396,7 +397,7 @@ export const getToTokenNumberMapAddr = async ( ); }; -export const getTargetChainIdMapAddr = async ( +export const getTargetChainMapAddr = async ( propeller: web3.PublicKey, targetChain: number, propellerProgramId: web3.PublicKey, @@ -579,6 +580,12 @@ export const generatePropellerEngineTxns = async ( console.info(` completePubkeys: ${JSON.stringify(completePubkeys, null, 2)} `); + const feeTrackingAccts = await getFeeTrackingAccounts( + propeller, + payer.publicKey, + propellerProgram, + twoPoolProgram, + ); const completeNativeWithPayloadIxs = propellerProgram.methods .propellerCompleteNativeWithPayload() @@ -586,19 +593,21 @@ export const generatePropellerEngineTxns = async ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore completeNativeWithPayload: completePubkeys, - feeTracker: propellerEngineFeeTracker, - aggregator, + feeTracking: feeTrackingAccts, + // aggregator, + // feeTracker: propellerEngineFeeTracker, // marginalPricePool: { // pool: marginalPricePoolInfo.pool, // poolToken0Account: marginalPricePoolInfo.token0Account, // poolToken1Account: marginalPricePoolInfo.token1Account, // lpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, // }, - marginalPricePool: marginalPricePoolInfo.pool, - marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, - marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, - marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, - twoPoolProgram: twoPoolProgram.programId, + // marginalPricePool: marginalPricePoolInfo.pool, + // marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, + // marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, + // marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -657,8 +666,7 @@ export const generatePropellerEngineTxns = async ( payer: payer.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, tokenIdMap: tokenNumberMapAddr, @@ -669,12 +677,15 @@ export const generatePropellerEngineTxns = async ( systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePoolInfo.pool, - marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, - marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, - marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: marginalPricePoolInfo.pool, + // marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, + // marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, + // marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, rent: web3.SYSVAR_RENT_PUBKEY, }) .transaction(); @@ -697,15 +708,16 @@ export const generatePropellerEngineTxns = async ( userSwimUsdAta: userSwimUsdAta, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - twoPoolProgram: twoPoolProgram.programId, systemProgram: web3.SystemProgram.programId, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePoolInfo.pool, - marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, - marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, - marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + feeTracking: feeTrackingAccts, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // aggregator, + // marginalPricePool: marginalPricePoolInfo.pool, + // marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, + // marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, + // marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, owner, }) .preInstructions([setComputeUnitLimitIx]) @@ -714,22 +726,16 @@ export const generatePropellerEngineTxns = async ( txns = [...txns, propellerProcessSwimPayloadFallbackTxn]; } else { const tokenIdMapPoolAddr = tokenNumberMapData.pool; - const tokenIdMapPoolData = await twoPoolProgram.account.twoPool.fetch( + const tokenNumberMapPoolData = await twoPoolProgram.account.twoPool.fetch( tokenIdMapPoolAddr, ); - const tokenIdMapPoolInfo = { + const tokenNumberMapPoolInfo = { pool: tokenIdMapPoolAddr, - tokenMints: tokenIdMapPoolData.tokenMintKeys, - tokenAccounts: tokenIdMapPoolData.tokenKeys, - lpMint: tokenIdMapPoolData.lpMintKey, - governanceFeeAcct: tokenIdMapPoolData.governanceFeeKey, + tokenMints: tokenNumberMapPoolData.tokenMintKeys, + tokenAccounts: tokenNumberMapPoolData.tokenKeys, + lpMint: tokenNumberMapPoolData.lpMintKey, + governanceFeeAcct: tokenNumberMapPoolData.governanceFeeKey, }; - // const mints = [...tokenIdMapPoolInfo.tokenMints, tokenIdMapPoolInfo.lpMint]; - // const ownerAtaAddrs = await Promise.all( - // mints.map(async (mint) => { - // return await getAssociatedTokenAddress(mint, owner); - // }), - // ); const ownerAtaAddrs = await getOwnerAtaAddrsForPool( tokenIdMapPoolAddr, owner, @@ -757,15 +763,14 @@ export const generatePropellerEngineTxns = async ( payer: payer.publicKey, redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, + claim: wormholeClaim, swimPayloadMessage, tokenNumberMap: tokenNumberMapAddr, - pool: tokenIdMapPoolInfo.pool, - poolToken0Mint: tokenIdMapPoolInfo.tokenMints[0], - poolToken1Mint: tokenIdMapPoolInfo.tokenMints[1], - poolLpMint: tokenIdMapPoolInfo.lpMint, + pool: tokenNumberMapPoolInfo.pool, + poolToken0Mint: tokenNumberMapPoolInfo.tokenMints[0], + poolToken1Mint: tokenNumberMapPoolInfo.tokenMints[1], + poolLpMint: tokenNumberMapPoolInfo.lpMint, user: owner, userPoolToken0Account: ownerAtaAddrs[0], userPoolToken1Account: ownerAtaAddrs[1], @@ -774,12 +779,22 @@ export const generatePropellerEngineTxns = async ( systemProgram: web3.SystemProgram.programId, tokenProgram: splToken.programId, memo: MEMO_PROGRAM_ID, - aggregator, - marginalPricePool: marginalPricePoolInfo.pool, - marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, - marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, - marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // aggregator, + // feeVault: propellerFeeVault, + // feeTracker: propellerEngineFeeTracker, + // marginalPricePool: { + // pool: marginalPricePoolInfo.pool, + // poolToken0Account: marginalPricePoolInfo.token0Account, + // poolToken1Account: marginalPricePoolInfo.token1Account, + // lpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePoolInfo.pool, + // marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, + // marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, + // marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + // twoPoolProgram: twoPoolProgram.programId, }) .preInstructions([setComputeUnitLimitIx]) .transaction(); @@ -797,11 +812,11 @@ export const generatePropellerEngineTxns = async ( redeemer: propellerRedeemer, redeemerEscrow: propellerRedeemerEscrowAccount, // tokenIdMap: ? - pool: tokenIdMapPoolInfo.pool, - poolTokenAccount0: tokenIdMapPoolInfo.tokenAccounts[0], - poolTokenAccount1: tokenIdMapPoolInfo.tokenAccounts[1], - lpMint: tokenIdMapPoolInfo.lpMint, - governanceFee: tokenIdMapPoolInfo.governanceFeeAcct, + pool: tokenNumberMapPoolInfo.pool, + poolTokenAccount0: tokenNumberMapPoolInfo.tokenAccounts[0], + poolTokenAccount1: tokenNumberMapPoolInfo.tokenAccounts[1], + lpMint: tokenNumberMapPoolInfo.lpMint, + governanceFee: tokenNumberMapPoolInfo.governanceFeeAcct, userTokenAccount0: ownerAtaAddrs[0], userTokenAccount1: ownerAtaAddrs[1], userLpTokenAccount: ownerAtaAddrs[2], @@ -810,19 +825,14 @@ export const generatePropellerEngineTxns = async ( systemProgram: web3.SystemProgram.programId, }) .pubkeys(); + const propellerProcessSwimPayloadTxn = await propellerProgram.methods .propellerProcessSwimPayload(toTokenNumber) .accounts({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore processSwimPayload: processSwimPayloadPubkeys, - feeVault: propellerFeeVault, - feeTracker: propellerEngineFeeTracker, - aggregator, - marginalPricePool: marginalPricePoolInfo.pool, - marginalPricePoolToken0Account: marginalPricePoolInfo.token0Account, - marginalPricePoolToken1Account: marginalPricePoolInfo.token1Account, - marginalPricePoolLpMint: marginalPricePoolInfo.lpMint, + feeTracking: feeTrackingAccts, owner, memo: MEMO_PROGRAM_ID, }) @@ -1211,33 +1221,35 @@ export const getPropellerCompleteNativeWithPayloadTxn = async ( // } const completeNativeWithPayloadPubkeys = await completeNativeWithPayload.pubkeys(); - const [feeTracker] = await getFeeTrackerPda( - swimUsdMint, + + + const feeTrackingAccts = await getFeeTrackingAccounts( + propeller, propellerProgram.provider.publicKey!, - propellerProgram.programId, - ); - const aggregator = propellerData.aggregator; - const marginalPricePool = propellerData.marginalPricePool; - const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( - marginalPricePool, + propellerProgram, + twoPoolProgram, ); - const marginalPricePoolToken0Account = marginalPricePoolData.tokenKeys[0]; - const marginalPricePoolToken1Account = marginalPricePoolData.tokenKeys[1]; - const marginalPricePoolLpMint = marginalPricePoolData.lpMintKey; - return propellerProgram.methods .propellerCompleteNativeWithPayload() .accounts({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore completeNativeWithPayload: completeNativeWithPayloadPubkeys, - feeTracker: feeTracker, - aggregator, - marginalPricePool: marginalPricePool, - marginalPricePoolToken0Account: marginalPricePoolToken0Account, - marginalPricePoolToken1Account: marginalPricePoolToken1Account, - marginalPricePoolLpMint: marginalPricePoolLpMint, - twoPoolProgram: twoPoolProgram.programId, + feeTracking: feeTrackingAccts, + // feeTracker: feeTracker, + // aggregator, + // marginalPricePool: { + // pool: marginalPricePool, + // poolToken0Account: marginalPricePoolToken0Account, + // poolToken1Account: marginalPricePoolToken1Account, + // lpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, + // }, + // marginalPricePool: marginalPricePool, + // marginalPricePoolToken0Account: marginalPricePoolToken0Account, + // marginalPricePoolToken1Account: marginalPricePoolToken1Account, + // marginalPricePoolLpMint: marginalPricePoolLpMint, + // twoPoolProgram: twoPoolProgram.programId, memo: MEMO_PROGRAM_ID, }) .preInstructions([setComputeUnitLimitIx]) @@ -1336,6 +1348,60 @@ export const getWormholeAddressesForMint = async ( }; }; +export interface FeeTrackingAccounts { + readonly feeVault: web3.PublicKey; + readonly feeTracker: web3.PublicKey; + readonly aggregator: web3.PublicKey; + readonly marginalPricePool: MarginalPricePoolAccounts; +} + +export interface MarginalPricePoolAccounts { + readonly pool: web3.PublicKey; + readonly poolToken0Account: web3.PublicKey; + readonly poolToken1Account: web3.PublicKey; + readonly lpMint: web3.PublicKey; + readonly twoPoolProgram: web3.PublicKey; +} + +//Note: should be able to just use the propellerProgram.provider as payer +// but just being explicit here for safety. +export const getFeeTrackingAccounts = async ( + propeller: web3.PublicKey, + payer: web3.PublicKey, + propellerProgram: Program, + twoPoolProgram: Program, +): Promise => { + const propellerData = await propellerProgram.account.propeller.fetch( + propeller, + ); + const feeVault = propellerData.feeVault; + const swimUsdMint = propellerData.swimUsdMint; + const [feeTracker] = await getFeeTrackerPda( + swimUsdMint, + payer, + propellerProgram.programId, + ); + const aggregator = propellerData.aggregator; + const marginalPricePool = propellerData.marginalPricePool; + const marginalPricePoolData = await twoPoolProgram.account.twoPool.fetch( + marginalPricePool, + ); + return { + feeVault, + feeTracker, + aggregator, + marginalPricePool: { + pool: marginalPricePool, + poolToken0Account: marginalPricePoolData.tokenKeys[0], + poolToken1Account: marginalPricePoolData.tokenKeys[1], + lpMint: marginalPricePoolData.lpMintKey, + twoPoolProgram: twoPoolProgram.programId, + }, + }; +}; + + + export const postVaaToSolana = async ( tokenTransferWithPayloadSignedVaa: Buffer, provider: AnchorProvider, diff --git a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts index 0b6682968..5ffb18f44 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts @@ -35,6 +35,8 @@ import { parsePoolAccount } from "../../poolDecoder"; import { TWO_POOL_PID } from "../consts"; import { + getAddOrRemoveAccounts, + getSwapAccounts, setupPoolPrereqs, setupUserAssociatedTokenAccts, } from "./poolTestUtils"; @@ -184,7 +186,7 @@ describe("TwoPool", () => { }); describe("Defi Instructions", () => { - it("Can add to pool", async () => { + it.skip("Can add to pool", async () => { const previousDepthBefore = ( await twoPoolProgram.account.twoPool.fetch(flagshipPool) ).previousDepth; @@ -242,6 +244,62 @@ describe("TwoPool", () => { `); expect(previousDepthAfter.gt(previousDepthBefore)).toBeTruthy(); }); + it("Can add_new to pool", async () => { + const previousDepthBefore = ( + await twoPoolProgram.account.twoPool.fetch(flagshipPool) + ).previousDepth; + + const inputAmounts = [new BN(100_000_000), new BN(100_000_000)]; + const minimumMintAmount = new BN(0); + // const addParams = { + // inputAmounts, + // minimumMintAmount, + // }; + const userTransferAuthority = Keypair.generate(); + const [approveIxs, revokeIxs] = await getApproveAndRevokeIxs( + splToken, + [userUsdcAtaAddr, userUsdtAtaAddr], + inputAmounts, + userTransferAuthority.publicKey, + payer, + ); + + + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); + const tx = await twoPoolProgram.methods + // .add(addParams) + .add(inputAmounts, minimumMintAmount) + .accounts(addOrRemoveAccounts) + .preInstructions([...approveIxs]) + .postInstructions([...revokeIxs]) + .signers([userTransferAuthority]) + .rpc(); + + console.info("Your transaction signature", tx); + + const userLpTokenAccountBalance = ( + await splToken.account.token.fetch(userSwimUsdAtaAddr) + ).amount; + console.info( + `userLpTokenAccountBalance: ${userLpTokenAccountBalance.toString()}`, + ); + + expect(userLpTokenAccountBalance.gt(new BN(0))).toBeTruthy(); + const previousDepthAfter = ( + await twoPoolProgram.account.twoPool.fetch(flagshipPool) + ).previousDepth; + console.info(` + previousDepth + Before: ${previousDepthBefore.toString()} + After: ${previousDepthAfter.toString()} + `); + expect(previousDepthAfter.gt(previousDepthBefore)).toBeTruthy(); + }); it("Can swap exact input to pool", async () => { const previousDepthBefore = ( diff --git a/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts b/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts index ca99bc93f..c6a131695 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/poolTestUtils.ts @@ -1,6 +1,7 @@ import type { BN, Program, Program, SplToken } from "@project-serum/anchor"; import { web3 } from "@project-serum/anchor"; import { + TOKEN_PROGRAM_ID, getAssociatedTokenAddress, getOrCreateAssociatedTokenAccount, } from "@solana/spl-token"; @@ -473,3 +474,50 @@ export const getUserAtaBalancesForPool = async ( ); return userTokenAccounts.map((ata) => ata.amount); }; + +export const getSwapAccounts = async ( + pool: web3.PublicKey, + user: web3.PublicKey, + userTransferAuthority: web3.PublicKey, + twoPoolProgram: Program, +) => { + const poolData = await twoPoolProgram.account.twoPool.fetch(pool); + const [userTokenAccount0, userTokenAccount1] = await getOwnerAtaAddrsForPool( + pool, + user, + twoPoolProgram, + ); + return { + pool, + poolTokenAccount0: poolData.tokenKeys[0], + poolTokenAccount1: poolData.tokenKeys[1], + lpMint: poolData.lpMintKey, + governanceFee: poolData.governanceFeeKey, + userTransferAuthority, + userTokenAccount0, + userTokenAccount1, + tokenProgram: TOKEN_PROGRAM_ID, + }; +}; + +export const getAddOrRemoveAccounts = async ( + pool: web3.PublicKey, + user: web3.PublicKey, + userTransferAuthority: web3.PublicKey, + twoPoolProgram: Program, +) => { + const swapAccounts = await getSwapAccounts( + pool, + user, + userTransferAuthority, + twoPoolProgram, + ); + const userLpTokenAccount = await getAssociatedTokenAddress( + swapAccounts.lpMint, + user, + ); + return { + swap: { ...swapAccounts }, + userLpTokenAccount, + }; +}; diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index fdb6483d2..306491717 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -245,14 +245,19 @@ "isSigner": true } ], - "args": [] + "args": [ + { + "name": "newPauseKey", + "type": "publicKey" + } + ] }, { "name": "prepareGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -274,16 +279,26 @@ "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], - "args": [] + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] }, { "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -305,6 +320,11 @@ "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -742,16 +762,19 @@ "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "routingContract", "type": { @@ -814,16 +837,19 @@ "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "isPaused", "type": "bool" @@ -979,7 +1005,10 @@ "args": [] }, { - "name": "crossChainAdd", + "name": "crossChainInitToSwimUsd", + "docs": [ + "Sending" + ], "accounts": [ { "name": "propeller", @@ -995,8 +1024,8 @@ { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -1076,7 +1105,10 @@ { "name": "userLpTokenAccount", "isMut": true, - "isSigner": false + "isSigner": false, + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { "name": "tokenProgram", @@ -1107,7 +1139,7 @@ "returns": "u64" }, { - "name": "propellerAdd", + "name": "propellerInitToSwimUsd", "accounts": [ { "name": "propeller", @@ -1123,8 +1155,8 @@ { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -1204,7 +1236,10 @@ { "name": "userLpTokenAccount", "isMut": true, - "isSigner": false + "isSigner": false, + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { "name": "tokenProgram", @@ -1235,11 +1270,11 @@ "returns": "u64" }, { - "name": "crossChainSwapExactInput", + "name": "crossChainTransferNativeWithPayload", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -1251,14 +1286,19 @@ { "kind": "account", "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" + "account": "Mint", + "path": "swim_usd_mint" } ] } }, { - "name": "pool", + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenBridgeConfig", "isMut": true, "isSigner": false, "pda": { @@ -1266,122 +1306,122 @@ { "kind": "const", "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "value": "config" } ], "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "Propeller", + "path": "propeller" } } }, { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", + "name": "userSwimUsdAta", "isMut": true, "isSigner": false }, { - "name": "lpMint", + "name": "swimUsdMint", "isMut": true, "isSigner": false }, { - "name": "governanceFee", + "name": "custody", "isMut": true, "isSigner": false }, { - "name": "userTransferAuthority", + "name": "tokenBridge", "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, "isSigner": false }, { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", + "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "twoPoolProgram", + "name": "authoritySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "authority_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "exactInputAmount", - "type": "u64" + "name": "wormholeConfig", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "Bridge" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } + } }, { - "name": "minimumOutputAmount", - "type": "u64" - } - ], - "returns": "u64" - }, - { - "name": "propellerSwapExactInput", - "accounts": [ + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, { - "name": "propeller", - "isMut": false, + "name": "wormholeEmitter", + "isMut": true, "isSigner": false, "pda": { "seeds": [ { "kind": "const", "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" + "value": "emitter" } - ] + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } } }, { - "name": "pool", + "name": "wormholeSequence", "isMut": true, "isSigner": false, "pda": { @@ -1389,292 +1429,41 @@ { "kind": "const", "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" + "value": "Sequence" }, { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "path": "wormhole_emitter" } ], "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "Propeller", + "path": "propeller" } } }, { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", + "name": "wormholeFeeCollector", "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "exactInputAmount", - "type": "u64" - }, - { - "name": "maxFee", - "type": "u64" - } - ], - "returns": "u64" - }, - { - "name": "crossChainTransferNativeWithPayload", - "accounts": [ - { - "name": "propeller", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "swim_usd_mint" - } - ] - } - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "tokenBridgeConfig", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "config" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "userSwimUsdAta", - "isMut": true, - "isSigner": false - }, - { - "name": "swimUsdMint", - "isMut": true, - "isSigner": false - }, - { - "name": "custody", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenBridge", - "isMut": false, - "isSigner": false - }, - { - "name": "custodySigner", - "isMut": false, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "custody_signer" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "token_bridge" - } - } - }, - { - "name": "authoritySigner", - "isMut": false, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "authority_signer" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "token_bridge" - } - } - }, - { - "name": "wormholeConfig", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "Bridge" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true - }, - { - "name": "wormholeEmitter", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "emitter" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeSequence", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "Sequence" - }, - { - "kind": "account", - "type": "publicKey", - "path": "wormhole_emitter" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeFeeCollector", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "fee_collector" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "fee_collector" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } + } }, { "name": "sender", @@ -2133,6 +1922,9 @@ }, { "name": "completeNativeWithPayload", + "docs": [ + "Receiving" + ], "accounts": [ { "name": "propeller", @@ -2835,101 +2627,90 @@ ] }, { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": { - "defined": "Box>" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.swim_usd_mint" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.payer" - } - ] - } - }, - { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -2996,41 +2777,6 @@ "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -3157,7 +2903,8 @@ "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "FeeTracking", + "path": "fee_tracking" } } }, @@ -3212,66 +2959,90 @@ "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -3553,109 +3324,90 @@ ] }, { - "name": "aggregator", - "isMut": false, - "isSigner": false, - "docs": [ - "Assuming that USD:USDC 1:1" - ] - }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false, - "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "ProcessSwimPayload", - "path": "process_swim_payload" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": { - "defined": "Program<'info,two_pool::program::TwoPool>" - }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.two_pool_program" + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false + ] }, { "name": "owner", @@ -3739,41 +3491,6 @@ "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -3906,66 +3623,90 @@ "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -4174,11 +3915,6 @@ "isMut": false, "isSigner": false }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - }, { "name": "memo", "isMut": false, @@ -4190,100 +3926,90 @@ "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false, - "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false + ] }, { "name": "owner", @@ -4473,6 +4199,9 @@ }, { "name": "aggregator", + "docs": [ + "switchboard *" + ], "type": "publicKey" }, { @@ -4949,6 +4678,20 @@ ] } }, + { + "name": "ToSwimUsdStep", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Add" + }, + { + "name": "SwapExactInput" + } + ] + } + }, { "name": "ConsistencyLevel", "type": { @@ -5054,238 +4797,273 @@ }, { "code": 6011, + "name": "InvalidPoolForInitToSwimUsd", + "msg": "Invalid Pool for Init To SwimUSD" + }, + { + "code": 6012, "name": "InvalidCpiReturnProgramId", "msg": "Incorrect ProgramId for CPI return value" }, { - "code": 6012, + "code": 6013, "name": "InvalidCpiReturnValue", "msg": "Invalid CPI Return value" }, { - "code": 6013, + "code": 6014, "name": "InvalidMint", "msg": "Invalid Mint" }, { - "code": 6014, + "code": 6015, "name": "InvalidAddAndWormholeTransferMint", "msg": "Invalid Mint for AddAndWormholeTransfer" }, { - "code": 6015, + "code": 6016, "name": "InvalidSwapExactInputOutputTokenIndex", "msg": "Invalid output token index for SwapExactInput params" }, { - "code": 6016, + "code": 6017, "name": "InvalidSwapExactInputInputAmount", "msg": "Invalid input amount for SwapExactInput params" }, { - "code": 6017, + "code": 6018, "name": "InvalidSwimUsdMint", "msg": "Invalid SwimUSD Mint" }, { - "code": 6018, + "code": 6019, "name": "InvalidPayloadTypeInVaa", "msg": "Invalid Payload Type in VAA" }, { - "code": 6019, + "code": 6020, "name": "SerializeError", "msg": "Serializing error" }, { - "code": 6020, + "code": 6021, "name": "DeserializeError", "msg": "Deserializing error" }, { - "code": 6021, + "code": 6022, "name": "UserRedeemerSignatureNotDetected", "msg": "User redeemer needs to be signer" }, { - "code": 6022, + "code": 6023, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6023, + "code": 6024, "name": "StaleFeed", "msg": "Switchboard feed value is stale " }, { - "code": 6024, + "code": 6025, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6025, + "code": 6026, "name": "InsufficientAmount", "msg": "Insufficient Amount being transferred" }, { - "code": 6026, + "code": 6027, "name": "InvalidWormholeClaimAccount", "msg": "Invalid Wormhole Claim Account" }, { - "code": 6027, + "code": 6028, "name": "InvalidClaimData", "msg": "Invalid claim data" }, { - "code": 6028, + "code": 6029, "name": "ClaimNotClaimed", "msg": "Claim Account not claimed" }, { - "code": 6029, + "code": 6030, "name": "InvalidPropellerGovernanceKey", "msg": "Invalid Propeller GovernanceKey" }, { - "code": 6030, + "code": 6031, "name": "InvalidPropellerPauseKey", "msg": "Invalid Propeller Pause Key" }, { - "code": 6031, + "code": 6032, "name": "InvalidTokenNumberMapPool", "msg": "Invalid Pool for Token Number Map" }, { - "code": 6032, + "code": 6033, "name": "InvalidOutputTokenIndex", "msg": "Invalid Output Token Index" }, { - "code": 6033, + "code": 6034, "name": "InvalidTokenNumberMapPoolTokenIndex", "msg": "Invalid Pool Token Index for Token Number Map" }, { - "code": 6034, + "code": 6035, "name": "InvalidTokenNumberMapPoolTokenMint", "msg": "Invalid Pool Token Mint for Token Number Map" }, { - "code": 6035, + "code": 6036, "name": "InvalidTokenNumberMapToTokenStep", "msg": "Invalid To Token Step for Token Number Map" }, { - "code": 6036, + "code": 6037, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6038, + "code": 6039, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6039, + "code": 6040, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6040, + "code": 6041, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6041, + "code": 6042, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6042, + "code": 6043, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6043, + "code": 6044, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6044, + "code": 6045, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6045, + "code": 6046, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6046, + "code": 6047, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6047, + "code": 6048, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6048, + "code": 6049, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6049, + "code": 6050, "name": "TokenNumberMapExists", "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6050, + "code": 6051, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6051, + "code": 6052, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6052, + "code": 6053, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" }, { - "code": 6053, + "code": 6054, "name": "InvalidMemo", "msg": "Invalid Memo" }, { - "code": 6054, + "code": 6055, "name": "ToTokenNumberMismatch", "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" }, { - "code": 6055, + "code": 6056, "name": "IsPaused", "msg": "Routing Contract is paused" }, { - "code": 6056, + "code": 6057, "name": "TargetChainIsPaused", "msg": "Target Chain is paused" }, { - "code": 6057, + "code": 6058, + "name": "InvalidTargetChainMap", + "msg": "Invalid Target Chain Map" + }, + { + "code": 6059, "name": "InvalidSwimPayloadMessagePayer", "msg": "Invalid SwimPayloadMessagePayer" + }, + { + "code": 6060, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key for UpdatePauseKey" + }, + { + "code": 6061, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key for Prepare Governance Transition" + }, + { + "code": 6062, + "name": "InvalidEnact", + "msg": "Invalid Enact Governance Transition" + }, + { + "code": 6063, + "name": "InsufficientDelay", + "msg": "Insufficient Delay for Enact Governance Transition" + }, + { + "code": 6064, + "name": "InvalidFeeTracker", + "msg": "Invalid Fee Tracker" } ] } \ No newline at end of file diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 68c57e6f7..7a3efdd12 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -245,14 +245,19 @@ export type Propeller = { "isSigner": true } ], - "args": [] + "args": [ + { + "name": "newPauseKey", + "type": "publicKey" + } + ] }, { "name": "prepareGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -274,16 +279,26 @@ export type Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], - "args": [] + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] }, { "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -305,6 +320,11 @@ export type Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -742,16 +762,19 @@ export type Propeller = { "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "routingContract", "type": { @@ -814,16 +837,19 @@ export type Propeller = { "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "isPaused", "type": "bool" @@ -979,7 +1005,10 @@ export type Propeller = { "args": [] }, { - "name": "crossChainAdd", + "name": "crossChainInitToSwimUsd", + "docs": [ + "Sending" + ], "accounts": [ { "name": "propeller", @@ -995,8 +1024,8 @@ export type Propeller = { { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -1076,7 +1105,10 @@ export type Propeller = { { "name": "userLpTokenAccount", "isMut": true, - "isSigner": false + "isSigner": false, + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { "name": "tokenProgram", @@ -1107,7 +1139,7 @@ export type Propeller = { "returns": "u64" }, { - "name": "propellerAdd", + "name": "propellerInitToSwimUsd", "accounts": [ { "name": "propeller", @@ -1123,8 +1155,8 @@ export type Propeller = { { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -1204,7 +1236,10 @@ export type Propeller = { { "name": "userLpTokenAccount", "isMut": true, - "isSigner": false + "isSigner": false, + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { "name": "tokenProgram", @@ -1235,11 +1270,11 @@ export type Propeller = { "returns": "u64" }, { - "name": "crossChainSwapExactInput", + "name": "crossChainTransferNativeWithPayload", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -1251,14 +1286,19 @@ export type Propeller = { { "kind": "account", "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" + "account": "Mint", + "path": "swim_usd_mint" } ] } }, { - "name": "pool", + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "tokenBridgeConfig", "isMut": true, "isSigner": false, "pda": { @@ -1266,122 +1306,122 @@ export type Propeller = { { "kind": "const", "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "value": "config" } ], "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "Propeller", + "path": "propeller" } } }, { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", + "name": "userSwimUsdAta", "isMut": true, "isSigner": false }, { - "name": "lpMint", + "name": "swimUsdMint", "isMut": true, "isSigner": false }, { - "name": "governanceFee", + "name": "custody", "isMut": true, "isSigner": false }, { - "name": "userTransferAuthority", + "name": "tokenBridge", "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, "isSigner": false }, { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", + "name": "custodySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "custody_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "twoPoolProgram", + "name": "authoritySigner", "isMut": false, - "isSigner": false + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "authority_signer" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "token_bridge" + } + } }, { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "exactInputAmount", - "type": "u64" + "name": "wormholeConfig", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "Bridge" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } + } }, { - "name": "minimumOutputAmount", - "type": "u64" - } - ], - "returns": "u64" - }, - { - "name": "propellerSwapExactInput", - "accounts": [ + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, { - "name": "propeller", - "isMut": false, + "name": "wormholeEmitter", + "isMut": true, "isSigner": false, "pda": { "seeds": [ { "kind": "const", "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" + "value": "emitter" } - ] + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } } }, { - "name": "pool", + "name": "wormholeSequence", "isMut": true, "isSigner": false, "pda": { @@ -1389,292 +1429,41 @@ export type Propeller = { { "kind": "const", "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" + "value": "Sequence" }, { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "path": "wormhole_emitter" } ], "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "Propeller", + "path": "propeller" } } }, { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", + "name": "wormholeFeeCollector", "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "swimUsdMint", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "exactInputAmount", - "type": "u64" - }, - { - "name": "maxFee", - "type": "u64" - } - ], - "returns": "u64" - }, - { - "name": "crossChainTransferNativeWithPayload", - "accounts": [ - { - "name": "propeller", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "swim_usd_mint" - } - ] - } - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "tokenBridgeConfig", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "config" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "userSwimUsdAta", - "isMut": true, - "isSigner": false - }, - { - "name": "swimUsdMint", - "isMut": true, - "isSigner": false - }, - { - "name": "custody", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenBridge", - "isMut": false, - "isSigner": false - }, - { - "name": "custodySigner", - "isMut": false, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "custody_signer" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "token_bridge" - } - } - }, - { - "name": "authoritySigner", - "isMut": false, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "authority_signer" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "token_bridge" - } - } - }, - { - "name": "wormholeConfig", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "Bridge" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true - }, - { - "name": "wormholeEmitter", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "emitter" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeSequence", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "Sequence" - }, - { - "kind": "account", - "type": "publicKey", - "path": "wormhole_emitter" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } - }, - { - "name": "wormholeFeeCollector", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "fee_collector" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller" - } - } + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "fee_collector" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller" + } + } }, { "name": "sender", @@ -2133,6 +1922,9 @@ export type Propeller = { }, { "name": "completeNativeWithPayload", + "docs": [ + "Receiving" + ], "accounts": [ { "name": "propeller", @@ -2835,101 +2627,90 @@ export type Propeller = { ] }, { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": { - "defined": "Box>" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.swim_usd_mint" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.payer" - } - ] - } - }, - { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -2996,41 +2777,6 @@ export type Propeller = { "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -3157,7 +2903,8 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "FeeTracking", + "path": "fee_tracking" } } }, @@ -3212,66 +2959,90 @@ export type Propeller = { "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -3553,117 +3324,98 @@ export type Propeller = { ] }, { - "name": "aggregator", - "isMut": false, - "isSigner": false, - "docs": [ - "Assuming that USD:USDC 1:1" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] + } ] }, { - "name": "feeVault", + "name": "owner", "isMut": true, "isSigner": false, "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "ProcessSwimPayload", - "path": "process_swim_payload" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" - }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": { - "defined": "Program<'info,two_pool::program::TwoPool>" - }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.two_pool_program" - } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "owner", - "isMut": true, - "isSigner": false, - "docs": [ - "This is for transferring lamports for kickstart", - "TODO: force this to be system account?" + "This is for transferring lamports for kickstart", + "TODO: force this to be system account?" ] }, { @@ -3739,41 +3491,6 @@ export type Propeller = { "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -3906,66 +3623,90 @@ export type Propeller = { "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -4174,11 +3915,6 @@ export type Propeller = { "isMut": false, "isSigner": false }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - }, { "name": "memo", "isMut": false, @@ -4190,107 +3926,97 @@ export type Propeller = { "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] + } + ] }, { - "name": "feeVault", + "name": "owner", "isMut": true, "isSigner": false, "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "owner", - "isMut": true, - "isSigner": false, - "docs": [ - "This is for transferring lamports for kickstart" + "This is for transferring lamports for kickstart" ] } ], @@ -4473,6 +4199,9 @@ export type Propeller = { }, { "name": "aggregator", + "docs": [ + "switchboard *" + ], "type": "publicKey" }, { @@ -4949,6 +4678,20 @@ export type Propeller = { ] } }, + { + "name": "ToSwimUsdStep", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Add" + }, + { + "name": "SwapExactInput" + } + ] + } + }, { "name": "ConsistencyLevel", "type": { @@ -5054,238 +4797,273 @@ export type Propeller = { }, { "code": 6011, + "name": "InvalidPoolForInitToSwimUsd", + "msg": "Invalid Pool for Init To SwimUSD" + }, + { + "code": 6012, "name": "InvalidCpiReturnProgramId", "msg": "Incorrect ProgramId for CPI return value" }, { - "code": 6012, + "code": 6013, "name": "InvalidCpiReturnValue", "msg": "Invalid CPI Return value" }, { - "code": 6013, + "code": 6014, "name": "InvalidMint", "msg": "Invalid Mint" }, { - "code": 6014, + "code": 6015, "name": "InvalidAddAndWormholeTransferMint", "msg": "Invalid Mint for AddAndWormholeTransfer" }, { - "code": 6015, + "code": 6016, "name": "InvalidSwapExactInputOutputTokenIndex", "msg": "Invalid output token index for SwapExactInput params" }, { - "code": 6016, + "code": 6017, "name": "InvalidSwapExactInputInputAmount", "msg": "Invalid input amount for SwapExactInput params" }, { - "code": 6017, + "code": 6018, "name": "InvalidSwimUsdMint", "msg": "Invalid SwimUSD Mint" }, { - "code": 6018, + "code": 6019, "name": "InvalidPayloadTypeInVaa", "msg": "Invalid Payload Type in VAA" }, { - "code": 6019, + "code": 6020, "name": "SerializeError", "msg": "Serializing error" }, { - "code": 6020, + "code": 6021, "name": "DeserializeError", "msg": "Deserializing error" }, { - "code": 6021, + "code": 6022, "name": "UserRedeemerSignatureNotDetected", "msg": "User redeemer needs to be signer" }, { - "code": 6022, + "code": 6023, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6023, + "code": 6024, "name": "StaleFeed", "msg": "Switchboard feed value is stale " }, { - "code": 6024, + "code": 6025, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6025, + "code": 6026, "name": "InsufficientAmount", "msg": "Insufficient Amount being transferred" }, { - "code": 6026, + "code": 6027, "name": "InvalidWormholeClaimAccount", "msg": "Invalid Wormhole Claim Account" }, { - "code": 6027, + "code": 6028, "name": "InvalidClaimData", "msg": "Invalid claim data" }, { - "code": 6028, + "code": 6029, "name": "ClaimNotClaimed", "msg": "Claim Account not claimed" }, { - "code": 6029, + "code": 6030, "name": "InvalidPropellerGovernanceKey", "msg": "Invalid Propeller GovernanceKey" }, { - "code": 6030, + "code": 6031, "name": "InvalidPropellerPauseKey", "msg": "Invalid Propeller Pause Key" }, { - "code": 6031, + "code": 6032, "name": "InvalidTokenNumberMapPool", "msg": "Invalid Pool for Token Number Map" }, { - "code": 6032, + "code": 6033, "name": "InvalidOutputTokenIndex", "msg": "Invalid Output Token Index" }, { - "code": 6033, + "code": 6034, "name": "InvalidTokenNumberMapPoolTokenIndex", "msg": "Invalid Pool Token Index for Token Number Map" }, { - "code": 6034, + "code": 6035, "name": "InvalidTokenNumberMapPoolTokenMint", "msg": "Invalid Pool Token Mint for Token Number Map" }, { - "code": 6035, + "code": 6036, "name": "InvalidTokenNumberMapToTokenStep", "msg": "Invalid To Token Step for Token Number Map" }, { - "code": 6036, + "code": 6037, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6038, + "code": 6039, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6039, + "code": 6040, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6040, + "code": 6041, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6041, + "code": 6042, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6042, + "code": 6043, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6043, + "code": 6044, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6044, + "code": 6045, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6045, + "code": 6046, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6046, + "code": 6047, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6047, + "code": 6048, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6048, + "code": 6049, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6049, + "code": 6050, "name": "TokenNumberMapExists", "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6050, + "code": 6051, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6051, + "code": 6052, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6052, + "code": 6053, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" }, { - "code": 6053, + "code": 6054, "name": "InvalidMemo", "msg": "Invalid Memo" }, { - "code": 6054, + "code": 6055, "name": "ToTokenNumberMismatch", "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" }, { - "code": 6055, + "code": 6056, "name": "IsPaused", "msg": "Routing Contract is paused" }, { - "code": 6056, + "code": 6057, "name": "TargetChainIsPaused", "msg": "Target Chain is paused" }, { - "code": 6057, + "code": 6058, + "name": "InvalidTargetChainMap", + "msg": "Invalid Target Chain Map" + }, + { + "code": 6059, "name": "InvalidSwimPayloadMessagePayer", "msg": "Invalid SwimPayloadMessagePayer" + }, + { + "code": 6060, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key for UpdatePauseKey" + }, + { + "code": 6061, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key for Prepare Governance Transition" + }, + { + "code": 6062, + "name": "InvalidEnact", + "msg": "Invalid Enact Governance Transition" + }, + { + "code": 6063, + "name": "InsufficientDelay", + "msg": "Insufficient Delay for Enact Governance Transition" + }, + { + "code": 6064, + "name": "InvalidFeeTracker", + "msg": "Invalid Fee Tracker" } ] }; @@ -5537,14 +5315,19 @@ export const IDL: Propeller = { "isSigner": true } ], - "args": [] + "args": [ + { + "name": "newPauseKey", + "type": "publicKey" + } + ] }, { "name": "prepareGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -5566,16 +5349,26 @@ export const IDL: Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], - "args": [] + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] }, { "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -5597,6 +5390,11 @@ export const IDL: Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -6034,16 +5832,19 @@ export const IDL: Propeller = { "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "routingContract", "type": { @@ -6106,16 +5907,19 @@ export const IDL: Propeller = { "path": "propeller" }, { - "kind": "account", + "kind": "arg", "type": "u16", - "account": "TargetChainMap", - "path": "target_chain_map.target_chain" + "path": "target_chain" } ] } } ], "args": [ + { + "name": "targetChain", + "type": "u16" + }, { "name": "isPaused", "type": "bool" @@ -6271,135 +6075,10 @@ export const IDL: Propeller = { "args": [] }, { - "name": "crossChainAdd", - "accounts": [ - { - "name": "propeller", - "isMut": false, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" - } - ] - } - }, - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "userLpTokenAccount", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "inputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - }, - { - "name": "minimumMintAmount", - "type": "u64" - } + "name": "crossChainInitToSwimUsd", + "docs": [ + "Sending" ], - "returns": "u64" - }, - { - "name": "propellerAdd", "accounts": [ { "name": "propeller", @@ -6415,8 +6094,8 @@ export const IDL: Propeller = { { "kind": "account", "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -6496,161 +6175,41 @@ export const IDL: Propeller = { { "name": "userLpTokenAccount", "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "inputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - }, - { - "name": "maxFee", - "type": "u64" - } - ], - "returns": "u64" - }, - { - "name": "crossChainSwapExactInput", - "accounts": [ - { - "name": "propeller", - "isMut": false, "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - } - ] - } - }, - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { - "name": "twoPoolProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "swimUsdMint", + "name": "twoPoolProgram", "isMut": false, "isSigner": false } ], "args": [ { - "name": "exactInputAmount", - "type": "u64" + "name": "inputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } }, { - "name": "minimumOutputAmount", + "name": "minimumMintAmount", "type": "u64" } ], "returns": "u64" }, { - "name": "propellerSwapExactInput", + "name": "propellerInitToSwimUsd", "accounts": [ { "name": "propeller", @@ -6666,8 +6225,8 @@ export const IDL: Propeller = { { "kind": "account", "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" + "account": "Propeller", + "path": "propeller.swim_usd_mint" } ] } @@ -6745,25 +6304,33 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + "name": "userLpTokenAccount", + "isMut": true, + "isSigner": false, + "docs": [ + "validation will be checked in the pool CPI call anyways" + ] }, { - "name": "twoPoolProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, { - "name": "swimUsdMint", + "name": "twoPoolProgram", "isMut": false, "isSigner": false } ], "args": [ { - "name": "exactInputAmount", - "type": "u64" + "name": "inputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } }, { "name": "maxFee", @@ -7425,6 +6992,9 @@ export const IDL: Propeller = { }, { "name": "completeNativeWithPayload", + "docs": [ + "Receiving" + ], "accounts": [ { "name": "propeller", @@ -8127,101 +7697,90 @@ export const IDL: Propeller = { ] }, { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": { - "defined": "Box>" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.swim_usd_mint" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false }, - "account": "CompleteNativeWithPayload", - "path": "complete_native_with_payload.payer" - } - ] - } - }, - { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -8288,41 +7847,6 @@ export const IDL: Propeller = { "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -8449,7 +7973,8 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "path": "two_pool_program" + "account": "FeeTracking", + "path": "fee_tracking" } } }, @@ -8461,110 +7986,134 @@ export const IDL: Propeller = { { "name": "poolToken1Mint", "isMut": false, - "isSigner": false - }, - { - "name": "poolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "user", - "isMut": false, - "isSigner": false - }, - { - "name": "userPoolToken0Account", - "isMut": true, - "isSigner": false - }, - { - "name": "userPoolToken1Account", - "isMut": true, - "isSigner": false - }, - { - "name": "userLpTokenAccount", - "isMut": true, - "isSigner": false - }, - { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - }, - { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" - } - } + "isSigner": false + }, + { + "name": "poolLpMint", + "isMut": false, + "isSigner": false }, { - "name": "marginalPricePoolToken0Account", + "name": "user", "isMut": false, "isSigner": false }, { - "name": "marginalPricePoolToken1Account", + "name": "userPoolToken0Account", + "isMut": true, + "isSigner": false + }, + { + "name": "userPoolToken1Account", + "isMut": true, + "isSigner": false + }, + { + "name": "userLpTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "associatedTokenProgram", "isMut": false, "isSigner": false }, { - "name": "marginalPricePoolLpMint", + "name": "systemProgram", "isMut": false, "isSigner": false }, { - "name": "twoPoolProgram", + "name": "tokenProgram", "isMut": false, "isSigner": false }, + { + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] + } + ] + }, { "name": "memo", "isMut": false, @@ -8845,109 +8394,90 @@ export const IDL: Propeller = { ] }, { - "name": "aggregator", - "isMut": false, - "isSigner": false, - "docs": [ - "Assuming that USD:USDC 1:1" - ] - }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false, - "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "ProcessSwimPayload", - "path": "process_swim_payload" - }, - { - "kind": "account", - "type": { - "defined": "Signer<'info>" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": { - "defined": "Program<'info,two_pool::program::TwoPool>" - }, - "account": "ProcessSwimPayload", - "path": "process_swim_payload.two_pool_program" + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false + ] }, { "name": "owner", @@ -9031,41 +8561,6 @@ export const IDL: Propeller = { "isMut": true, "isSigner": false }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, { "name": "claim", "isMut": false, @@ -9198,66 +8693,90 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false - }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false + ] }, { "name": "memo", @@ -9466,11 +8985,6 @@ export const IDL: Propeller = { "isMut": false, "isSigner": false }, - { - "name": "twoPoolProgram", - "isMut": false, - "isSigner": false - }, { "name": "memo", "isMut": false, @@ -9482,100 +8996,90 @@ export const IDL: Propeller = { "isSigner": false }, { - "name": "aggregator", - "isMut": false, - "isSigner": false - }, - { - "name": "feeVault", - "isMut": true, - "isSigner": false, - "docs": [ - "this is \"to_fees\"", - "recipient of fees for executing complete transfer (e.g. relayer)" - ] - }, - { - "name": "feeTracker", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "const", - "type": "string", - "value": "fee" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" - }, - { - "kind": "account", - "type": "publicKey", - "path": "payer" - } - ] - } - }, - { - "name": "marginalPricePool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_0_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "marginal_price_pool_token_1_account.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "marginal_price_pool_lp_mint" - } - ], - "programId": { - "kind": "account", - "type": "publicKey", - "path": "two_pool_program" + "name": "feeTracking", + "accounts": [ + { + "name": "aggregator", + "isMut": false, + "isSigner": false + }, + { + "name": "feeVault", + "isMut": true, + "isSigner": false, + "docs": [ + "this is \"to_fees\"", + "recipient of fees for executing complete transfer (e.g. relayer)" + ] + }, + { + "name": "feeTracker", + "isMut": true, + "isSigner": false + }, + { + "name": "marginalPricePool", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_0_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_1_account.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ], + "programId": { + "kind": "account", + "type": "publicKey", + "path": "two_pool_program" + } + } + }, + { + "name": "poolToken0Account", + "isMut": false, + "isSigner": false + }, + { + "name": "poolToken1Account", + "isMut": false, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": false, + "isSigner": false + }, + { + "name": "twoPoolProgram", + "isMut": false, + "isSigner": false + } + ] } - } - }, - { - "name": "marginalPricePoolToken0Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolToken1Account", - "isMut": false, - "isSigner": false - }, - { - "name": "marginalPricePoolLpMint", - "isMut": false, - "isSigner": false + ] }, { "name": "owner", @@ -9765,6 +9269,9 @@ export const IDL: Propeller = { }, { "name": "aggregator", + "docs": [ + "switchboard *" + ], "type": "publicKey" }, { @@ -10241,6 +9748,20 @@ export const IDL: Propeller = { ] } }, + { + "name": "ToSwimUsdStep", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Add" + }, + { + "name": "SwapExactInput" + } + ] + } + }, { "name": "ConsistencyLevel", "type": { @@ -10346,238 +9867,273 @@ export const IDL: Propeller = { }, { "code": 6011, + "name": "InvalidPoolForInitToSwimUsd", + "msg": "Invalid Pool for Init To SwimUSD" + }, + { + "code": 6012, "name": "InvalidCpiReturnProgramId", "msg": "Incorrect ProgramId for CPI return value" }, { - "code": 6012, + "code": 6013, "name": "InvalidCpiReturnValue", "msg": "Invalid CPI Return value" }, { - "code": 6013, + "code": 6014, "name": "InvalidMint", "msg": "Invalid Mint" }, { - "code": 6014, + "code": 6015, "name": "InvalidAddAndWormholeTransferMint", "msg": "Invalid Mint for AddAndWormholeTransfer" }, { - "code": 6015, + "code": 6016, "name": "InvalidSwapExactInputOutputTokenIndex", "msg": "Invalid output token index for SwapExactInput params" }, { - "code": 6016, + "code": 6017, "name": "InvalidSwapExactInputInputAmount", "msg": "Invalid input amount for SwapExactInput params" }, { - "code": 6017, + "code": 6018, "name": "InvalidSwimUsdMint", "msg": "Invalid SwimUSD Mint" }, { - "code": 6018, + "code": 6019, "name": "InvalidPayloadTypeInVaa", "msg": "Invalid Payload Type in VAA" }, { - "code": 6019, + "code": 6020, "name": "SerializeError", "msg": "Serializing error" }, { - "code": 6020, + "code": 6021, "name": "DeserializeError", "msg": "Deserializing error" }, { - "code": 6021, + "code": 6022, "name": "UserRedeemerSignatureNotDetected", "msg": "User redeemer needs to be signer" }, { - "code": 6022, + "code": 6023, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6023, + "code": 6024, "name": "StaleFeed", "msg": "Switchboard feed value is stale " }, { - "code": 6024, + "code": 6025, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6025, + "code": 6026, "name": "InsufficientAmount", "msg": "Insufficient Amount being transferred" }, { - "code": 6026, + "code": 6027, "name": "InvalidWormholeClaimAccount", "msg": "Invalid Wormhole Claim Account" }, { - "code": 6027, + "code": 6028, "name": "InvalidClaimData", "msg": "Invalid claim data" }, { - "code": 6028, + "code": 6029, "name": "ClaimNotClaimed", "msg": "Claim Account not claimed" }, { - "code": 6029, + "code": 6030, "name": "InvalidPropellerGovernanceKey", "msg": "Invalid Propeller GovernanceKey" }, { - "code": 6030, + "code": 6031, "name": "InvalidPropellerPauseKey", "msg": "Invalid Propeller Pause Key" }, { - "code": 6031, + "code": 6032, "name": "InvalidTokenNumberMapPool", "msg": "Invalid Pool for Token Number Map" }, { - "code": 6032, + "code": 6033, "name": "InvalidOutputTokenIndex", "msg": "Invalid Output Token Index" }, { - "code": 6033, + "code": 6034, "name": "InvalidTokenNumberMapPoolTokenIndex", "msg": "Invalid Pool Token Index for Token Number Map" }, { - "code": 6034, + "code": 6035, "name": "InvalidTokenNumberMapPoolTokenMint", "msg": "Invalid Pool Token Mint for Token Number Map" }, { - "code": 6035, + "code": 6036, "name": "InvalidTokenNumberMapToTokenStep", "msg": "Invalid To Token Step for Token Number Map" }, { - "code": 6036, + "code": 6037, "name": "InvalidSwimPayloadGasKickstart", "msg": "Invalid Gas Kickstart parameter in Swim Payload" }, { - "code": 6037, + "code": 6038, "name": "InvalidMarginalPricePool", "msg": "Invalid Marginal Price Pool" }, { - "code": 6038, + "code": 6039, "name": "InvalidMarginalPricePoolAccounts", "msg": "Invalid Marginal Price Pool Accounts" }, { - "code": 6039, + "code": 6040, "name": "NotPropellerEnabled", "msg": "Propeller Not Enabled in payload" }, { - "code": 6040, + "code": 6041, "name": "InvalidRoutingContractAddress", "msg": "Invalid Routing Contract Address" }, { - "code": 6041, + "code": 6042, "name": "IntegerOverflow", "msg": "Integer Overflow" }, { - "code": 6042, + "code": 6043, "name": "ConversionError", "msg": "Conversion Error" }, { - "code": 6043, + "code": 6044, "name": "UnableToRetrieveSwimUsdMintDecimals", "msg": "Unable to retrieve SwimUSD mint decimals from marginal price pool information" }, { - "code": 6044, + "code": 6045, "name": "InvalidMetapoolTokenMint", "msg": "Invalid Metapool Token Mint. token_mint[0] should == swim_usd_mint" }, { - "code": 6045, + "code": 6046, "name": "UnableToDeserializeTokenAccount", "msg": "Unable to deserialize account info as token account" }, { - "code": 6046, + "code": 6047, "name": "InvalidTokenAccountDataLen", "msg": "Invalid token account data length. != 0 && != TokenAccount::LEN" }, { - "code": 6047, + "code": 6048, "name": "PayerInsufficientFundsForGasKickstart", "msg": "Payer has insufficient funds for gas kickstart" }, { - "code": 6048, + "code": 6049, "name": "IncorrectOwnerForCreateTokenAccount", "msg": "Owner of token account != swimPayload.owner" }, { - "code": 6049, + "code": 6050, "name": "TokenNumberMapExists", "msg": "TokenNumberMap exists. Please use the correct instruction" }, { - "code": 6050, + "code": 6051, "name": "InvalidSwimPayloadVersion", "msg": "Invalid Swim Payload version" }, { - "code": 6051, + "code": 6052, "name": "InvalidAggregator", "msg": "Invalid Aggregator" }, { - "code": 6052, + "code": 6053, "name": "InvalidFeeVault", "msg": "Invalid Fee Vault" }, { - "code": 6053, + "code": 6054, "name": "InvalidMemo", "msg": "Invalid Memo" }, { - "code": 6054, + "code": 6055, "name": "ToTokenNumberMismatch", "msg": "ToTokenNumber does not match SwimPayload.to_tokenNumber" }, { - "code": 6055, + "code": 6056, "name": "IsPaused", "msg": "Routing Contract is paused" }, { - "code": 6056, + "code": 6057, "name": "TargetChainIsPaused", "msg": "Target Chain is paused" }, { - "code": 6057, + "code": 6058, + "name": "InvalidTargetChainMap", + "msg": "Invalid Target Chain Map" + }, + { + "code": 6059, "name": "InvalidSwimPayloadMessagePayer", "msg": "Invalid SwimPayloadMessagePayer" + }, + { + "code": 6060, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key for UpdatePauseKey" + }, + { + "code": 6061, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key for Prepare Governance Transition" + }, + { + "code": 6062, + "name": "InvalidEnact", + "msg": "Invalid Enact Governance Transition" + }, + { + "code": 6063, + "name": "InsufficientDelay", + "msg": "Insufficient Delay for Enact Governance Transition" + }, + { + "code": 6064, + "name": "InvalidFeeTracker", + "msg": "Invalid Fee Tracker" } ] }; diff --git a/packages/solana-contracts/src/artifacts/two_pool.json b/packages/solana-contracts/src/artifacts/two_pool.json index 8b217d768..04c6b9943 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.json +++ b/packages/solana-contracts/src/artifacts/two_pool.json @@ -128,81 +128,86 @@ "name": "add", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ diff --git a/packages/solana-contracts/src/artifacts/two_pool.ts b/packages/solana-contracts/src/artifacts/two_pool.ts index 0994bdcc8..f19a5eff6 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.ts +++ b/packages/solana-contracts/src/artifacts/two_pool.ts @@ -128,81 +128,86 @@ export type TwoPool = { "name": "add", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -2318,81 +2323,86 @@ export const IDL: TwoPool = { "name": "add", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ From 6706960d7a32e95d7eabd934318ecd9c72377b9e Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 25 Oct 2022 12:53:27 -0400 Subject: [PATCH 12/17] refactor(solana-contracts): refactor contexts for two pool ixs and update tests --- .../programs/propeller/src/constants.rs | 2 +- .../programs/propeller/src/fees.rs | 10 +- .../create_owner_token_accounts.rs | 25 +- .../propeller/src/instructions/fee_tracker.rs | 5 +- .../propeller/src/instructions/initialize.rs | 2 +- .../src/instructions/marginal_price_pool.rs | 18 +- .../src/instructions/process_swim_payload.rs | 98 +- .../src/instructions/target_chain_map.rs | 7 +- .../src/instructions/token_number_map.rs | 14 +- .../src/instructions/two_pool_cpi/add.rs | 6 +- .../two_pool_cpi/init_to_swim_usd.rs | 62 +- .../two_pool_cpi/remove_exact_burn.rs | 338 ++-- .../two_pool_cpi/remove_exact_output.rs | 242 +-- .../two_pool_cpi/remove_uniform.rs | 203 ++- .../two_pool_cpi/swap_exact_input.rs | 322 ++-- .../two_pool_cpi/swap_exact_output.rs | 372 ++--- .../wormhole/complete_native_with_payload.rs | 26 +- .../wormhole/secp256k1_and_verify.rs | 6 +- .../wormhole/transfer_native_with_payload.rs | 19 +- .../programs/propeller/src/lib.rs | 8 +- .../programs/propeller/src/state/propeller.rs | 8 +- .../programs/propeller/src/token_bridge.rs | 5 +- .../programs/propeller/src/wormhole.rs | 21 +- .../programs/two-pool/src/error.rs | 2 + .../src/instructions/defi/add_or_remove.rs | 619 ++++--- .../two-pool/src/instructions/defi/mod.rs | 76 +- .../two-pool/src/instructions/defi/swap.rs | 470 ++++++ .../src/instructions/remove_exact_burn.rs | 414 ++--- .../src/instructions/remove_exact_output.rs | 428 ++--- .../src/instructions/remove_uniform.rs | 294 ++-- .../src/instructions/swap_exact_input.rs | 444 ++--- .../src/instructions/swap_exact_output.rs | 462 +++--- .../programs/two-pool/src/lib.rs | 60 +- .../src/__tests__/twoPool/pool.test.ts | 92 +- .../src/artifacts/two_pool.json | 662 ++++---- .../src/artifacts/two_pool.ts | 1442 +++++++++-------- 36 files changed, 3943 insertions(+), 3341 deletions(-) create mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs diff --git a/packages/solana-contracts/programs/propeller/src/constants.rs b/packages/solana-contracts/programs/propeller/src/constants.rs index e7d875977..e71a1263f 100644 --- a/packages/solana-contracts/programs/propeller/src/constants.rs +++ b/packages/solana-contracts/programs/propeller/src/constants.rs @@ -1,4 +1,4 @@ -use {num_traits::FromPrimitive, rust_decimal::Decimal}; +use {rust_decimal::Decimal}; pub const CURRENT_SWIM_PAYLOAD_VERSION: u8 = 1; pub const TOKEN_COUNT: usize = 2; diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs index 566dc02ca..cb68c5513 100644 --- a/packages/solana-contracts/programs/propeller/src/fees.rs +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -1,16 +1,14 @@ use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, marginal_price_pool::*, FeeTracker, Propeller, PropellerError, TOKEN_COUNT, + constants::LAMPORTS_PER_SOL_DECIMAL, marginal_price_pool::*, FeeTracker, Propeller, PropellerError, }, anchor_lang::prelude::*, anchor_spl::{ - token, - token::{Token, TokenAccount, Transfer}, + token::{TokenAccount}, }, num_traits::{FromPrimitive, ToPrimitive}, rust_decimal::Decimal, - switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, - two_pool::BorshDecimal, + switchboard_v2::{AggregatorAccountData, SWITCHBOARD_PROGRAM_ID}, }; pub trait Fees<'info> { @@ -75,7 +73,7 @@ impl<'info> FeeTracking<'info> { fn convert_fees_to_swim_usd_atomic(&self, fee_in_lamports: u64, propeller: &Propeller) -> Result { let intermediate_token_price_decimal: Decimal = - self.marginal_price_pool.get_marginal_price_decimal(&propeller)?; + self.marginal_price_pool.get_marginal_price_decimal(propeller)?; msg!("intermediate_token_price_decimal: {:?}", intermediate_token_price_decimal); 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 a128f759b..db809f6de 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 @@ -1,27 +1,18 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, - deserialize_message_payload, error::*, fees::*, - get_memo_as_utf8, get_message_data, get_transfer_with_payload_from_message_account, hash_vaa, - marginal_price_pool::*, - state::{SwimClaim, SwimPayloadMessage, *}, - token_bridge::TokenBridge, - token_number_map::{ToTokenStep, TokenNumberMap}, - ClaimData, FeeTracker, Fees, PayloadTransferWithPayload, PostVAAData, PostedVAAData, Propeller, TOKEN_COUNT, + get_memo_as_utf8, + state::{SwimPayloadMessage}, + token_number_map::{TokenNumberMap}, Fees, Propeller, }, anchor_lang::{prelude::*, solana_program::program::invoke}, anchor_spl::{ associated_token::{get_associated_token_address, AssociatedToken}, token::{self, Mint, Token, TokenAccount, Transfer}, }, - num_traits::{FromPrimitive, ToPrimitive}, - rust_decimal::Decimal, - solana_program::{instruction::Instruction, program::invoke_signed}, - std::{convert::TryInto, iter::zip}, - two_pool::{state::TwoPool, BorshDecimal}, + two_pool::{state::TwoPool}, }; #[derive(Accounts)] @@ -168,11 +159,11 @@ impl<'info> PropellerCreateOwnerTokenAccounts<'info> { let token_account = TokenAccount::try_deserialize(&mut &**user_unchecked_token_account.data.try_borrow_mut().unwrap())?; require_keys_eq!(token_account.owner, user.key(), PropellerError::IncorrectOwnerForCreateTokenAccount); - return Ok(0u64); + Ok(0u64) } else if ata_data_len != 0 { //TODO: spl_token_2022? // panic!("data_len != 0 && != TokenAcount::LEN"); - return err!(PropellerError::InvalidTokenAccountDataLen); + err!(PropellerError::InvalidTokenAccountDataLen) } else { let ix = spl_associated_token_account::instruction::create_associated_token_account( &payer.key(), @@ -244,7 +235,7 @@ impl<'info> Fees<'info> for PropellerCreateOwnerTokenAccounts<'info> { to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.propeller.redeemer_bump]]], ), fees_in_swim_usd, ) @@ -420,7 +411,7 @@ impl<'info> Fees<'info> for PropellerCreateOwnerSwimUsdAta<'info> { to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.propeller.redeemer_bump]]], ), fees_in_swim_usd, ) diff --git a/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs b/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs index 8bf0055cf..e0aa93359 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/fee_tracker.rs @@ -2,10 +2,9 @@ use { crate::{error::*, Propeller}, anchor_lang::prelude::*, anchor_spl::{ - associated_token::{create, get_associated_token_address, AssociatedToken, Create}, + associated_token::{get_associated_token_address}, token::{self, Mint, Token, TokenAccount, Transfer}, }, - two_pool::state::TwoPool, }; //TODO: need to initialize propeller with a "fee_vault" @@ -125,7 +124,7 @@ pub fn handle_claim_fees(ctx: Context) -> Result<()> { CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), cpi_accounts, - &[&[&b"propeller".as_ref(), ctx.accounts.propeller.swim_usd_mint.as_ref(), &[ctx.accounts.propeller.bump]]], + &[&[(b"propeller".as_ref()), ctx.accounts.propeller.swim_usd_mint.as_ref(), &[ctx.accounts.propeller.bump]]], ), fees_owed, )?; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs index a8e02645c..dec7383e1 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/initialize.rs @@ -2,7 +2,7 @@ use { crate::{error::*, Propeller}, anchor_lang::prelude::*, anchor_spl::{ - associated_token::{create, AssociatedToken, Create}, + associated_token::{AssociatedToken}, token::{Mint, Token, TokenAccount}, }, switchboard_v2::{AggregatorAccountData, SWITCHBOARD_PROGRAM_ID}, diff --git a/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs index e5a38f1e4..e8680aa9b 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs @@ -1,26 +1,16 @@ -use crate::{get_memo_as_utf8, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees}; + use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, get_message_data, - get_transfer_with_payload_from_message_account, hash_vaa, instructions::fee_tracker::FeeTracker, - state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, PayloadTransferWithPayload, PostVAAData, - PostedVAAData, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, + error::*, Propeller, TOKEN_COUNT, }, anchor_lang::{ prelude::*, - solana_program::{instruction::Instruction, program::invoke_signed, system_program, sysvar::SysvarId}, }, anchor_spl::{ - associated_token::get_associated_token_address, - token, - token::{Mint, Token, TokenAccount, Transfer}, + token::{Mint, TokenAccount}, }, - byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, - num_traits::{FromPrimitive, ToPrimitive}, // primitive_types::U256, rust_decimal::Decimal, - solana_program::program::invoke, - switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, two_pool::{state::TwoPool, BorshDecimal}, }; @@ -127,7 +117,7 @@ impl<'info> MarginalPricePool<'info> { } else if swim_usd_mint == marginal_price_pool.token_mint_keys[1] { Ok(marginal_price_pool_lp_mint_decimals + marginal_price_pool.token_decimal_equalizers[1]) } else { - return err!(PropellerError::UnableToRetrieveSwimUsdMintDecimals); + err!(PropellerError::UnableToRetrieveSwimUsdMintDecimals) } } } 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 c04070f2c..c081d2524 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 @@ -1,43 +1,20 @@ pub use switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}; use { - crate::{constants::LAMPORTS_PER_SOL_DECIMAL, FeeTracker}, crate::{ - deserialize_message_payload, - // env::*, error::*, - get_message_data, - get_transfer_with_payload_from_message_account, - hash_vaa, - marginal_price_pool::*, - state::{SwimClaim, SwimPayloadMessage, *}, - token_bridge::TokenBridge, + fees::*, + get_memo_as_utf8, + state::{SwimClaim, SwimPayloadMessage}, token_number_map::{ToTokenStep, TokenNumberMap}, - ClaimData, - PayloadTransferWithPayload, - PostVAAData, - PostedVAAData, - Propeller, - TOKEN_COUNT, + ClaimData, Propeller, TOKEN_COUNT, }, - anchor_lang::system_program, - anchor_lang::{prelude::*, solana_program::program::invoke}, + anchor_lang::{prelude::*, solana_program::program::invoke, system_program}, anchor_spl::{ - associated_token::{get_associated_token_address, AssociatedToken}, - token::Transfer, + associated_token::get_associated_token_address, + token::{self, Mint, Token, TokenAccount, Transfer}, }, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - num_traits::{FromPrimitive, ToPrimitive}, - rust_decimal::Decimal, - std::convert::TryInto, two_pool::state::TwoPool, }; -use { - crate::{fees::*, get_memo_as_utf8}, - two_pool::BorshDecimal, -}; pub const SWIM_USD_TO_TOKEN_NUMBER: u16 = 0; @@ -122,7 +99,7 @@ pub struct ProcessSwimPayload<'info> { )] pub token_number_map: Account<'info, TokenNumberMap>, - /* Pool Used for final swap to get token_id_map.pool_token_mint */ + /* Pool Used for final swap to get token_number_map.pool_token_mint */ #[account( mut, seeds = [ @@ -209,7 +186,7 @@ impl<'info> ProcessSwimPayload<'info> { pool_token_index, pool_token_mint, &self.redeemer.to_account_info(), - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.propeller.redeemer_bump]]], ) } @@ -224,7 +201,7 @@ impl<'info> ProcessSwimPayload<'info> { user_transfer_authority: &AccountInfo<'info>, signer_seeds: &[&[&[u8]]], ) -> Result { - let swim_payload_owner = self.swim_payload_message.owner; + let _swim_payload_owner = self.swim_payload_message.owner; require_gt!(TOKEN_COUNT, pool_token_index as usize); match to_token_step { ToTokenStep::RemoveExactBurn => { @@ -235,17 +212,28 @@ impl<'info> ProcessSwimPayload<'info> { Ok(two_pool::cpi::remove_exact_burn( CpiContext::new_with_signer( self.two_pool_program.to_account_info(), - two_pool::cpi::accounts::RemoveExactBurn { - pool: self.pool.to_account_info(), - pool_token_account_0: self.pool_token_account_0.to_account_info(), - pool_token_account_1: self.pool_token_account_1.to_account_info(), - lp_mint: self.lp_mint.to_account_info(), - governance_fee: self.governance_fee.to_account_info(), - user_transfer_authority: user_transfer_authority.to_account_info(), - user_token_account_0: self.user_token_account_0.to_account_info(), - user_token_account_1: self.user_token_account_1.to_account_info(), + two_pool::cpi::accounts::AddOrRemove { + swap: two_pool::cpi::accounts::Swap { + pool: self.pool.to_account_info(), + pool_token_account_0: self.pool_token_account_0.to_account_info(), + pool_token_account_1: self.pool_token_account_1.to_account_info(), + lp_mint: self.lp_mint.to_account_info(), + governance_fee: self.governance_fee.to_account_info(), + user_transfer_authority: user_transfer_authority.to_account_info(), + user_token_account_0: self.user_token_account_0.to_account_info(), + user_token_account_1: self.user_token_account_1.to_account_info(), + token_program: self.token_program.to_account_info(), + }, + // pool: self.pool.to_account_info(), + // pool_token_account_0: self.pool_token_account_0.to_account_info(), + // pool_token_account_1: self.pool_token_account_1.to_account_info(), + // lp_mint: self.lp_mint.to_account_info(), + // governance_fee: self.governance_fee.to_account_info(), + // user_transfer_authority: user_transfer_authority.to_account_info(), + // user_token_account_0: self.user_token_account_0.to_account_info(), + // user_token_account_1: self.user_token_account_1.to_account_info(), user_lp_token_account: self.redeemer_escrow.to_account_info(), - token_program: self.token_program.to_account_info(), + // token_program: self.token_program.to_account_info(), }, signer_seeds, ), @@ -262,7 +250,7 @@ impl<'info> ProcessSwimPayload<'info> { Ok(two_pool::cpi::swap_exact_input( CpiContext::new_with_signer( self.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactInput { + two_pool::cpi::accounts::Swap { pool: self.pool.to_account_info(), pool_token_account_0: self.pool_token_account_0.to_account_info(), pool_token_account_1: self.pool_token_account_1.to_account_info(), @@ -332,8 +320,8 @@ pub fn handle_process_swim_payload( let transfer_amount = ctx.accounts.swim_payload_message.transfer_amount; - let owner = propeller_message.owner; - let token_program = &ctx.accounts.token_program; + let _owner = propeller_message.owner; + let _token_program = &ctx.accounts.token_program; msg!("transfer_amount: {}", transfer_amount); let output_amount = ctx.accounts.transfer_tokens(to_token_number, transfer_amount, min_output_amount)?; @@ -465,7 +453,7 @@ impl<'info> Fees<'info> for PropellerProcessSwimPayload<'info> { to: self.fee_tracking.fee_vault.to_account_info(), authority: self.process_swim_payload.redeemer.to_account_info(), }, - &[&[&b"redeemer".as_ref(), &[self.process_swim_payload.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.process_swim_payload.propeller.redeemer_bump]]], ), fees_in_swim_usd, ) @@ -492,7 +480,7 @@ TODO: */ pub fn handle_propeller_process_swim_payload( ctx: Context, - to_token_number: u16, + _to_token_number: u16, ) -> Result { let swim_payload_message = &ctx.accounts.process_swim_payload.swim_payload_message; let is_gas_kickstart = swim_payload_message.gas_kickstart; @@ -505,9 +493,9 @@ pub fn handle_propeller_process_swim_payload( let mut transfer_amount = swim_payload_message.transfer_amount; let propeller = &ctx.accounts.process_swim_payload.propeller; - let redeemer = &ctx.accounts.process_swim_payload.redeemer; + let _redeemer = &ctx.accounts.process_swim_payload.redeemer; let swim_payload_owner = swim_payload_message.owner; - let token_program = &ctx.accounts.process_swim_payload.token_program; + let _token_program = &ctx.accounts.process_swim_payload.token_program; msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.process_swim_payload.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; @@ -743,7 +731,7 @@ impl<'info> Fees<'info> for PropellerProcessSwimPayloadFallback<'info> { to: self.fee_tracking.fee_vault.to_account_info(), authority: self.redeemer.to_account_info(), }, - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.propeller.redeemer_bump]]], ), fees_in_swim_usd, ) @@ -755,7 +743,7 @@ pub fn handle_propeller_process_swim_payload_fallback( ) -> Result { let swim_payload_message = &ctx.accounts.swim_payload_message; let is_gas_kickstart = swim_payload_message.gas_kickstart; - let target_token_id = swim_payload_message.target_token_id; + let _target_token_id = swim_payload_message.target_token_id; let claim_data = ClaimData::try_from_slice(&mut ctx.accounts.claim.data.borrow()) .map_err(|_| error!(PropellerError::InvalidClaimData))?; @@ -765,9 +753,9 @@ pub fn handle_propeller_process_swim_payload_fallback( let mut transfer_amount = swim_payload_message.transfer_amount; let propeller = &ctx.accounts.propeller; let propeller_redeemer_bump = ctx.accounts.propeller.redeemer_bump; - let redeemer = &ctx.accounts.redeemer; + let _redeemer = &ctx.accounts.redeemer; let swim_payload_owner = swim_payload_message.owner; - let token_program = &ctx.accounts.token_program; + let _token_program = &ctx.accounts.token_program; msg!("original transfer_amount: {:?}", transfer_amount); if swim_payload_owner != ctx.accounts.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; @@ -786,7 +774,7 @@ pub fn handle_propeller_process_swim_payload_fallback( let output_amount = ctx.accounts.transfer_swim_usd_tokens( transfer_amount, &ctx.accounts.redeemer.to_account_info(), - &[&[&b"redeemer".as_ref(), &[propeller_redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[propeller_redeemer_bump]]], )?; let swim_claim_bump = *ctx.bumps.get("swim_claim").unwrap(); diff --git a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs index 31df74648..dd82147fe 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/target_chain_map.rs @@ -1,11 +1,6 @@ use { - crate::{error::PropellerError, Propeller, TOKEN_COUNT}, + crate::{error::PropellerError, Propeller}, anchor_lang::prelude::*, - anchor_spl::{ - associated_token::{create, AssociatedToken, Create}, - token::{Mint, Token, TokenAccount}, - }, - two_pool::state::TwoPool, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs b/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs index 06f0c1f9e..12e06d4e3 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/token_number_map.rs @@ -1,10 +1,6 @@ use { crate::{error::PropellerError, Propeller, TOKEN_COUNT}, anchor_lang::prelude::*, - anchor_spl::{ - associated_token::{create, AssociatedToken, Create}, - token::{Mint, Token, TokenAccount}, - }, two_pool::state::TwoPool, }; @@ -83,7 +79,7 @@ pub enum ToTokenStep { impl<'info> CreateTokenNumberMap<'info> { pub fn accounts( ctx: &Context, - to_token_number: u16, + _to_token_number: u16, pool: Pubkey, pool_token_index: u8, pool_token_mint: Pubkey, @@ -118,7 +114,7 @@ pub fn handle_create_token_number_map( pool_token_mint: Pubkey, to_token_step: ToTokenStep, ) -> Result<()> { - let mut token_number_map = &mut ctx.accounts.token_number_map; + let token_number_map = &mut ctx.accounts.token_number_map; token_number_map.to_token_number = to_token_number; token_number_map.pool = pool; token_number_map.pool_token_index = pool_token_index; @@ -186,8 +182,8 @@ impl<'info> UpdateTokenNumberMap<'info> { &[ b"two_pool".as_ref(), pool.token_mint_keys[0].as_ref(), - &pool.token_mint_keys[1].as_ref(), - &pool.lp_mint_key.as_ref(), + (pool.token_mint_keys[1].as_ref()), + (pool.lp_mint_key.as_ref()), &[pool.bump], ], &ctx.accounts.two_pool_program.key(), @@ -206,7 +202,7 @@ impl<'info> UpdateTokenNumberMap<'info> { ToTokenStep::SwapExactInput => { require_keys_eq!(pool.token_mint_keys[0], propeller.swim_usd_mint); require_keys_eq!(pool.token_mint_keys[1], pool_token_mint); - require_eq!(pool_token_index, 1 as usize); + require_eq!(pool_token_index, 1_usize); } ToTokenStep::RemoveExactBurn => { require_keys_eq!(pool.lp_mint_key, pool_token_mint); diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs index 3e23e8800..3036c75ce 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs @@ -1,11 +1,11 @@ use { - crate::{constants::PROPELLER_MINIMUM_OUTPUT_AMOUNT, error::*, Propeller}, - anchor_lang::{prelude::*, solana_program::program::invoke}, + crate::{error::*, Propeller}, + anchor_lang::{prelude::*}, anchor_spl::{ associated_token::get_associated_token_address, token::{Mint, Token, TokenAccount}, }, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, + two_pool::{state::TwoPool}, }; #[derive(Accounts)] diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs index 30e9170f6..1dcc64602 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/init_to_swim_usd.rs @@ -4,12 +4,12 @@ use { error::*, Propeller, TOKEN_COUNT, }, - anchor_lang::{prelude::*, solana_program::program::invoke}, + anchor_lang::prelude::*, anchor_spl::{ associated_token::get_associated_token_address, token::{Mint, Token, TokenAccount}, }, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool}, + two_pool::state::TwoPool, }; #[derive(Accounts)] @@ -32,9 +32,7 @@ pub struct InitToSwimUsd<'info> { seeds::program = two_pool_program.key() )] pub pool: Box>, - // /// TODO: could be removed if initialized with pool_v2 - // /// CHECK: checked in CPI - // pub pool_auth: UncheckedAccount<'info>, + #[account( mut, address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), @@ -90,13 +88,13 @@ impl<'info> InitToSwimUsd<'info> { fn determine_to_swim_usd_step(&self) -> Result { let pool = &self.pool; let swim_usd_mint = self.propeller.swim_usd_mint; - return if pool.lp_mint_key == swim_usd_mint { + if pool.lp_mint_key == swim_usd_mint { Ok(ToSwimUsdStep::Add) } else if pool.token_mint_keys[0] == swim_usd_mint { Ok(ToSwimUsdStep::SwapExactInput) } else { err!(PropellerError::InvalidPoolForInitToSwimUsd) - }; + } } fn invoke_pool_ix_for_swim_usd( @@ -112,6 +110,30 @@ impl<'info> InitToSwimUsd<'info> { Ok(output_amount) } + fn invoke_add(&self, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { + let cpi_ctx = CpiContext::new( + self.two_pool_program.to_account_info(), + two_pool::cpi::accounts::AddOrRemove { + swap: two_pool::cpi::accounts::Swap { + pool: self.pool.to_account_info(), + pool_token_account_0: self.pool_token_account_0.to_account_info(), + pool_token_account_1: self.pool_token_account_1.to_account_info(), + lp_mint: self.lp_mint.to_account_info(), + governance_fee: self.governance_fee.to_account_info(), + user_transfer_authority: self.user_transfer_authority.to_account_info(), + user_token_account_0: self.user_token_account_0.to_account_info(), + user_token_account_1: self.user_token_account_1.to_account_info(), + token_program: self.token_program.to_account_info(), + }, + user_lp_token_account: self.user_lp_token_account.to_account_info(), + }, + ); + let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; + let output_amount = result.get(); + msg!("ToSwimUsd(add) - output_amount: {}", output_amount); + Ok(output_amount) + } + fn invoke_swap_exact_input( &self, exact_input_amounts: [u64; TOKEN_COUNT], @@ -124,7 +146,7 @@ impl<'info> InitToSwimUsd<'info> { ); let cpi_ctx = CpiContext::new( self.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactInput { + two_pool::cpi::accounts::Swap { pool: self.pool.to_account_info(), pool_token_account_0: self.pool_token_account_0.to_account_info(), pool_token_account_1: self.pool_token_account_1.to_account_info(), @@ -147,30 +169,6 @@ impl<'info> InitToSwimUsd<'info> { msg!("ToSwimUsd[swap_exact_input] - output_amount: {}", output_amount); Ok(output_amount) } - - fn invoke_add(&self, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { - let cpi_ctx = CpiContext::new( - self.two_pool_program.to_account_info(), - two_pool::cpi::accounts::AddOrRemove { - swap: two_pool::cpi::accounts::Swap { - pool: self.pool.to_account_info(), - pool_token_account_0: self.pool_token_account_0.to_account_info(), - pool_token_account_1: self.pool_token_account_1.to_account_info(), - lp_mint: self.lp_mint.to_account_info(), - governance_fee: self.governance_fee.to_account_info(), - user_transfer_authority: self.user_transfer_authority.to_account_info(), - user_token_account_0: self.user_token_account_0.to_account_info(), - user_token_account_1: self.user_token_account_1.to_account_info(), - token_program: self.token_program.to_account_info(), - }, - user_lp_token_account: self.user_lp_token_account.to_account_info(), - }, - ); - let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; - let output_amount = result.get(); - msg!("ToSwimUsd(add) - output_amount: {}", output_amount); - Ok(output_amount) - } } pub fn handle_cross_chain_init_to_swim_usd( diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs index 98f735b77..ab7e41c6c 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs @@ -1,101 +1,142 @@ -use { - crate::{ - constants::{PROPELLER_MINIMUM_OUTPUT_AMOUNT, REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX}, - error::*, - Propeller, - }, - anchor_lang::{prelude::*, solana_program::program::invoke}, - anchor_spl::token::{Mint, Token, TokenAccount}, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, -}; - -#[derive(Accounts)] -pub struct RemoveExactBurn<'info> { - #[account( - seeds = [ - b"propeller".as_ref(), - pool_token_account_0.mint.as_ref(), - ], - bump = propeller.bump, - has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, - )] - pub propeller: Account<'info, Propeller>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - 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>, - #[account(executable, address = spl_memo::id())] - ///CHECK: memo program - pub memo: UncheckedAccount<'info>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, - pub swim_usd_mint: Account<'info, Mint>, -} - -// pub fn handle_remove_exact_burn( +// use { +// crate::{ +// constants::{PROPELLER_MINIMUM_OUTPUT_AMOUNT, REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX}, +// error::*, +// Propeller, +// }, +// anchor_lang::{prelude::*, solana_program::program::invoke}, +// anchor_spl::token::{Mint, Token, TokenAccount}, +// two_pool::{state::TwoPool}, +// }; +// +// #[derive(Accounts)] +// pub struct RemoveExactBurn<'info> { +// #[account( +// seeds = [ +// b"propeller".as_ref(), +// pool_token_account_0.mint.as_ref(), +// ], +// bump = propeller.bump, +// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, +// )] +// pub propeller: Account<'info, Propeller>, +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump, +// seeds::program = two_pool_program.key() +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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>, +// #[account(executable, address = spl_memo::id())] +// ///CHECK: memo program +// pub memo: UncheckedAccount<'info>, +// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +// pub swim_usd_mint: Account<'info, Mint>, +// } +// +// // pub fn handle_remove_exact_burn( +// // ctx: Context, +// // exact_burn_amount: u64, +// // // output_token_index: u8, +// // minimum_output_amount: u64, +// // memo: &[u8], +// // propeller_enabled: bool, +// // target_chain: u16, +// // ) -> Result { +// // let cpi_ctx = CpiContext::new( +// // ctx.accounts.two_pool_program.to_account_info(), +// // two_pool::cpi::accounts::RemoveExactBurn { +// // pool: ctx.accounts.pool.to_account_info(), +// // pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// // pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// // lp_mint: ctx.accounts.lp_mint.to_account_info(), +// // governance_fee: ctx.accounts.governance_fee.to_account_info(), +// // user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// // user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// // user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// // user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// // token_program: ctx.accounts.token_program.to_account_info(), +// // }, +// // ); +// // let result = two_pool::cpi::remove_exact_burn( +// // cpi_ctx, +// // exact_burn_amount, +// // REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, +// // minimum_output_amount, +// // )?; +// // let return_val = result.get(); +// // let memo_ix = spl_memo::build_memo(memo, &[]); +// // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// // anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", return_val); +// // is_transfer_amount_sufficient( +// // &ctx.accounts.propeller, +// // &ctx.accounts.token_bridge_mint, +// // propeller_enabled, +// // target_chain, +// // return_val, +// // )?; +// // Ok(return_val) +// // } +// +// pub fn handle_cross_chain_remove_exact_burn( // ctx: Context, // exact_burn_amount: u64, -// // output_token_index: u8, // minimum_output_amount: u64, // memo: &[u8], -// propeller_enabled: bool, -// target_chain: u16, // ) -> Result { // let cpi_ctx = CpiContext::new( // ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::RemoveExactBurn { +// two_pool::cpi::accounts::AddOrRemove { // pool: ctx.accounts.pool.to_account_info(), // pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), // pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), @@ -114,85 +155,44 @@ pub struct RemoveExactBurn<'info> { // REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, // minimum_output_amount, // )?; -// let return_val = result.get(); +// let output_amount = result.get(); // let memo_ix = spl_memo::build_memo(memo, &[]); // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", return_val); -// is_transfer_amount_sufficient( -// &ctx.accounts.propeller, -// &ctx.accounts.token_bridge_mint, -// propeller_enabled, -// target_chain, -// return_val, +// anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); +// Ok(output_amount) +// } +// +// pub fn handle_propeller_remove_exact_burn( +// ctx: Context, +// exact_burn_amount: u64, +// memo: &[u8], +// max_fee: u64, +// ) -> Result { +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::RemoveExactBurn { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let result = two_pool::cpi::remove_exact_burn( +// cpi_ctx, +// exact_burn_amount, +// REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, +// PROPELLER_MINIMUM_OUTPUT_AMOUNT, // )?; -// Ok(return_val) +// let output_amount = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); +// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); +// Ok(output_amount) // } - -pub fn handle_cross_chain_remove_exact_burn( - ctx: Context, - exact_burn_amount: u64, - minimum_output_amount: u64, - memo: &[u8], -) -> Result { - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::RemoveExactBurn { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let result = two_pool::cpi::remove_exact_burn( - cpi_ctx, - exact_burn_amount, - REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, - minimum_output_amount, - )?; - let output_amount = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); - Ok(output_amount) -} - -pub fn handle_propeller_remove_exact_burn( - ctx: Context, - exact_burn_amount: u64, - memo: &[u8], - max_fee: u64, -) -> Result { - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::RemoveExactBurn { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let result = two_pool::cpi::remove_exact_burn( - cpi_ctx, - exact_burn_amount, - REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, - PROPELLER_MINIMUM_OUTPUT_AMOUNT, - )?; - let output_amount = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); - require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); - Ok(output_amount) -} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs index 2d75ec414..bf27cbd0f 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs @@ -1,121 +1,121 @@ -use { - crate::{error::*, Propeller}, - anchor_lang::{prelude::*, solana_program::program::invoke}, - anchor_spl::token::{Mint, Token, TokenAccount}, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, -}; - -#[derive(Accounts)] -pub struct RemoveExactOutput<'info> { - #[account( - seeds = [ - b"propeller".as_ref(), - pool_token_account_0.mint.as_ref(), - ], - bump = propeller.bump, - has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, - )] - pub propeller: Account<'info, Propeller>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - 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>, - #[account(executable, address = spl_memo::id())] - ///CHECK: memo program - pub memo: UncheckedAccount<'info>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, - pub swim_usd_mint: Account<'info, Mint>, -} - -pub fn handle_remove_exact_output( - ctx: Context, - maximum_burn_amount: u64, - exact_output_amount: u64, - memo: &[u8], - propeller_enabled: bool, - target_chain: u16, -) -> Result> { - // is_transfer_amount_sufficient( - // &ctx.accounts.propeller, - // &ctx.accounts.token_bridge_mint, - // propeller_enabled, - // target_chain, - // exact_output_amount, - // )?; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::RemoveExactOutput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - - let exact_output_amounts = [exact_output_amount, 0]; - let result = two_pool::cpi::remove_exact_output(cpi_ctx, maximum_burn_amount, exact_output_amounts)?; - let return_val = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("remove_exact_output return_val: {:?}", return_val); - Ok(return_val) -} +// use { +// crate::{error::*, Propeller}, +// anchor_lang::{prelude::*, solana_program::program::invoke}, +// anchor_spl::token::{Mint, Token, TokenAccount}, +// two_pool::{state::TwoPool}, +// }; +// +// #[derive(Accounts)] +// pub struct RemoveExactOutput<'info> { +// #[account( +// seeds = [ +// b"propeller".as_ref(), +// pool_token_account_0.mint.as_ref(), +// ], +// bump = propeller.bump, +// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, +// )] +// pub propeller: Account<'info, Propeller>, +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump, +// seeds::program = two_pool_program.key() +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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>, +// #[account(executable, address = spl_memo::id())] +// ///CHECK: memo program +// pub memo: UncheckedAccount<'info>, +// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +// pub swim_usd_mint: Account<'info, Mint>, +// } +// +// pub fn handle_remove_exact_output( +// ctx: Context, +// maximum_burn_amount: u64, +// exact_output_amount: u64, +// memo: &[u8], +// _propeller_enabled: bool, +// _target_chain: u16, +// ) -> Result> { +// // is_transfer_amount_sufficient( +// // &ctx.accounts.propeller, +// // &ctx.accounts.token_bridge_mint, +// // propeller_enabled, +// // target_chain, +// // exact_output_amount, +// // )?; +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::RemoveExactOutput { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// +// let exact_output_amounts = [exact_output_amount, 0]; +// let result = two_pool::cpi::remove_exact_output(cpi_ctx, maximum_burn_amount, exact_output_amounts)?; +// let return_val = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("remove_exact_output return_val: {:?}", return_val); +// Ok(return_val) +// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs index 4e1685655..545e3e15a 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs @@ -1,102 +1,101 @@ -use { - crate::Propeller, - anchor_lang::{prelude::*, solana_program::program::invoke}, - anchor_spl::token::{Mint, Token, TokenAccount}, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, -}; - -#[derive(Accounts)] -pub struct RemoveUniform<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - 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>, - #[account(executable, address = spl_memo::id())] - ///CHECK: memo program - pub memo: UncheckedAccount<'info>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -} - -pub fn handle_remove_uniform( - ctx: Context, - exact_burn_amount: u64, - minimum_output_amounts: [u64; TOKEN_COUNT], - memo: &[u8], -) -> Result> { - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::RemoveUniform { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - - let result = two_pool::cpi::remove_uniform(cpi_ctx, exact_burn_amount, minimum_output_amounts)?; - let return_val = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("remove_uniform return_val: {:?}", return_val); - Ok(return_val) -} +// use { +// anchor_lang::{prelude::*, solana_program::program::invoke}, +// anchor_spl::token::{Mint, Token, TokenAccount}, +// two_pool::{state::TwoPool, TOKEN_COUNT}, +// }; +// +// #[derive(Accounts)] +// pub struct RemoveUniform<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump, +// seeds::program = two_pool_program.key() +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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>, +// #[account(executable, address = spl_memo::id())] +// ///CHECK: memo program +// pub memo: UncheckedAccount<'info>, +// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +// } +// +// pub fn handle_remove_uniform( +// ctx: Context, +// exact_burn_amount: u64, +// minimum_output_amounts: [u64; TOKEN_COUNT], +// memo: &[u8], +// ) -> Result> { +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::RemoveUniform { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// +// let result = two_pool::cpi::remove_uniform(cpi_ctx, exact_burn_amount, minimum_output_amounts)?; +// let return_val = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("remove_uniform return_val: {:?}", return_val); +// Ok(return_val) +// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs index f2ce57c2c..3fb98bd6c 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs @@ -1,90 +1,161 @@ -use { - crate::{ - constants::{METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT}, - Propeller, PropellerError, - }, - anchor_lang::{prelude::*, solana_program::program::invoke}, - anchor_spl::token::{Mint, Token, TokenAccount}, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, -}; - -#[derive(Accounts)] -pub struct SwapExactInput<'info> { - #[account( - seeds = [ - b"propeller".as_ref(), - pool_token_account_0.mint.as_ref(), - ], - bump = propeller.bump, - has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, - constraint = !propeller.is_paused @ PropellerError::IsPaused, - )] - pub propeller: Account<'info, Propeller>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: 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>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, - pub swim_usd_mint: Account<'info, Mint>, -} - -// pub fn handle_swap_exact_input( +// use { +// crate::{ +// constants::{METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT}, +// Propeller, PropellerError, +// }, +// anchor_lang::{prelude::*}, +// anchor_spl::token::{Mint, Token, TokenAccount}, +// two_pool::{state::TwoPool}, +// }; +// +// #[derive(Accounts)] +// pub struct SwapExactInput<'info> { +// #[account( +// seeds = [ +// b"propeller".as_ref(), +// pool_token_account_0.mint.as_ref(), +// ], +// bump = propeller.bump, +// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, +// constraint = !propeller.is_paused @ PropellerError::IsPaused, +// )] +// pub propeller: Account<'info, Propeller>, +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump, +// seeds::program = two_pool_program.key() +// )] +// pub pool: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: 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>, +// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +// pub swim_usd_mint: Account<'info, Mint>, +// } +// +// // pub fn handle_swap_exact_input( +// // ctx: Context, +// // exact_input_amount: u64, +// // // exact_input_amounts: [u64; TOKEN_COUNT], +// // // output_token_index: u8, +// // minimum_output_amount: u64, +// // memo: &[u8], +// // propeller_enabled: bool, +// // target_chain: u16, +// // ) -> Result { +// // require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); +// // let exact_input_amounts = [0, exact_input_amount]; +// // let cpi_ctx = CpiContext::new( +// // ctx.accounts.two_pool_program.to_account_info(), +// // two_pool::cpi::accounts::SwapExactInput { +// // pool: ctx.accounts.pool.to_account_info(), +// // pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// // pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// // lp_mint: ctx.accounts.lp_mint.to_account_info(), +// // governance_fee: ctx.accounts.governance_fee.to_account_info(), +// // user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// // user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// // user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// // token_program: ctx.accounts.token_program.to_account_info(), +// // }, +// // ); +// // +// // let result = two_pool::cpi::swap_exact_input( +// // cpi_ctx, +// // exact_input_amounts, +// // SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX, +// // minimum_output_amount, +// // )?; +// // let return_val = result.get(); +// // let memo_ix = spl_memo::build_memo(memo, &[]); +// // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// // anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); +// // is_transfer_amount_sufficient( +// // &ctx.accounts.propeller, +// // &ctx.accounts.token_bridge_mint, +// // propeller_enabled, +// // target_chain, +// // return_val, +// // )?; +// // Ok(return_val) +// // } +// +// pub fn handle_cross_chain_swap_exact_input( // ctx: Context, // exact_input_amount: u64, -// // exact_input_amounts: [u64; TOKEN_COUNT], -// // output_token_index: u8, // minimum_output_amount: u64, -// memo: &[u8], -// propeller_enabled: bool, -// target_chain: u16, +// ) -> Result { +// require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); +// let exact_input_amounts = [0, exact_input_amount]; +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::SwapExactInput { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// +// let result = +// two_pool::cpi::swap_exact_input(cpi_ctx, exact_input_amounts, METAPOOL_SWIM_USD_INDEX, minimum_output_amount)?; +// let return_val = result.get(); +// anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); +// Ok(return_val) +// } +// +// pub fn handle_propeller_swap_exact_input( +// ctx: Context, +// exact_input_amount: u64, +// max_fee: u64, // ) -> Result { // require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); // let exact_input_amounts = [0, exact_input_amount]; @@ -106,82 +177,11 @@ pub struct SwapExactInput<'info> { // let result = two_pool::cpi::swap_exact_input( // cpi_ctx, // exact_input_amounts, -// SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX, -// minimum_output_amount, +// METAPOOL_SWIM_USD_INDEX, +// PROPELLER_MINIMUM_OUTPUT_AMOUNT, // )?; -// let return_val = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); -// is_transfer_amount_sufficient( -// &ctx.accounts.propeller, -// &ctx.accounts.token_bridge_mint, -// propeller_enabled, -// target_chain, -// return_val, -// )?; -// Ok(return_val) +// let output_amount = result.get(); +// anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", output_amount); +// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); +// Ok(output_amount) // } - -pub fn handle_cross_chain_swap_exact_input( - ctx: Context, - exact_input_amount: u64, - minimum_output_amount: u64, -) -> Result { - require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); - let exact_input_amounts = [0, exact_input_amount]; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactInput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - - let result = - two_pool::cpi::swap_exact_input(cpi_ctx, exact_input_amounts, METAPOOL_SWIM_USD_INDEX, minimum_output_amount)?; - let return_val = result.get(); - anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); - Ok(return_val) -} - -pub fn handle_propeller_swap_exact_input( - ctx: Context, - exact_input_amount: u64, - max_fee: u64, -) -> Result { - require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); - let exact_input_amounts = [0, exact_input_amount]; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactInput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - - let result = two_pool::cpi::swap_exact_input( - cpi_ctx, - exact_input_amounts, - METAPOOL_SWIM_USD_INDEX, - PROPELLER_MINIMUM_OUTPUT_AMOUNT, - )?; - let output_amount = result.get(); - anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", output_amount); - require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); - Ok(output_amount) -} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs index e2c79d93e..da30ffea5 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs @@ -1,186 +1,186 @@ -use { - crate::{constants::SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX, error::*, Propeller}, - anchor_lang::{prelude::*, solana_program::program::invoke}, - anchor_spl::token::{Mint, Token, TokenAccount}, - two_pool::{gen_pool_signer_seeds, program::TwoPool as TwoPoolProgram, state::TwoPool, TOKEN_COUNT}, -}; - -#[derive(Accounts)] -pub struct SwapExactOutput<'info> { - #[account( - seeds = [ - b"propeller".as_ref(), - pool_token_account_0.mint.as_ref(), - ], - bump = propeller.bump, - has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, - )] - pub propeller: Account<'info, Propeller>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: 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>, - #[account(executable, address = spl_memo::id())] - ///CHECK: memo program - pub memo: UncheckedAccount<'info>, - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, - pub swim_usd_mint: Account<'info, Mint>, -} - -pub fn handle_swap_exact_output( - ctx: Context, - maximum_input_amount: u64, - exact_output_amount: u64, - // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, - memo: &[u8], - propeller_enabled: bool, - target_chain: u16, -) -> Result> { - // is_transfer_amount_sufficient( - // &ctx.accounts.propeller, - // &ctx.accounts.token_bridge_mint, - // propeller_enabled, - // target_chain, - // exact_output_amount, - // )?; - let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactOutput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let exact_output_amounts = [exact_output_amount, 0]; - let result = - two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; - let return_val: Vec = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); - - Ok(return_val) -} - -pub fn handle_cross_chain_swap_exact_output( - ctx: Context, - maximum_input_amount: u64, - exact_output_amount: u64, - memo: &[u8], -) -> Result { - let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactOutput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let exact_output_amounts = [exact_output_amount, 0]; - let result = - two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; - let return_val: Vec = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("cross_chain_swap_exact_output return_val[0]: {:?}", return_val.get(0)); - //TODO: adding this check just for testing purposes. remove later. - require_eq!(return_val.get(0).unwrap(), &exact_output_amount); - Ok(exact_output_amount) -} - -pub fn handle_propeller_swap_exact_output( - ctx: Context, - maximum_input_amount: u64, - exact_output_amount: u64, - // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, - memo: &[u8], - max_fee: u64, -) -> Result> { - require_gt!(exact_output_amount, max_fee, PropellerError::InsufficientAmount); - let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; - let cpi_ctx = CpiContext::new( - ctx.accounts.two_pool_program.to_account_info(), - two_pool::cpi::accounts::SwapExactOutput { - pool: ctx.accounts.pool.to_account_info(), - pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), - pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), - lp_mint: ctx.accounts.lp_mint.to_account_info(), - governance_fee: ctx.accounts.governance_fee.to_account_info(), - user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), - user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), - user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), - token_program: ctx.accounts.token_program.to_account_info(), - }, - ); - let exact_output_amounts = [exact_output_amount, 0]; - let result = - two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; - let return_val: Vec = result.get(); - let memo_ix = spl_memo::build_memo(memo, &[]); - invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; - anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); - - Ok(return_val) -} +// use { +// crate::{constants::SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX, error::*, Propeller}, +// anchor_lang::{prelude::*, solana_program::program::invoke}, +// anchor_spl::token::{Mint, Token, TokenAccount}, +// two_pool::{state::TwoPool}, +// }; +// +// #[derive(Accounts)] +// pub struct SwapExactOutput<'info> { +// #[account( +// seeds = [ +// b"propeller".as_ref(), +// pool_token_account_0.mint.as_ref(), +// ], +// bump = propeller.bump, +// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, +// )] +// pub propeller: Account<'info, Propeller>, +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump, +// seeds::program = two_pool_program.key() +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: 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>, +// #[account(executable, address = spl_memo::id())] +// ///CHECK: memo program +// pub memo: UncheckedAccount<'info>, +// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, +// pub swim_usd_mint: Account<'info, Mint>, +// } +// +// pub fn handle_swap_exact_output( +// ctx: Context, +// maximum_input_amount: u64, +// exact_output_amount: u64, +// // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, +// memo: &[u8], +// _propeller_enabled: bool, +// _target_chain: u16, +// ) -> Result> { +// // is_transfer_amount_sufficient( +// // &ctx.accounts.propeller, +// // &ctx.accounts.token_bridge_mint, +// // propeller_enabled, +// // target_chain, +// // exact_output_amount, +// // )?; +// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::SwapExactOutput { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let exact_output_amounts = [exact_output_amount, 0]; +// let result = +// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; +// let return_val: Vec = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); +// +// Ok(return_val) +// } +// +// pub fn handle_cross_chain_swap_exact_output( +// ctx: Context, +// maximum_input_amount: u64, +// exact_output_amount: u64, +// memo: &[u8], +// ) -> Result { +// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::SwapExactOutput { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let exact_output_amounts = [exact_output_amount, 0]; +// let result = +// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; +// let return_val: Vec = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("cross_chain_swap_exact_output return_val[0]: {:?}", return_val.first()); +// //TODO: adding this check just for testing purposes. remove later. +// require_eq!(return_val.first().unwrap(), &exact_output_amount); +// Ok(exact_output_amount) +// } +// +// pub fn handle_propeller_swap_exact_output( +// ctx: Context, +// maximum_input_amount: u64, +// exact_output_amount: u64, +// // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, +// memo: &[u8], +// max_fee: u64, +// ) -> Result> { +// require_gt!(exact_output_amount, max_fee, PropellerError::InsufficientAmount); +// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; +// let cpi_ctx = CpiContext::new( +// ctx.accounts.two_pool_program.to_account_info(), +// two_pool::cpi::accounts::SwapExactOutput { +// pool: ctx.accounts.pool.to_account_info(), +// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), +// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), +// lp_mint: ctx.accounts.lp_mint.to_account_info(), +// governance_fee: ctx.accounts.governance_fee.to_account_info(), +// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), +// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), +// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), +// token_program: ctx.accounts.token_program.to_account_info(), +// }, +// ); +// let exact_output_amounts = [exact_output_amount, 0]; +// let result = +// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; +// let return_val: Vec = result.get(); +// let memo_ix = spl_memo::build_memo(memo, &[]); +// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; +// anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); +// +// Ok(return_val) +// } 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 898875eea..142f2b185 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 @@ -1,12 +1,10 @@ use crate::{ - get_memo_as_utf8, marginal_price_pool::*, validate_marginal_prices_pool_accounts, wormhole::SwimPayload, Fees, + get_memo_as_utf8, wormhole::SwimPayload, Fees, }; use { crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, deserialize_message_payload, error::*, fees::*, get_message_data, - get_transfer_with_payload_from_message_account, hash_vaa, instructions::fee_tracker::FeeTracker, - state::SwimPayloadMessage, Address, ChainID, ClaimData, MessageData, PayloadTransferWithPayload, PostVAAData, - PostedVAAData, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, TOKEN_COUNT, + error::*, fees::*, get_message_data, + state::SwimPayloadMessage, ClaimData, MessageData, PayloadTransferWithPayload, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, }, anchor_lang::{ prelude::*, @@ -17,13 +15,7 @@ use { token, token::{Mint, Token, TokenAccount, Transfer}, }, - byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, - num_traits::{FromPrimitive, ToPrimitive}, - // primitive_types::U256, - rust_decimal::Decimal, solana_program::program::invoke, - switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, - two_pool::{state::TwoPool, BorshDecimal}, }; #[derive(Accounts)] @@ -188,7 +180,7 @@ impl<'info> CompleteNativeWithPayload<'info> { //TODO: allow for "user" to call CompleteNativeWithPayload through this program? // dependent on if `vaa.to` is this programId for user initiated transfers - fn redeemer_check(ctx: &Context) -> bool { + fn redeemer_check(_ctx: &Context) -> bool { // if ctx.accounts.redeemer.address == ctx.accounts.message.payload.to_address() { // return ctx.accounts.redeemer.to_account_info().is_signer; // } @@ -241,7 +233,7 @@ impl<'info> CompleteNativeWithPayload<'info> { &complete_transfer_with_payload_ix, &wh_complete_native_with_payload_acct_infos, // &self.to_account_infos(), - &[&[&b"redeemer".as_ref(), &[self.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.propeller.redeemer_bump]]], )?; msg!("successfully invoked self.complete_native_with_payload()"); Ok(()) @@ -338,7 +330,7 @@ pub struct PropellerCompleteNativeWithPayload<'info> { impl<'info> PropellerCompleteNativeWithPayload<'info> { pub fn accounts(ctx: &Context) -> Result<()> { let propeller = &ctx.accounts.complete_native_with_payload.propeller; - ctx.accounts.fee_tracking.marginal_price_pool.validate(&propeller)?; + ctx.accounts.fee_tracking.marginal_price_pool.validate(propeller)?; Ok(()) } @@ -401,7 +393,7 @@ impl<'info> Fees<'info> for PropellerCompleteNativeWithPayload<'info> { to: self.complete_native_with_payload.fee_vault.to_account_info(), authority: self.complete_native_with_payload.redeemer.to_account_info(), }, - &[&[&b"redeemer".as_ref(), &[self.complete_native_with_payload.propeller.redeemer_bump]]], + &[&[(b"redeemer".as_ref()), &[self.complete_native_with_payload.propeller.redeemer_bump]]], ), fees_in_swim_usd, ) @@ -443,7 +435,7 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context { } impl<'info> Secp256k1AndVerify<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { + pub fn accounts(_ctx: &Context) -> Result<()> { Ok(()) } } @@ -54,10 +54,10 @@ pub struct VerifySignaturesData { pub fn handle_secp256k1_and_verify( ctx: Context, secp_payload: Vec, - guardian_set_index: u32, + _guardian_set_index: u32, verify_signatures_data: VerifySignaturesData, ) -> Result<()> { - let test = secp256k1_program::id(); + let _test = secp256k1_program::id(); let secp_ix = Instruction { program_id: ctx.accounts.secp256k1_program.key(), accounts: vec![], data: secp_payload }; invoke(&secp_ix, &[])?; 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 536c95749..37175e13c 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 @@ -1,16 +1,12 @@ use { crate::{ - constants::CURRENT_SWIM_PAYLOAD_VERSION, error::*, target_chain_map::TargetChainMap, wormhole::SwimPayload, - Address, Propeller, TokenBridge, Wormhole, TOKEN_COUNT, TRANSFER_NATIVE_WITH_PAYLOAD_INSTRUCTION, + constants::CURRENT_SWIM_PAYLOAD_VERSION, error::*, target_chain_map::TargetChainMap, wormhole::SwimPayload, Propeller, TokenBridge, Wormhole, TRANSFER_NATIVE_WITH_PAYLOAD_INSTRUCTION, }, anchor_lang::{ prelude::*, solana_program::{ - borsh::try_from_slice_unchecked, instruction::Instruction, - program::{get_return_data, invoke, invoke_signed}, - program_option::COption, - system_instruction::transfer, + program::{invoke_signed}, sysvar::SysvarId, }, }, @@ -18,11 +14,6 @@ use { associated_token::get_associated_token_address, token::{self, Mint, Token, TokenAccount}, }, - byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, - std::{ - io::{Cursor, ErrorKind, Read, Write}, - str, - }, }; #[derive(Accounts)] @@ -267,7 +258,7 @@ impl<'info> TransferNativeWithPayload<'info> { }, // &self.to_account_infos(), &wh_token_transfer_acct_infos, - &[&[&b"sender".as_ref(), &[self.propeller.sender_bump]]], + &[&[(b"sender".as_ref()), &[self.propeller.sender_bump]]], )?; Ok(()) } @@ -314,7 +305,7 @@ pub fn handle_cross_chain_transfer_native_with_payload( SwimPayload { swim_payload_version: CURRENT_SWIM_PAYLOAD_VERSION, owner: owner_addr, ..Default::default() }; msg!("transfer_native_with_payload swim_payload: {:?}", swim_payload); - let target_address = ctx.accounts.target_chain_map.target_address.clone(); + let target_address = ctx.accounts.target_chain_map.target_address; let transfer_with_payload_data = TransferWithPayloadData { nonce, amount, @@ -378,7 +369,7 @@ pub fn handle_propeller_transfer_native_with_payload( }; msg!("transfer_native_with_payload swim_payload: {:?}", swim_payload); - let target_address = ctx.accounts.target_chain_map.target_address.clone(); + let target_address = ctx.accounts.target_chain_map.target_address; let transfer_with_payload_data = TransferWithPayloadData { nonce, amount, diff --git a/packages/solana-contracts/programs/propeller/src/lib.rs b/packages/solana-contracts/programs/propeller/src/lib.rs index 13e4bd250..e184e950e 100644 --- a/packages/solana-contracts/programs/propeller/src/lib.rs +++ b/packages/solana-contracts/programs/propeller/src/lib.rs @@ -1,11 +1,9 @@ use { crate::two_pool_cpi::{ - add::*, init_to_swim_usd::*, - swap_exact_input::*, // remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_output::*, }, - anchor_lang::{prelude::*, solana_program}, + anchor_lang::{prelude::*}, // crate::two_pool_cpi::*, constants::TOKEN_COUNT, fees::*, @@ -22,7 +20,7 @@ mod state; mod token_bridge; mod wormhole; -use two_pool::state::TwoPool; + pub use {error::*, instructions::*}; declare_id!("9z6G41AyXk73r1E4nTv81drQPtEqupCSAnsLdGV5WGfK"); @@ -49,7 +47,7 @@ pub mod propeller { handle_prepare_governance_transition(ctx, upcoming_governance_key) } - pub fn enact_governance_transition(ctx: Context) -> Result<()> { + pub fn enact_governance_transition(_ctx: Context) -> Result<()> { Ok(()) } diff --git a/packages/solana-contracts/programs/propeller/src/state/propeller.rs b/packages/solana-contracts/programs/propeller/src/state/propeller.rs index 063508d52..130500c2f 100644 --- a/packages/solana-contracts/programs/propeller/src/state/propeller.rs +++ b/packages/solana-contracts/programs/propeller/src/state/propeller.rs @@ -1,11 +1,9 @@ use { - crate::{constants::CURRENT_SWIM_PAYLOAD_VERSION, error::PropellerError, Address, TOKEN_COUNT}, + crate::{error::PropellerError, TOKEN_COUNT}, anchor_lang::prelude::*, anchor_spl::token::TokenAccount, - byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, std::{ - io::{Cursor, ErrorKind, Read, Write}, - str::FromStr, + io::{Write}, }, two_pool::state::TwoPool, }; @@ -188,7 +186,7 @@ pub fn validate_marginal_prices_pool_accounts<'info>( #[cfg(test)] mod tests { - use super::*; + #[test] fn test_non_propeller_swim_payload() {} diff --git a/packages/solana-contracts/programs/propeller/src/token_bridge.rs b/packages/solana-contracts/programs/propeller/src/token_bridge.rs index 3f54698ea..c58f92fb1 100644 --- a/packages/solana-contracts/programs/propeller/src/token_bridge.rs +++ b/packages/solana-contracts/programs/propeller/src/token_bridge.rs @@ -1,9 +1,8 @@ use { anchor_lang::{ prelude::*, - solana_program::{declare_id, pubkey}, + solana_program::{pubkey}, }, - borsh::{BorshDeserialize, BorshSerialize}, }; // mod token_bridge { // use super::*; @@ -57,8 +56,6 @@ pub const TRANSFER_NATIVE_WITH_PAYLOAD_INSTRUCTION: u8 = 12; mod test { use { super::*, - // crate::TOKEN_BRIDGE_ID, - std::str::FromStr, }; #[test] diff --git a/packages/solana-contracts/programs/propeller/src/wormhole.rs b/packages/solana-contracts/programs/propeller/src/wormhole.rs index 6a31f6bd0..3a0d13a8c 100644 --- a/packages/solana-contracts/programs/propeller/src/wormhole.rs +++ b/packages/solana-contracts/programs/propeller/src/wormhole.rs @@ -1,5 +1,5 @@ use { - crate::{constants::CURRENT_SWIM_PAYLOAD_VERSION, Propeller, PropellerError}, + crate::{constants::CURRENT_SWIM_PAYLOAD_VERSION}, anchor_lang::{prelude::*, solana_program::pubkey}, borsh::{BorshDeserialize, BorshSerialize}, byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}, @@ -8,7 +8,6 @@ use { std::{ io::{Cursor, ErrorKind, Read, Write}, ops::{Deref, DerefMut}, - str::FromStr, }, }; @@ -94,7 +93,7 @@ pub struct BridgeConfig { /// [From womrhole repo] #[repr(transparent)] -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct PostedMessageData { pub message: MessageData, } @@ -130,12 +129,12 @@ impl Deref for PostedMessageData { type Target = PostedMessageData; fn deref(&self) -> &Self { - &self + self } } // #[derive(Debug, Default, BorshDeserialize, BorshSerialize)] -#[derive(Debug, AnchorDeserialize, AnchorSerialize, Clone, PartialEq)] +#[derive(Debug, AnchorDeserialize, AnchorSerialize, Clone, PartialEq, Eq)] pub struct MessageData { /// Header of the posted VAA pub vaa_version: u8, @@ -285,7 +284,7 @@ impl anchor_lang::AccountSerialize for MessageData {} // } // } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone)] pub struct PayloadTransferWithPayload { pub message_type: u8, /// Amount being transferred (big-endian uint256) @@ -387,7 +386,7 @@ pub fn get_message_data(vaa_account: &AccountInfo) -> Result { } pub fn get_transfer_with_payload_from_message_account(vaa_account: &AccountInfo) -> Result { - let message_data = get_message_data(&vaa_account)?; + let message_data = get_message_data(vaa_account)?; let payload_transfer_with_payload = deserialize_message_payload(&mut message_data.payload.as_slice())?; Ok(payload_transfer_with_payload) } @@ -527,7 +526,7 @@ pub fn hash_vaa(vaa: &PostVAAData) -> [u8; 32] { h.finalize().into() } -#[derive(PartialEq, Debug, Clone, Default)] +#[derive(PartialEq, Eq, Debug, Clone, Default)] pub struct SwimPayload { //TOOD: should this come from propeller? //required @@ -579,8 +578,8 @@ impl AnchorDeserialize for SwimPayload { /* optional fields */ match v.read_u8() { Ok(propeller_enabled_val) => { - let propeller_enabled = !(propeller_enabled_val == 0); - let gas_kickstart = !(v.read_u8()? == 0); + let propeller_enabled = propeller_enabled_val != 0; + let gas_kickstart = v.read_u8()? != 0; let max_fee = v.read_u64::()?; let target_token_id = v.read_u16::()?; // optional memo field @@ -609,7 +608,7 @@ impl AnchorDeserialize for SwimPayload { } Err(error) => match error.kind() { ErrorKind::UnexpectedEof => Ok(SwimPayload { swim_payload_version, owner, ..Default::default() }), - _ => return Err(error), + _ => Err(error), }, } } diff --git a/packages/solana-contracts/programs/two-pool/src/error.rs b/packages/solana-contracts/programs/two-pool/src/error.rs index 7fcd09775..9f3dc5563 100644 --- a/packages/solana-contracts/programs/two-pool/src/error.rs +++ b/packages/solana-contracts/programs/two-pool/src/error.rs @@ -84,6 +84,8 @@ pub enum PoolError { MaxDecimalsExceeded, #[msg("Conversion error")] ConversionError, + #[msg("Burn amount exceeds lp total supply")] + BurnAmountExceedsTotalSupply, } // impl From for ProgramError { diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs index a6b368a55..d6126babf 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs @@ -1,11 +1,12 @@ use { crate::{ common::{self, array_equalize, result_from_equalized, to_equalized}, - defi::*, + decimal::DecimalU64, + defi::swap::*, error::*, gen_pool_signer_seeds, get_current_ts, invariant::Invariant, - AddParams, Swap, TwoPool, TOKEN_COUNT, + AddParams, TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, anchor_spl::{ @@ -14,164 +15,6 @@ use { }, std::iter::zip, }; -// -// #[derive(Accounts)] -// pub struct AddOrRemove<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Box>, -// #[account( -// mut, -// address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), -// constraint = pool_token_account_0.key() == 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] @ PoolError::PoolTokenAccountExpected, -// )] -// pub pool_token_account_1: Box>, -// -// #[account(mut, address = pool.lp_mint_key @ PoolError::InvalidMintAccount)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint, -// address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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>, -// } -// pub fn handle_add( -// ctx: Context, -// params: AddParams, -// // input_amounts: [u64; TOKEN_COUNT], -// // minimum_mint_amount: u64, -// ) -> Result { -// let pool_state = &ctx.accounts.pool; -// require!(!pool_state.is_paused, PoolError::PoolIsPaused); -// -// let input_amounts = params.input_amounts; -// let minimum_mint_amount = params.minimum_mint_amount; -// require!(input_amounts.iter().any(|&x| x > 0), PoolError::AddRequiresAtLeastOneToken); -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// //initial add to pool must add all tokens -// if lp_total_supply == 0 { -// require!(input_amounts.iter().all(|&x| x > 0), PoolError::InitialAddRequiresAllTokens); -// } -// -// let pool = &ctx.accounts.pool; -// let user_token_accounts = [&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; -// let pool_token_accounts = [&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// let current_ts = Clock::get()?.unix_timestamp; -// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); -// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::add( -// &common::array_equalize(input_amounts, pool.token_decimal_equalizers), -// &common::array_equalize(pool_balances, pool.token_decimal_equalizers), -// pool.amp_factor.get(current_ts), -// pool.lp_fee.get(), -// pool.governance_fee.get(), -// common::to_equalized(lp_total_supply, pool.lp_decimal_equalizer), -// pool.previous_depth.into(), -// )?; -// let (mint_amount, governance_mint_amount, latest_depth) = common::result_from_equalized( -// user_amount, -// pool.lp_decimal_equalizer, -// governance_mint_amount, -// pool.lp_decimal_equalizer, -// latest_depth, -// ); -// require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); -// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// for input_amount in input_amounts.iter().take(TOKEN_COUNT) { -// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); -// if *input_amount > 0u64 { -// let pool_token_account = pool_token_account.to_account_info(); -// let user_token_account = user_token_account.to_account_info(); -// let user_transfer_authority = ctx.accounts.user_transfer_authority.to_account_info(); -// token::transfer( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// from: user_token_account.clone(), -// to: pool_token_account.clone(), -// authority: user_transfer_authority.clone(), -// }, -// ), -// *input_amount, -// )?; -// } -// } -// -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.user_lp_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// mint_amount, -// )?; -// -// if governance_mint_amount > 0 { -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.governance_fee.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// governance_mint_amount, -// )?; -// } -// -// let pool_state = &mut ctx.accounts.pool; -// pool_state.previous_depth = latest_depth; -// Ok(mint_amount) -// } #[derive(Accounts)] pub struct AddOrRemove<'info> { @@ -184,6 +27,22 @@ pub struct AddOrRemove<'info> { pub user_lp_token_account: Box>, } +impl<'info> AddOrRemove<'info> { + fn burn_user_lp_tokens(&self, burn_amount: u64) -> Result<()> { + token::burn( + CpiContext::new( + self.swap.token_program.to_account_info(), + token::Burn { + mint: self.swap.lp_mint.to_account_info(), + from: self.user_lp_token_account.to_account_info(), + authority: self.swap.user_transfer_authority.to_account_info(), + }, + ), + burn_amount, + ) + } +} + pub fn handle_add( ctx: Context, params: AddParams, @@ -203,8 +62,8 @@ pub fn handle_add( } let pool = &ctx.accounts.swap.pool; - let user_token_accounts = [&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; - let pool_token_accounts = [&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; + let user_token_accounts = &[&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; + let pool_token_accounts = &[&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; let current_ts = Clock::get()?.unix_timestamp; require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); @@ -226,57 +85,405 @@ pub fn handle_add( ); require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + let user_transfer_authority = &ctx.accounts.swap.user_transfer_authority; for input_amount in input_amounts.iter().take(TOKEN_COUNT) { let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if *input_amount > 0u64 { - let pool_token_account = pool_token_account.to_account_info(); - let user_token_account = user_token_account.to_account_info(); - let user_transfer_authority = ctx.accounts.swap.user_transfer_authority.to_account_info(); - token::transfer( - CpiContext::new( - ctx.accounts.swap.token_program.to_account_info(), - token::Transfer { - from: user_token_account.clone(), - to: pool_token_account.clone(), - authority: user_transfer_authority.clone(), - }, - ), - *input_amount, - )?; - } + ctx.accounts.swap.transfer_from_user_to_pool( + user_token_account, + user_transfer_authority, + pool_token_account, + *input_amount, + )?; + // if *input_amount > 0u64 { + // // let pool_token_account = pool_token_account.to_account_info(); + // // let user_token_account = user_token_account.to_account_info(); + // // let user_transfer_authority = ctx.accounts.swap.user_transfer_authority.to_account_info(); + // // ctx.accounts.swap.transfer_from_user_to_pool( + // // user_token_account, + // // user_transfer_authority, + // // pool_token_account, + // // *input_amount, + // // )?; + // // token::transfer( + // // CpiContext::new( + // // ctx.accounts.swap.token_program.to_account_info(), + // // token::Transfer { + // // from: user_token_account.clone(), + // // to: pool_token_account.clone(), + // // authority: user_transfer_authority.clone(), + // // }, + // // ), + // // *input_amount, + // // )?; + // } } - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.swap.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.swap.lp_mint.to_account_info(), - to: ctx.accounts.user_lp_token_account.to_account_info(), - authority: ctx.accounts.swap.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], - ), - mint_amount, + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.swap.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.swap.lp_mint.to_account_info(), + // to: ctx.accounts.user_lp_token_account.to_account_info(), + // authority: ctx.accounts.swap.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], + // ), + // mint_amount, + // )?; + + // mint user lp tokens + ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.user_lp_token_account, mint_amount)?; + + // mint governance fee + ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.swap.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.swap.lp_mint.to_account_info(), + // to: ctx.accounts.swap.governance_fee.to_account_info(), + // authority: ctx.accounts.swap.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + + // let pool_state = &mut ctx.accounts.swap.pool; + // pool_state.previous_depth = latest_depth; + ctx.accounts.swap.update_previous_depth(latest_depth)?; + Ok(mint_amount) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct RemoveExactBurnParams { + pub exact_burn_amount: u64, + pub output_token_index: u8, + pub minimum_output_amount: u64, +} + +pub fn handle_remove_exact_burn( + ctx: Context, + remove_exact_burn_params: RemoveExactBurnParams, +) -> Result { + let output_token_index = remove_exact_burn_params.output_token_index as usize; + let exact_burn_amount = remove_exact_burn_params.exact_burn_amount; + let lp_total_supply = ctx.accounts.swap.lp_mint.supply; + require!(output_token_index < TOKEN_COUNT, PoolError::InvalidRemoveExactBurnParameters); + require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveExactBurnParameters); + require_gt!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveExactBurnParameters); + + // let pool = &ctx.accounts.swap.pool; + // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; + // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; + // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; + // let _lp_mint = &ctx.accounts.lp_mint; + // let _governance_fee = &ctx.accounts.governance_fee; + // // let user_transfer_auth = &ctx.accounts.user_transfer_authority; + // let user_token_account_0 = &ctx.accounts.user_token_account_0; + // let user_token_account_1 = &ctx.accounts.user_token_account_1; + // let user_token_accounts = [user_token_account_0, user_token_account_1]; + // + // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; + + let pool = &ctx.accounts.swap.pool; + require!(!pool.is_paused, PoolError::PoolIsPaused); + let user_token_accounts = [&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; + let pool_token_accounts = [&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; + let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; + + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); + let (user_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_burn( + to_equalized(exact_burn_amount, pool.lp_decimal_equalizer), + output_token_index, + &array_equalize(pool_balances, pool.token_decimal_equalizers), + pool.amp_factor.get(current_ts), + pool.lp_fee.get(), + pool.governance_fee.get(), + to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + pool.previous_depth.into(), )?; + let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( + user_amount, + pool.token_decimal_equalizers[output_token_index], + governance_mint_amount, + pool.lp_decimal_equalizer, + latest_depth, + ); + let minimum_output_amount = remove_exact_burn_params.minimum_output_amount; + require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.swap.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.swap.lp_mint.to_account_info(), - to: ctx.accounts.swap.governance_fee.to_account_info(), - authority: ctx.accounts.swap.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], - ), - governance_mint_amount, + // let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + ctx.accounts.burn_user_lp_tokens(exact_burn_amount)?; + // token::burn( + // CpiContext::new( + // ctx.accounts.token_program.to_account_info(), + // token::Burn { + // mint: ctx.accounts.lp_mint.to_account_info(), + // from: ctx.accounts.user_lp_token_account.to_account_info(), + // authority: ctx.accounts.user_transfer_authority.to_account_info(), + // }, + // ), + // exact_burn_amount, + // )?; + + let user_output_token_account = user_token_accounts[output_token_index]; + let pool_output_token_account = pool_token_accounts[output_token_index]; + ctx.accounts.swap.transfer_from_pool_to_user( + pool_output_token_account, + user_output_token_account, + output_amount, + )?; + // token::transfer( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: pool_output_token_account.to_account_info(), + // to: user_output_token_account.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // output_amount, + // )?; + + ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; + // ctx.accounts.swap.mint_governance_fee(governance_mint_amount)?; + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.lp_mint.to_account_info(), + // to: ctx.accounts.governance_fee.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + + // let pool = &mut ctx.accounts.swap.pool; + // pool.previous_depth = latest_depth; + ctx.accounts.swap.update_previous_depth(latest_depth)?; + Ok(output_amount) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct RemoveExactOutputParams { + pub maximum_burn_amount: u64, + pub exact_output_amounts: [u64; TOKEN_COUNT], +} + +pub fn handle_remove_exact_output( + ctx: Context, + remove_exact_output_params: RemoveExactOutputParams, +) -> Result> { + let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; + let exact_output_amounts = remove_exact_output_params.exact_output_amounts; + let pool = &ctx.accounts.swap.pool; + require!(!pool.is_paused, PoolError::PoolIsPaused); + let user_token_accounts = &[&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; + let pool_token_accounts = &[&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; + let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; + + let lp_total_supply = ctx.accounts.swap.lp_mint.supply; + // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; + + require!(exact_output_amounts.iter().any(|amount| *amount > 0), PoolError::InvalidRemoveExactOutputParameters); + require_gt!(maximum_burn_amount, 0u64, PoolError::InvalidRemoveExactOutputParameters); + let are_output_amounts_valid = exact_output_amounts + .iter() + .zip(pool_balances.iter()) + .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); + require!(are_output_amounts_valid, PoolError::InvalidRemoveExactOutputParameters); + + // let pool = &ctx.accounts.pool; + // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; + // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; + // let _lp_mint = &ctx.accounts.lp_mint; + // let _governance_fee = &ctx.accounts.governance_fee; + // // let user_transfer_auth = &ctx.accounts.user_transfer_authority; + // let user_token_account_0 = &ctx.accounts.user_token_account_0; + // let user_token_account_1 = &ctx.accounts.user_token_account_1; + // let user_token_accounts = [user_token_account_0, user_token_account_1]; + // + // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; + + let current_ts = get_current_ts()?; + + let (burn_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_output( + &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), + &array_equalize(pool_balances, pool.token_decimal_equalizers), + pool.amp_factor.get(current_ts), + pool.lp_fee.get(), + pool.governance_fee.get(), + to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + pool.previous_depth.into(), + )?; + let (burn_amount, governance_mint_amount, latest_depth) = result_from_equalized( + burn_amount, + pool.lp_decimal_equalizer, + governance_mint_amount, + pool.lp_decimal_equalizer, + latest_depth, + ); + + let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; + require_gte!(maximum_burn_amount, burn_amount, PoolError::OutsideSpecifiedLimits); + require_gte!(lp_total_supply, burn_amount, PoolError::BurnAmountExceedsTotalSupply); + + let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + ctx.accounts.burn_user_lp_tokens(burn_amount)?; + // token::burn( + // CpiContext::new( + // ctx.accounts.token_program.to_account_info(), + // token::Burn { + // mint: ctx.accounts.lp_mint.to_account_info(), + // from: ctx.accounts.user_lp_token_account.to_account_info(), + // authority: ctx.accounts.user_transfer_authority.to_account_info(), + // }, + // ), + // burn_amount, + // )?; + + for i in 0..TOKEN_COUNT { + let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); + ctx.accounts.swap.transfer_from_pool_to_user( + pool_token_account, + user_token_account, + exact_output_amounts[i], )?; + // if exact_output_amounts[i] > 0 { + // // token::transfer( + // // CpiContext::new_with_signer( + // // ctx.accounts.token_program.to_account_info(), + // // token::Transfer { + // // // source + // // from: pool_token_account.to_account_info(), + // // to: user_token_account.to_account_info(), + // // authority: ctx.accounts.pool.to_account_info(), + // // }, + // // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // // ), + // // exact_output_amounts[i], + // // )?; + // } } + ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; - let pool_state = &mut ctx.accounts.swap.pool; - pool_state.previous_depth = latest_depth; - Ok(mint_amount) + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.lp_mint.to_account_info(), + // to: ctx.accounts.governance_fee.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + // let pool = &mut ctx.accounts.pool; + // pool.previous_depth = latest_depth; + ctx.accounts.swap.update_previous_depth(latest_depth)?; + Ok(exact_output_amounts.into()) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct RemoveUniformParams { + pub exact_burn_amount: u64, + pub minimum_output_amounts: [u64; TOKEN_COUNT], +} + +pub fn handle_remove_uniform( + ctx: Context, + remove_uniform_params: RemoveUniformParams, +) -> Result> { + let exact_burn_amount = remove_uniform_params.exact_burn_amount; + let minimum_output_amounts = remove_uniform_params.minimum_output_amounts; + let lp_total_supply = ctx.accounts.swap.lp_mint.supply; + require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveUniformParameters); + require_gte!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveUniformParameters); + + // let pool = &ctx.accounts.pool; + // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; + // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; + // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; + + //Note: this is the only ix that can be called even if the pool is paused. + let pool = &ctx.accounts.swap.pool; + let user_token_accounts = &[&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; + let pool_token_accounts = &[&ctx.accounts.swap.pool_token_account_0, &ctx.accounts.swap.pool_token_account_1]; + let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; + + let user_share = DecimalU64::from(exact_burn_amount) / lp_total_supply; + //u64 can store 19 decimals, previous_depth can theoretically go up to TOKEN_COUNT * u64::MAX + //hence, just to be safe, we allow for previous depth to have up to 20 decimals + //therefore we can only multiply with a number with at most 18 decimals to stay within + //the 38 max decimals range of u128 + const DECIMAL_UPSHIFT: u32 = 18; + let user_depth = (pool.previous_depth * ((user_share * 10u64.pow(DECIMAL_UPSHIFT)).trunc() as u128)) + / 10u128.pow(DECIMAL_UPSHIFT); + let latest_depth = pool.previous_depth - user_depth; + + // let user_token_account_0 = &ctx.accounts.user_token_account_0; + // let user_token_account_1 = &ctx.accounts.user_token_account_1; + // let user_token_accounts = [user_token_account_0, user_token_account_1]; + // + // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; + + let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + + let mut output_amounts = vec![]; + for i in 0..TOKEN_COUNT { + let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); + let output_amount = (pool_balances[i] * user_share).trunc(); + output_amounts.push(output_amount); + require_gte!(output_amount, minimum_output_amounts[i], PoolError::OutsideSpecifiedLimits); + ctx.accounts.swap.transfer_from_pool_to_user(&pool_token_account, &user_token_account, output_amount)?; + // token::transfer( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: pool_token_account.to_account_info(), + // to: user_token_account.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // output_amount, + // )?; + } + + ctx.accounts.burn_user_lp_tokens(exact_burn_amount)?; + // token::burn( + // CpiContext::new( + // ctx.accounts.token_program.to_account_info(), + // token::Burn { + // mint: ctx.accounts.lp_mint.to_account_info(), + // from: ctx.accounts.user_lp_token_account.to_account_info(), + // authority: ctx.accounts.user_transfer_authority.to_account_info(), + // }, + // ), + // exact_burn_amount, + // )?; + ctx.accounts.swap.update_previous_depth(latest_depth)?; + // + // let pool = &mut ctx.accounts.pool; + // pool.previous_depth = latest_depth; + + Ok(output_amounts) } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs index c32222ee3..c82e6e422 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/mod.rs @@ -1,75 +1,3 @@ -pub use add_or_remove::*; +pub use {add_or_remove::*, swap::*}; pub mod add_or_remove; - -use { - crate::{ - common::{self, array_equalize, result_from_equalized, to_equalized}, - error::*, - gen_pool_signer_seeds, get_current_ts, - invariant::Invariant, - AddParams, TwoPool, TOKEN_COUNT, - }, - anchor_lang::prelude::*, - anchor_spl::{ - associated_token::get_associated_token_address, - token::{self, Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -#[derive(Accounts)] -pub struct Swap<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Box>, - #[account( - mut, - address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]), - constraint = pool_token_account_0.key() == 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] @ PoolError::PoolTokenAccountExpected, - )] - pub pool_token_account_1: Box>, - - #[account(mut, address = pool.lp_mint_key @ PoolError::InvalidMintAccount)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint, - address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: 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>, -} +pub mod swap; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs new file mode 100644 index 000000000..d0c31254e --- /dev/null +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs @@ -0,0 +1,470 @@ +use { + crate::{ + common::{self, array_equalize, result_from_equalized, to_equalized}, + error::*, + gen_pool_signer_seeds, get_current_ts, + invariant::Invariant, + AddParams, TwoPool, TOKEN_COUNT, + }, + anchor_lang::prelude::*, + anchor_spl::{ + associated_token::get_associated_token_address, + token::{self, Mint, Token, TokenAccount}, + }, + std::iter::zip, +}; + +#[derive(Accounts)] +pub struct Swap<'info> { + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool_token_account_0.mint.as_ref(), + pool_token_account_1.mint.as_ref(), + lp_mint.key().as_ref(), + ], + bump = pool.bump + )] + pub pool: Box>, + #[account( + mut, + address = get_associated_token_address(&pool.key(), &pool.token_mint_keys[0]) @ PoolError::PoolTokenAccountExpected, + constraint = pool_token_account_0.key() == 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]) @ PoolError::PoolTokenAccountExpected, + constraint = pool_token_account_1.key() == pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, + )] + pub pool_token_account_1: Box>, + + #[account(mut, address = pool.lp_mint_key @ PoolError::InvalidMintAccount)] + pub lp_mint: Box>, + #[account( + mut, + token::mint = lp_mint, + address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, + )] + pub governance_fee: Box>, + + pub user_transfer_authority: Signer<'info>, + + #[account( + mut, + token::mint = pool_token_account_0.mint, + )] + pub user_token_account_0: Box>, + + #[account( + mut, + token::mint = pool_token_account_1.mint, + )] + pub user_token_account_1: 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> Swap<'info> { + // pub fn validate(&self) -> Result<()> { + // let pool_state = &self.pool; + // + // require_keys_eq!( + // self.pool_token_account_0.key(), + // pool_state.token_keys[0], + // PoolError::PoolTokenAccountExpected + // ); + // require_keys_eq!( + // self.pool_token_account_1.key(), + // pool_state.token_keys[1], + // PoolError::PoolTokenAccountExpected + // ); + // require_keys_eq!(self.lp_mint.key(), pool_state.lp_mint_key, PoolError::InvalidMintAccount); + // require_keys_eq!( + // self.governance_fee.key(), + // pool_state.governance_fee_key, + // PoolError::InvalidGovernanceFeeAccount + // ); + // msg!("finished accounts context check"); + // Ok(()) + // } + // pub fn accounts(ctx: &Context) -> Result<()> { + // ctx.accounts.validate() + // } + + pub fn update_previous_depth(&mut self, latest_depth: u128) -> Result<()> { + let pool_state = &mut self.pool; + pool_state.previous_depth = latest_depth; + Ok(()) + } + + pub fn transfer_from_user_to_pool( + &self, + user_token_account: &Account<'info, TokenAccount>, + user_transfer_authority: &Signer<'info>, + pool_token_account: &Account<'info, TokenAccount>, + amount: u64, + ) -> Result<()> { + if amount > 0u64 { + token::transfer( + CpiContext::new( + self.token_program.to_account_info(), + token::Transfer { + from: user_token_account.to_account_info(), + to: pool_token_account.to_account_info(), + authority: user_transfer_authority.to_account_info(), + }, + ), + amount, + )?; + } + Ok(()) + + // let seeds = gen_pool_signer_seeds( + // &self.pool.key(), + // &self.pool.token_mint_keys[0], + // &self.pool.token_mint_keys[1], + // &self.lp_mint.key(), + // ); + // let cpi_accounts = Transfer { + // from: user_token_account.to_account_info(), + // to: pool_token_account.to_account_info(), + // authority: self.user_transfer_authority.to_account_info(), + // }; + // let cpi_program = self.token_program.to_account_info(); + // let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + // token::transfer(cpi_ctx, amount)?; + // Ok(()) + } + + pub fn transfer_from_pool_to_user( + &self, + pool_token_account: &Account<'info, TokenAccount>, + user_token_account: &Account<'info, TokenAccount>, + amount: u64, + ) -> Result<()> { + if amount > 0u64 { + token::transfer( + CpiContext::new_with_signer( + self.token_program.to_account_info(), + token::Transfer { + // source + from: pool_token_account.to_account_info(), + to: user_token_account.to_account_info(), + authority: self.pool.to_account_info(), + }, + &[&gen_pool_signer_seeds!(self.pool)[..]], + ), + amount, + )?; + } + Ok(()) + } + + pub fn mint_lp_tokens(&self, recipient: &Account<'info, TokenAccount>, mint_amount: u64) -> Result<()> { + if mint_amount > 0 { + token::mint_to( + CpiContext::new_with_signer( + self.token_program.to_account_info(), + token::MintTo { + // source + mint: self.lp_mint.to_account_info(), + to: recipient.to_account_info(), + authority: self.pool.to_account_info(), + }, + &[&gen_pool_signer_seeds!(self.pool)[..]], + ), + mint_amount, + )?; + } + Ok(()) + } + + // pub fn burn_lp_tokens(&self, from: &Account<'info, TokenAccount>, authority: ) + + // pub fn mint_governance_fee(&self, governance_mint_amount: u64) -> Result<()> { + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // self.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: self.lp_mint.to_account_info(), + // to: self.governance_fee.to_account_info(), + // authority: self.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(self.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + // Ok(()) + // } +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct SwapExactInputParams { + pub exact_input_amounts: [u64; TOKEN_COUNT], + pub output_token_index: u8, + pub minimum_output_amount: u64, +} + +pub fn handle_swap_exact_input( + ctx: Context, + swap_exact_input_params: SwapExactInputParams, + // exact_input_amounts: [u64; TOKEN_COUNT], + // output_token_index: u8, + // minimum_output_amount: u64, +) -> Result { + // let output_token_index = output_token_index as usize; + let output_token_index = swap_exact_input_params.output_token_index as usize; + let exact_input_amounts = swap_exact_input_params.exact_input_amounts; + let minimum_output_amount = swap_exact_input_params.minimum_output_amount; + if exact_input_amounts.iter().all(|amount| *amount == 0) + || output_token_index >= TOKEN_COUNT + || exact_input_amounts[output_token_index] != 0 + { + return err!(PoolError::InvalidSwapExactInputParameters); + } + + let pool = &ctx.accounts.pool; + require!(!pool.is_paused, PoolError::PoolIsPaused); + + // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; + // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; + // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; + // + // let user_token_account_0 = &ctx.accounts.user_token_account_0; + // let user_token_account_1 = &ctx.accounts.user_token_account_1; + // let user_token_accounts = [user_token_account_0, user_token_account_1]; + // + // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; + + let user_token_accounts = &[&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; + let pool_token_accounts = &[&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; + let pool_balances = pool_token_accounts.map(|account| account.amount); + + let lp_total_supply = ctx.accounts.lp_mint.supply; + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); + let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_input( + &array_equalize(exact_input_amounts, pool.token_decimal_equalizers), + output_token_index, + &array_equalize(pool_balances, pool.token_decimal_equalizers), + pool.amp_factor.get(current_ts), + pool.lp_fee.get(), + pool.governance_fee.get(), + to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + pool.previous_depth.into(), + )?; + let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( + user_amount, + pool.token_decimal_equalizers[output_token_index], + governance_mint_amount, + pool.lp_decimal_equalizer, + latest_depth, + ); + + require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); + + let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + let user_transfer_auth = &ctx.accounts.user_transfer_authority; + for i in 0..TOKEN_COUNT { + let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); + // if exact_input_amounts[i] > 0 { + // token::transfer( + // CpiContext::new( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: user_token_account.to_account_info(), + // to: pool_token_account.to_account_info(), + // authority: ctx.accounts.user_transfer_authority.to_account_info(), + // }, + // ), + // exact_input_amounts[i], + // )?; + // } + ctx.accounts.transfer_from_user_to_pool( + user_token_account, + user_transfer_auth, + pool_token_account, + exact_input_amounts[i], + )?; + } + let user_output_token_account = user_token_accounts[output_token_index]; + let pool_output_token_account = pool_token_accounts[output_token_index]; + ctx.accounts.transfer_from_pool_to_user(&pool_output_token_account, &user_output_token_account, output_amount)?; + // token::transfer( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: pool_output_token_account.to_account_info(), + // to: user_output_token_account.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // output_amount, + // )?; + + ctx.accounts.mint_lp_tokens(&ctx.accounts.governance_fee, governance_mint_amount)?; + + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.lp_mint.to_account_info(), + // to: ctx.accounts.governance_fee.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + // let pool = &mut ctx.accounts.pool; + // pool.previous_depth = latest_depth; + ctx.accounts.update_previous_depth(latest_depth)?; + Ok(output_amount) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct SwapExactOutputParams { + pub maximum_input_amount: u64, + pub input_token_index: u8, + pub exact_output_amounts: [u64; TOKEN_COUNT], +} + +pub fn handle_swap_exact_output( + ctx: Context, + swap_exact_output_params: SwapExactOutputParams, +) -> Result> { + let input_token_index = swap_exact_output_params.input_token_index as usize; + let exact_output_amounts = swap_exact_output_params.exact_output_amounts; + + require!(input_token_index < TOKEN_COUNT, PoolError::InvalidSwapExactOutputParameters); + require!(exact_output_amounts[input_token_index] == 0, PoolError::InvalidSwapExactOutputParameters); + + let user_token_accounts = &[&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; + let pool_token_accounts = &[&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; + let pool_balances = pool_token_accounts.map(|account| account.amount); + let are_output_amounts_valid = exact_output_amounts.iter().any(|amount| *amount > 0); + // at least one of the output amounts should be greater than 0 + require!(are_output_amounts_valid, PoolError::InvalidSwapExactOutputParameters); + // || exact_output_amounts[input_token_index] != 0 + // if exact_output_amounts.iter().all(|amount| *amount == 0) + // || input_token_index >= TOKEN_COUNT + // || exact_output_amounts[input_token_index] != 0 + // { + // return err!(PoolError::InvalidSwapExactOutputParameters); + // } + let are_pool_balances_sufficient = exact_output_amounts + .iter() + .zip(pool_balances.iter()) + .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); + require!(are_pool_balances_sufficient, PoolError::InsufficientPoolTokenAccountBalance); + + let pool = &ctx.accounts.pool; + require!(!pool.is_paused, PoolError::PoolIsPaused); + + let user_transfer_auth = &ctx.accounts.user_transfer_authority; + + let lp_total_supply = ctx.accounts.lp_mint.supply; + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); + let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_output( + input_token_index, + &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), + &array_equalize(pool_balances, pool.token_decimal_equalizers), + pool.amp_factor.get(current_ts), + pool.lp_fee.get(), + pool.governance_fee.get(), + to_equalized(lp_total_supply, pool.lp_decimal_equalizer), + pool.previous_depth.into(), + )?; + let (input_amount, governance_mint_amount, latest_depth) = result_from_equalized( + user_amount, + pool.token_decimal_equalizers[input_token_index], + governance_mint_amount, + pool.lp_decimal_equalizer, + latest_depth, + ); + + let maximum_input_amount = swap_exact_output_params.maximum_input_amount; + require_gte!(maximum_input_amount, input_amount, PoolError::OutsideSpecifiedLimits); + + let user_input_token_account = user_token_accounts[input_token_index]; + let pool_input_token_account = pool_token_accounts[input_token_index]; + ctx.accounts.transfer_from_user_to_pool( + user_input_token_account, + user_transfer_auth, + pool_input_token_account, + input_amount, + )?; + // token::transfer( + // CpiContext::new( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: user_input_token_account.to_account_info(), + // to: pool_input_token_account.to_account_info(), + // authority: user_transfer_auth.to_account_info(), + // }, + // ), + // input_amount, + // )?; + + let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); + + for i in 0..TOKEN_COUNT { + let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); + ctx.accounts.transfer_from_pool_to_user(pool_token_account, user_token_account, exact_output_amounts[i])?; + // if exact_output_amounts[i] > 0 { + // token::transfer( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::Transfer { + // // source + // from: pool_token_account.to_account_info(), + // to: user_token_account.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // exact_output_amounts[i], + // )?; + // } + } + + ctx.accounts.mint_lp_tokens(&ctx.accounts.governance_fee, governance_mint_amount)?; + + // if governance_mint_amount > 0 { + // token::mint_to( + // CpiContext::new_with_signer( + // ctx.accounts.token_program.to_account_info(), + // token::MintTo { + // // source + // mint: ctx.accounts.lp_mint.to_account_info(), + // to: ctx.accounts.governance_fee.to_account_info(), + // authority: ctx.accounts.pool.to_account_info(), + // }, + // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], + // ), + // governance_mint_amount, + // )?; + // } + // let pool = &mut ctx.accounts.pool; + // pool.previous_depth = latest_depth; + ctx.accounts.update_previous_depth(latest_depth)?; + Ok(exact_output_amounts.into()) +} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs index a712c5f65..3c88faafb 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs @@ -1,207 +1,207 @@ -use { - crate::{ - common::{array_equalize, result_from_equalized, to_equalized}, - error::*, - gen_pool_signer_seeds, - invariant::Invariant, - TwoPool, TOKEN_COUNT, - }, - anchor_lang::prelude::*, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct RemoveExactBurnParams { - pub exact_burn_amount: u64, - pub output_token_index: u8, - pub minimum_output_amount: u64, -} - -#[derive(Accounts)] -pub struct RemoveExactBurn<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - 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> RemoveExactBurn<'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_exact_burn( - ctx: Context, - remove_exact_burn_params: RemoveExactBurnParams, -) -> Result { - let output_token_index = remove_exact_burn_params.output_token_index as usize; - let exact_burn_amount = remove_exact_burn_params.exact_burn_amount; - let lp_total_supply = ctx.accounts.lp_mint.supply; - require!(output_token_index < TOKEN_COUNT, PoolError::InvalidRemoveExactBurnParameters); - require_gt!(exact_burn_amount, 0, PoolError::InvalidRemoveExactBurnParameters); - require_gt!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveExactBurnParameters); - - let pool = &ctx.accounts.pool; - let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let _lp_mint = &ctx.accounts.lp_mint; - let _governance_fee = &ctx.accounts.governance_fee; - // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - let user_token_account_0 = &ctx.accounts.user_token_account_0; - let user_token_account_1 = &ctx.accounts.user_token_account_1; - let user_token_accounts = [user_token_account_0, user_token_account_1]; - - let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - - let current_ts = Clock::get()?.unix_timestamp; - require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); - let (user_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_burn( - to_equalized(exact_burn_amount, pool.lp_decimal_equalizer), - output_token_index, - &array_equalize(pool_balances, pool.token_decimal_equalizers), - pool.amp_factor.get(current_ts), - pool.lp_fee.get(), - pool.governance_fee.get(), - to_equalized(lp_total_supply, pool.lp_decimal_equalizer), - pool.previous_depth.into(), - )?; - let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( - user_amount, - pool.token_decimal_equalizers[output_token_index], - governance_mint_amount, - pool.lp_decimal_equalizer, - latest_depth, - ); - let minimum_output_amount = remove_exact_burn_params.minimum_output_amount; - require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); - - let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - token::burn( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Burn { - mint: ctx.accounts.lp_mint.to_account_info(), - from: ctx.accounts.user_lp_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), - }, - ), - exact_burn_amount, - )?; - - let user_output_token_account = user_token_accounts[output_token_index]; - let pool_output_token_account = pool_token_accounts[output_token_index]; - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: pool_output_token_account.to_account_info(), - to: user_output_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - output_amount, - )?; - - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.governance_fee.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - governance_mint_amount, - )?; - } - let pool = &mut ctx.accounts.pool; - pool.previous_depth = latest_depth; - Ok(output_amount) -} +// use { +// crate::{ +// common::{array_equalize, result_from_equalized, to_equalized}, +// error::*, +// gen_pool_signer_seeds, +// invariant::Invariant, +// TwoPool, TOKEN_COUNT, +// }, +// anchor_lang::prelude::*, +// anchor_spl::{ +// token, +// token::{Mint, Token, TokenAccount}, +// }, +// std::iter::zip, +// }; +// +// #[derive(AnchorSerialize, AnchorDeserialize)] +// pub struct RemoveExactBurnParams { +// pub exact_burn_amount: u64, +// pub output_token_index: u8, +// pub minimum_output_amount: u64, +// } +// +// #[derive(Accounts)] +// pub struct RemoveExactBurn<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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> RemoveExactBurn<'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_exact_burn_old( +// ctx: Context, +// remove_exact_burn_params: RemoveExactBurnParams, +// ) -> Result { +// let output_token_index = remove_exact_burn_params.output_token_index as usize; +// let exact_burn_amount = remove_exact_burn_params.exact_burn_amount; +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// require!(output_token_index < TOKEN_COUNT, PoolError::InvalidRemoveExactBurnParameters); +// require_gt!(exact_burn_amount, 0, PoolError::InvalidRemoveExactBurnParameters); +// require_gt!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveExactBurnParameters); +// +// let pool = &ctx.accounts.pool; +// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; +// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// let _lp_mint = &ctx.accounts.lp_mint; +// let _governance_fee = &ctx.accounts.governance_fee; +// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; +// let user_token_account_0 = &ctx.accounts.user_token_account_0; +// let user_token_account_1 = &ctx.accounts.user_token_account_1; +// let user_token_accounts = [user_token_account_0, user_token_account_1]; +// +// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; +// +// let current_ts = Clock::get()?.unix_timestamp; +// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); +// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_burn( +// to_equalized(exact_burn_amount, pool.lp_decimal_equalizer), +// output_token_index, +// &array_equalize(pool_balances, pool.token_decimal_equalizers), +// pool.amp_factor.get(current_ts), +// pool.lp_fee.get(), +// pool.governance_fee.get(), +// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), +// pool.previous_depth.into(), +// )?; +// let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( +// user_amount, +// pool.token_decimal_equalizers[output_token_index], +// governance_mint_amount, +// pool.lp_decimal_equalizer, +// latest_depth, +// ); +// let minimum_output_amount = remove_exact_burn_params.minimum_output_amount; +// require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); +// +// let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// token::burn( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Burn { +// mint: ctx.accounts.lp_mint.to_account_info(), +// from: ctx.accounts.user_lp_token_account.to_account_info(), +// authority: ctx.accounts.user_transfer_authority.to_account_info(), +// }, +// ), +// exact_burn_amount, +// )?; +// +// let user_output_token_account = user_token_accounts[output_token_index]; +// let pool_output_token_account = pool_token_accounts[output_token_index]; +// token::transfer( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: pool_output_token_account.to_account_info(), +// to: user_output_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// output_amount, +// )?; +// +// if governance_mint_amount > 0 { +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.governance_fee.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// governance_mint_amount, +// )?; +// } +// let pool = &mut ctx.accounts.pool; +// pool.previous_depth = latest_depth; +// Ok(output_amount) +// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs index 4ce3e3b8a..b8d9d906b 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs @@ -1,214 +1,214 @@ -use { - crate::{ - common::{array_equalize, result_from_equalized, to_equalized}, - error::*, - gen_pool_signer_seeds, get_current_ts, - invariant::Invariant, - TwoPool, TOKEN_COUNT, - }, - anchor_lang::prelude::*, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct RemoveExactOutputParams { - pub maximum_burn_amount: u64, - pub exact_output_amounts: [u64; TOKEN_COUNT], -} - -#[derive(Accounts)] -pub struct RemoveExactOutput<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - 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> RemoveExactOutput<'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_exact_output( - ctx: Context, - remove_exact_output_params: RemoveExactOutputParams, -) -> Result> { - let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; - let exact_output_amounts = remove_exact_output_params.exact_output_amounts; - let lp_total_supply = ctx.accounts.lp_mint.supply; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - - require!(exact_output_amounts.iter().any(|amount| *amount > 0), PoolError::InvalidRemoveExactOutputParameters); - require_gt!(maximum_burn_amount, 0u64, PoolError::InvalidRemoveExactOutputParameters); - let are_output_amounts_valid = exact_output_amounts - .iter() - .zip(pool_balances.iter()) - .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); - require!(are_output_amounts_valid, PoolError::InvalidRemoveExactOutputParameters); - - let pool = &ctx.accounts.pool; - let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let _lp_mint = &ctx.accounts.lp_mint; - let _governance_fee = &ctx.accounts.governance_fee; - // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - let user_token_account_0 = &ctx.accounts.user_token_account_0; - let user_token_account_1 = &ctx.accounts.user_token_account_1; - let user_token_accounts = [user_token_account_0, user_token_account_1]; - - let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - - let current_ts = get_current_ts()?; - - let (burn_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_output( - &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), - &array_equalize(pool_balances, pool.token_decimal_equalizers), - pool.amp_factor.get(current_ts), - pool.lp_fee.get(), - pool.governance_fee.get(), - to_equalized(lp_total_supply, pool.lp_decimal_equalizer), - pool.previous_depth.into(), - )?; - let (burn_amount, governance_mint_amount, latest_depth) = result_from_equalized( - burn_amount, - pool.lp_decimal_equalizer, - governance_mint_amount, - pool.lp_decimal_equalizer, - latest_depth, - ); - - let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; - require_gte!(maximum_burn_amount, burn_amount, PoolError::OutsideSpecifiedLimits); - - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - token::burn( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Burn { - mint: ctx.accounts.lp_mint.to_account_info(), - from: ctx.accounts.user_lp_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), - }, - ), - burn_amount, - )?; - - for i in 0..TOKEN_COUNT { - let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if exact_output_amounts[i] > 0 { - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: pool_token_account.to_account_info(), - to: user_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - exact_output_amounts[i], - )?; - } - } - - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.governance_fee.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - governance_mint_amount, - )?; - } - let pool = &mut ctx.accounts.pool; - pool.previous_depth = latest_depth; - Ok(exact_output_amounts.into()) -} +// use { +// crate::{ +// common::{array_equalize, result_from_equalized, to_equalized}, +// error::*, +// gen_pool_signer_seeds, get_current_ts, +// invariant::Invariant, +// TwoPool, TOKEN_COUNT, +// }, +// anchor_lang::prelude::*, +// anchor_spl::{ +// token, +// token::{Mint, Token, TokenAccount}, +// }, +// std::iter::zip, +// }; +// +// #[derive(AnchorSerialize, AnchorDeserialize)] +// pub struct RemoveExactOutputParams { +// pub maximum_burn_amount: u64, +// pub exact_output_amounts: [u64; TOKEN_COUNT], +// } +// +// #[derive(Accounts)] +// pub struct RemoveExactOutput<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// 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> RemoveExactOutput<'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_exact_output( +// ctx: Context, +// remove_exact_output_params: RemoveExactOutputParams, +// ) -> Result> { +// let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; +// let exact_output_amounts = remove_exact_output_params.exact_output_amounts; +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// +// require!(exact_output_amounts.iter().any(|amount| *amount > 0), PoolError::InvalidRemoveExactOutputParameters); +// require_gt!(maximum_burn_amount, 0u64, PoolError::InvalidRemoveExactOutputParameters); +// let are_output_amounts_valid = exact_output_amounts +// .iter() +// .zip(pool_balances.iter()) +// .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); +// require!(are_output_amounts_valid, PoolError::InvalidRemoveExactOutputParameters); +// +// let pool = &ctx.accounts.pool; +// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; +// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; +// let _lp_mint = &ctx.accounts.lp_mint; +// let _governance_fee = &ctx.accounts.governance_fee; +// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; +// let user_token_account_0 = &ctx.accounts.user_token_account_0; +// let user_token_account_1 = &ctx.accounts.user_token_account_1; +// let user_token_accounts = [user_token_account_0, user_token_account_1]; +// +// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; +// +// let current_ts = get_current_ts()?; +// +// let (burn_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_output( +// &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), +// &array_equalize(pool_balances, pool.token_decimal_equalizers), +// pool.amp_factor.get(current_ts), +// pool.lp_fee.get(), +// pool.governance_fee.get(), +// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), +// pool.previous_depth.into(), +// )?; +// let (burn_amount, governance_mint_amount, latest_depth) = result_from_equalized( +// burn_amount, +// pool.lp_decimal_equalizer, +// governance_mint_amount, +// pool.lp_decimal_equalizer, +// latest_depth, +// ); +// +// let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; +// require_gte!(maximum_burn_amount, burn_amount, PoolError::OutsideSpecifiedLimits); +// +// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// token::burn( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Burn { +// mint: ctx.accounts.lp_mint.to_account_info(), +// from: ctx.accounts.user_lp_token_account.to_account_info(), +// authority: ctx.accounts.user_transfer_authority.to_account_info(), +// }, +// ), +// burn_amount, +// )?; +// +// for i in 0..TOKEN_COUNT { +// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); +// if exact_output_amounts[i] > 0 { +// token::transfer( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: pool_token_account.to_account_info(), +// to: user_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// exact_output_amounts[i], +// )?; +// } +// } +// +// if governance_mint_amount > 0 { +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.governance_fee.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// governance_mint_amount, +// )?; +// } +// let pool = &mut ctx.accounts.pool; +// pool.previous_depth = latest_depth; +// Ok(exact_output_amounts.into()) +// } 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 75def334b..70de6c722 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,147 +1,147 @@ -use { - crate::{error::*, gen_pool_signer_seeds, DecimalU64, TwoPool, TOKEN_COUNT}, - anchor_lang::prelude::*, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct RemoveUniformParams { - pub exact_burn_amount: u64, - pub minimum_output_amounts: [u64; TOKEN_COUNT], -} - -#[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 = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Box>, - #[account( - mut, - address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, - )] - pub pool_token_account_1: Box>, - #[account( - mut, - address = pool.lp_mint_key @ PoolError::InvalidMintAccount, - )] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint, - address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - pub user_lp_token_account: Box>, - - pub token_program: Program<'info, Token>, -} - -pub fn handle_remove_uniform( - ctx: Context, - remove_uniform_params: RemoveUniformParams, -) -> Result> { - let exact_burn_amount = remove_uniform_params.exact_burn_amount; - let minimum_output_amounts = remove_uniform_params.minimum_output_amounts; - let lp_total_supply = ctx.accounts.lp_mint.supply; - require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveUniformParameters); - require_gte!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveUniformParameters); - - let pool = &ctx.accounts.pool; - let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - - let user_share = DecimalU64::from(exact_burn_amount) / lp_total_supply; - //u64 can store 19 decimals, previous_depth can theoretically go up to TOKEN_COUNT * u64::MAX - //hence, just to be safe, we allow for previous depth to have up to 20 decimals - //therefore we can only multiply with a number with at most 18 decimals to stay within - //the 38 max decimals range of u128 - const DECIMAL_UPSHIFT: u32 = 18; - let user_depth = (pool.previous_depth * ((user_share * 10u64.pow(DECIMAL_UPSHIFT)).trunc() as u128)) - / 10u128.pow(DECIMAL_UPSHIFT); - let latest_depth = pool.previous_depth - user_depth; - - let user_token_account_0 = &ctx.accounts.user_token_account_0; - let user_token_account_1 = &ctx.accounts.user_token_account_1; - let user_token_accounts = [user_token_account_0, user_token_account_1]; - - let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - - let mut output_amounts = vec![]; - for i in 0..TOKEN_COUNT { - let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - let output_amount = (pool_balances[i] * user_share).trunc(); - output_amounts.push(output_amount); - require_gte!(output_amount, minimum_output_amounts[i], PoolError::OutsideSpecifiedLimits); - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: pool_token_account.to_account_info(), - to: user_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - output_amount, - )?; - } - - token::burn( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Burn { - mint: ctx.accounts.lp_mint.to_account_info(), - from: ctx.accounts.user_lp_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), - }, - ), - exact_burn_amount, - )?; - - let pool = &mut ctx.accounts.pool; - pool.previous_depth = latest_depth; - - Ok(output_amounts) -} +// use { +// crate::{error::*, gen_pool_signer_seeds, DecimalU64, TwoPool, TOKEN_COUNT}, +// anchor_lang::prelude::*, +// anchor_spl::{ +// token, +// token::{Mint, Token, TokenAccount}, +// }, +// std::iter::zip, +// }; +// +// #[derive(AnchorSerialize, AnchorDeserialize)] +// pub struct RemoveUniformParams { +// pub exact_burn_amount: u64, +// pub minimum_output_amounts: [u64; TOKEN_COUNT], +// } +// +// #[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 = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Box>, +// #[account( +// mut, +// address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, +// )] +// pub pool_token_account_1: Box>, +// #[account( +// mut, +// address = pool.lp_mint_key @ PoolError::InvalidMintAccount, +// )] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint, +// address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// #[account( +// mut, +// token::mint = lp_mint, +// )] +// pub user_lp_token_account: Box>, +// +// pub token_program: Program<'info, Token>, +// } +// +// pub fn handle_remove_uniform( +// ctx: Context, +// remove_uniform_params: RemoveUniformParams, +// ) -> Result> { +// let exact_burn_amount = remove_uniform_params.exact_burn_amount; +// let minimum_output_amounts = remove_uniform_params.minimum_output_amounts; +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveUniformParameters); +// require_gte!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveUniformParameters); +// +// let pool = &ctx.accounts.pool; +// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; +// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// +// let user_share = DecimalU64::from(exact_burn_amount) / lp_total_supply; +// //u64 can store 19 decimals, previous_depth can theoretically go up to TOKEN_COUNT * u64::MAX +// //hence, just to be safe, we allow for previous depth to have up to 20 decimals +// //therefore we can only multiply with a number with at most 18 decimals to stay within +// //the 38 max decimals range of u128 +// const DECIMAL_UPSHIFT: u32 = 18; +// let user_depth = (pool.previous_depth * ((user_share * 10u64.pow(DECIMAL_UPSHIFT)).trunc() as u128)) +// / 10u128.pow(DECIMAL_UPSHIFT); +// let latest_depth = pool.previous_depth - user_depth; +// +// let user_token_account_0 = &ctx.accounts.user_token_account_0; +// let user_token_account_1 = &ctx.accounts.user_token_account_1; +// let user_token_accounts = [user_token_account_0, user_token_account_1]; +// +// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; +// +// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// +// let mut output_amounts = vec![]; +// for i in 0..TOKEN_COUNT { +// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); +// let output_amount = (pool_balances[i] * user_share).trunc(); +// output_amounts.push(output_amount); +// require_gte!(output_amount, minimum_output_amounts[i], PoolError::OutsideSpecifiedLimits); +// token::transfer( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: pool_token_account.to_account_info(), +// to: user_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// output_amount, +// )?; +// } +// +// token::burn( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Burn { +// mint: ctx.accounts.lp_mint.to_account_info(), +// from: ctx.accounts.user_lp_token_account.to_account_info(), +// authority: ctx.accounts.user_transfer_authority.to_account_info(), +// }, +// ), +// exact_burn_amount, +// )?; +// +// let pool = &mut ctx.accounts.pool; +// pool.previous_depth = latest_depth; +// +// Ok(output_amounts) +// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs index f91f13e1f..4431688a4 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs @@ -1,222 +1,222 @@ -use { - crate::{ - common::{array_equalize, result_from_equalized, to_equalized}, - error::*, - gen_pool_signer_seeds, - invariant::Invariant, - TwoPool, TOKEN_COUNT, - }, - anchor_lang::prelude::*, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -/// Swaps in the exact specified amounts for -/// at least `minimum_out_amount` of the output_token specified -/// by output_token_index -/// -/// Accounts expected by this instruction: -/// 0. `[w]` The pool state account -/// 1. `[]` pool authority -/// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts -/// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint -/// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account -/// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account -/// 6. ..6 + TOKEN_COUNT `[w]` user token accounts -#[derive(Accounts)] -pub struct SwapExactInput<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - pub token_program: Program<'info, Token>, -} - -impl<'info> SwapExactInput<'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(()) - } -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct SwapExactInputParams { - pub exact_input_amounts: [u64; TOKEN_COUNT], - pub output_token_index: u8, - pub minimum_output_amount: u64, -} - -pub fn handle_swap_exact_input( - ctx: Context, - swap_exact_input_params: SwapExactInputParams, - // exact_input_amounts: [u64; TOKEN_COUNT], - // output_token_index: u8, - // minimum_output_amount: u64, -) -> Result { - // let output_token_index = output_token_index as usize; - let output_token_index = swap_exact_input_params.output_token_index as usize; - let exact_input_amounts = swap_exact_input_params.exact_input_amounts; - let minimum_output_amount = swap_exact_input_params.minimum_output_amount; - if exact_input_amounts.iter().all(|amount| *amount == 0) - || output_token_index >= TOKEN_COUNT - || exact_input_amounts[output_token_index] != 0 - { - return err!(PoolError::InvalidSwapExactInputParameters); - } - - let pool = &ctx.accounts.pool; - let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let _lp_mint = &ctx.accounts.lp_mint; - let _governance_fee = &ctx.accounts.governance_fee; - // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - let user_token_account_0 = &ctx.accounts.user_token_account_0; - let user_token_account_1 = &ctx.accounts.user_token_account_1; - let user_token_accounts = [user_token_account_0, user_token_account_1]; - - let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - - let lp_total_supply = ctx.accounts.lp_mint.supply; - let current_ts = Clock::get()?.unix_timestamp; - require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); - let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_input( - &array_equalize(exact_input_amounts, pool.token_decimal_equalizers), - output_token_index, - &array_equalize(pool_balances, pool.token_decimal_equalizers), - pool.amp_factor.get(current_ts), - pool.lp_fee.get(), - pool.governance_fee.get(), - to_equalized(lp_total_supply, pool.lp_decimal_equalizer), - pool.previous_depth.into(), - )?; - let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( - user_amount, - pool.token_decimal_equalizers[output_token_index], - governance_mint_amount, - pool.lp_decimal_equalizer, - latest_depth, - ); - - require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); - - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - for i in 0..TOKEN_COUNT { - let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if exact_input_amounts[i] > 0 { - token::transfer( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: user_token_account.to_account_info(), - to: pool_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), - }, - ), - exact_input_amounts[i], - )?; - } - } - let user_output_token_account = user_token_accounts[output_token_index]; - let pool_output_token_account = pool_token_accounts[output_token_index]; - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: pool_output_token_account.to_account_info(), - to: user_output_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - output_amount, - )?; - - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.governance_fee.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - governance_mint_amount, - )?; - } - let pool = &mut ctx.accounts.pool; - pool.previous_depth = latest_depth; - Ok(output_amount) -} +// use { +// crate::{ +// common::{array_equalize, result_from_equalized, to_equalized}, +// error::*, +// gen_pool_signer_seeds, +// invariant::Invariant, +// TwoPool, TOKEN_COUNT, +// }, +// anchor_lang::prelude::*, +// anchor_spl::{ +// token, +// token::{Mint, Token, TokenAccount}, +// }, +// std::iter::zip, +// }; +// +// /// Swaps in the exact specified amounts for +// /// at least `minimum_out_amount` of the output_token specified +// /// by output_token_index +// /// +// /// Accounts expected by this instruction: +// /// 0. `[w]` The pool state account +// /// 1. `[]` pool authority +// /// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts +// /// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint +// /// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account +// /// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account +// /// 6. ..6 + TOKEN_COUNT `[w]` user token accounts +// #[derive(Accounts)] +// pub struct SwapExactInput<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: Box>, +// +// pub token_program: Program<'info, Token>, +// } +// +// impl<'info> SwapExactInput<'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(()) +// } +// } +// +// #[derive(AnchorSerialize, AnchorDeserialize)] +// pub struct SwapExactInputParams { +// pub exact_input_amounts: [u64; TOKEN_COUNT], +// pub output_token_index: u8, +// pub minimum_output_amount: u64, +// } +// +// pub fn handle_swap_exact_input( +// ctx: Context, +// swap_exact_input_params: SwapExactInputParams, +// // exact_input_amounts: [u64; TOKEN_COUNT], +// // output_token_index: u8, +// // minimum_output_amount: u64, +// ) -> Result { +// // let output_token_index = output_token_index as usize; +// let output_token_index = swap_exact_input_params.output_token_index as usize; +// let exact_input_amounts = swap_exact_input_params.exact_input_amounts; +// let minimum_output_amount = swap_exact_input_params.minimum_output_amount; +// if exact_input_amounts.iter().all(|amount| *amount == 0) +// || output_token_index >= TOKEN_COUNT +// || exact_input_amounts[output_token_index] != 0 +// { +// return err!(PoolError::InvalidSwapExactInputParameters); +// } +// +// let pool = &ctx.accounts.pool; +// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; +// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// let _lp_mint = &ctx.accounts.lp_mint; +// let _governance_fee = &ctx.accounts.governance_fee; +// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; +// let user_token_account_0 = &ctx.accounts.user_token_account_0; +// let user_token_account_1 = &ctx.accounts.user_token_account_1; +// let user_token_accounts = [user_token_account_0, user_token_account_1]; +// +// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; +// +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// let current_ts = Clock::get()?.unix_timestamp; +// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); +// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_input( +// &array_equalize(exact_input_amounts, pool.token_decimal_equalizers), +// output_token_index, +// &array_equalize(pool_balances, pool.token_decimal_equalizers), +// pool.amp_factor.get(current_ts), +// pool.lp_fee.get(), +// pool.governance_fee.get(), +// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), +// pool.previous_depth.into(), +// )?; +// let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( +// user_amount, +// pool.token_decimal_equalizers[output_token_index], +// governance_mint_amount, +// pool.lp_decimal_equalizer, +// latest_depth, +// ); +// +// require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); +// +// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// for i in 0..TOKEN_COUNT { +// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); +// if exact_input_amounts[i] > 0 { +// token::transfer( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: user_token_account.to_account_info(), +// to: pool_token_account.to_account_info(), +// authority: ctx.accounts.user_transfer_authority.to_account_info(), +// }, +// ), +// exact_input_amounts[i], +// )?; +// } +// } +// let user_output_token_account = user_token_accounts[output_token_index]; +// let pool_output_token_account = pool_token_accounts[output_token_index]; +// token::transfer( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: pool_output_token_account.to_account_info(), +// to: user_output_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// output_amount, +// )?; +// +// if governance_mint_amount > 0 { +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.governance_fee.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// governance_mint_amount, +// )?; +// } +// let pool = &mut ctx.accounts.pool; +// pool.previous_depth = latest_depth; +// Ok(output_amount) +// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs index d749980b9..446163d26 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs @@ -1,231 +1,231 @@ -use { - crate::{ - common::{array_equalize, result_from_equalized, to_equalized}, - error::*, - gen_pool_signer_seeds, - invariant::Invariant, - TwoPool, TOKEN_COUNT, - }, - anchor_lang::prelude::*, - anchor_spl::{ - token, - token::{Mint, Token, TokenAccount}, - }, - std::iter::zip, -}; - -/// Swaps in the exact specified amounts for -/// at least `minimum_out_amount` of the output_token specified -/// by output_token_index -/// -/// Accounts expected by this instruction: -/// 0. `[w]` The pool state account -/// 1. `[]` pool authority -/// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts -/// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint -/// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account -/// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account -/// 6. ..6 + TOKEN_COUNT `[w]` user token accounts -#[derive(Accounts)] -pub struct SwapExactOutput<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - #[account( - mut, - token::mint = pool.token_mint_keys[0], - token::authority = pool, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - token::mint = pool.token_mint_keys[1], - token::authority = pool, - )] - pub pool_token_account_1: Box>, - #[account(mut)] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint - )] - pub governance_fee: Box>, - - pub user_transfer_authority: Signer<'info>, - - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: 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> SwapExactOutput<'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 - ); - msg!("finished accounts context check"); - Ok(()) - } -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct SwapExactOutputParams { - pub maximum_input_amount: u64, - pub input_token_index: u8, - pub exact_output_amounts: [u64; TOKEN_COUNT], -} - -pub fn handle_swap_exact_output( - ctx: Context, - swap_exact_output_params: SwapExactOutputParams, -) -> Result> { - let input_token_index = swap_exact_output_params.input_token_index as usize; - let exact_output_amounts = swap_exact_output_params.exact_output_amounts; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let are_output_amounts_valid = exact_output_amounts.iter().any(|amount| *amount == 0); - require!(are_output_amounts_valid, PoolError::InvalidSwapExactOutputParameters); - require!(input_token_index < TOKEN_COUNT, PoolError::InvalidSwapExactOutputParameters); - require!(exact_output_amounts[input_token_index] == 0, PoolError::InvalidSwapExactOutputParameters); - // || exact_output_amounts[input_token_index] != 0 - // if exact_output_amounts.iter().all(|amount| *amount == 0) - // || input_token_index >= TOKEN_COUNT - // || exact_output_amounts[input_token_index] != 0 - // { - // return err!(PoolError::InvalidSwapExactOutputParameters); - // } - let are_pool_balances_sufficient = exact_output_amounts - .iter() - .zip(pool_balances.iter()) - .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); - require!(are_pool_balances_sufficient, PoolError::InsufficientPoolTokenAccountBalance); - - let pool = &ctx.accounts.pool; - let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let _lp_mint = &ctx.accounts.lp_mint; - let _governance_fee = &ctx.accounts.governance_fee; - // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - let user_token_account_0 = &ctx.accounts.user_token_account_0; - let user_token_account_1 = &ctx.accounts.user_token_account_1; - let user_token_accounts = [user_token_account_0, user_token_account_1]; - - let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - - let lp_total_supply = ctx.accounts.lp_mint.supply; - let current_ts = Clock::get()?.unix_timestamp; - require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); - let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_output( - input_token_index, - &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), - &array_equalize(pool_balances, pool.token_decimal_equalizers), - pool.amp_factor.get(current_ts), - pool.lp_fee.get(), - pool.governance_fee.get(), - to_equalized(lp_total_supply, pool.lp_decimal_equalizer), - pool.previous_depth.into(), - )?; - let (input_amount, governance_mint_amount, latest_depth) = result_from_equalized( - user_amount, - pool.token_decimal_equalizers[input_token_index], - governance_mint_amount, - pool.lp_decimal_equalizer, - latest_depth, - ); - - let maximum_input_amount = swap_exact_output_params.maximum_input_amount; - require_gte!(maximum_input_amount, input_amount, PoolError::OutsideSpecifiedLimits); - - let user_input_token_account = user_token_accounts[input_token_index]; - let pool_input_token_account = pool_token_accounts[input_token_index]; - token::transfer( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: user_input_token_account.to_account_info(), - to: pool_input_token_account.to_account_info(), - authority: ctx.accounts.user_transfer_authority.to_account_info(), - }, - ), - input_amount, - )?; - - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - - for i in 0..TOKEN_COUNT { - let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if exact_output_amounts[i] > 0 { - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - // source - from: pool_token_account.to_account_info(), - to: user_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - exact_output_amounts[i], - )?; - } - } - - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.governance_fee.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - governance_mint_amount, - )?; - } - let pool = &mut ctx.accounts.pool; - pool.previous_depth = latest_depth; - Ok(exact_output_amounts.into()) -} +// use { +// crate::{ +// common::{array_equalize, result_from_equalized, to_equalized}, +// error::*, +// gen_pool_signer_seeds, +// invariant::Invariant, +// TwoPool, TOKEN_COUNT, +// }, +// anchor_lang::prelude::*, +// anchor_spl::{ +// token, +// token::{Mint, Token, TokenAccount}, +// }, +// std::iter::zip, +// }; +// +// /// Swaps in the exact specified amounts for +// /// at least `minimum_out_amount` of the output_token specified +// /// by output_token_index +// /// +// /// Accounts expected by this instruction: +// /// 0. `[w]` The pool state account +// /// 1. `[]` pool authority +// /// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts +// /// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint +// /// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account +// /// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account +// /// 6. ..6 + TOKEN_COUNT `[w]` user token accounts +// #[derive(Accounts)] +// pub struct SwapExactOutput<'info> { +// #[account( +// mut, +// seeds = [ +// b"two_pool".as_ref(), +// pool_token_account_0.mint.as_ref(), +// pool_token_account_1.mint.as_ref(), +// lp_mint.key().as_ref(), +// ], +// bump = pool.bump +// )] +// pub pool: Account<'info, TwoPool>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[0], +// token::authority = pool, +// )] +// pub pool_token_account_0: Box>, +// #[account( +// mut, +// token::mint = pool.token_mint_keys[1], +// token::authority = pool, +// )] +// pub pool_token_account_1: Box>, +// #[account(mut)] +// pub lp_mint: Box>, +// #[account( +// mut, +// token::mint = lp_mint +// )] +// pub governance_fee: Box>, +// +// pub user_transfer_authority: Signer<'info>, +// +// #[account( +// mut, +// token::mint = pool_token_account_0.mint, +// )] +// pub user_token_account_0: Box>, +// +// #[account( +// mut, +// token::mint = pool_token_account_1.mint, +// )] +// pub user_token_account_1: 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> SwapExactOutput<'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 +// ); +// msg!("finished accounts context check"); +// Ok(()) +// } +// } +// +// #[derive(AnchorSerialize, AnchorDeserialize)] +// pub struct SwapExactOutputParams { +// pub maximum_input_amount: u64, +// pub input_token_index: u8, +// pub exact_output_amounts: [u64; TOKEN_COUNT], +// } +// +// pub fn handle_swap_exact_output( +// ctx: Context, +// swap_exact_output_params: SwapExactOutputParams, +// ) -> Result> { +// let input_token_index = swap_exact_output_params.input_token_index as usize; +// let exact_output_amounts = swap_exact_output_params.exact_output_amounts; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// let are_output_amounts_valid = exact_output_amounts.iter().any(|amount| *amount == 0); +// require!(are_output_amounts_valid, PoolError::InvalidSwapExactOutputParameters); +// require!(input_token_index < TOKEN_COUNT, PoolError::InvalidSwapExactOutputParameters); +// require!(exact_output_amounts[input_token_index] == 0, PoolError::InvalidSwapExactOutputParameters); +// // || exact_output_amounts[input_token_index] != 0 +// // if exact_output_amounts.iter().all(|amount| *amount == 0) +// // || input_token_index >= TOKEN_COUNT +// // || exact_output_amounts[input_token_index] != 0 +// // { +// // return err!(PoolError::InvalidSwapExactOutputParameters); +// // } +// let are_pool_balances_sufficient = exact_output_amounts +// .iter() +// .zip(pool_balances.iter()) +// .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); +// require!(are_pool_balances_sufficient, PoolError::InsufficientPoolTokenAccountBalance); +// +// let pool = &ctx.accounts.pool; +// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; +// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; +// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; +// let _lp_mint = &ctx.accounts.lp_mint; +// let _governance_fee = &ctx.accounts.governance_fee; +// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; +// let user_token_account_0 = &ctx.accounts.user_token_account_0; +// let user_token_account_1 = &ctx.accounts.user_token_account_1; +// let user_token_accounts = [user_token_account_0, user_token_account_1]; +// +// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; +// +// let lp_total_supply = ctx.accounts.lp_mint.supply; +// let current_ts = Clock::get()?.unix_timestamp; +// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); +// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_output( +// input_token_index, +// &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), +// &array_equalize(pool_balances, pool.token_decimal_equalizers), +// pool.amp_factor.get(current_ts), +// pool.lp_fee.get(), +// pool.governance_fee.get(), +// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), +// pool.previous_depth.into(), +// )?; +// let (input_amount, governance_mint_amount, latest_depth) = result_from_equalized( +// user_amount, +// pool.token_decimal_equalizers[input_token_index], +// governance_mint_amount, +// pool.lp_decimal_equalizer, +// latest_depth, +// ); +// +// let maximum_input_amount = swap_exact_output_params.maximum_input_amount; +// require_gte!(maximum_input_amount, input_amount, PoolError::OutsideSpecifiedLimits); +// +// let user_input_token_account = user_token_accounts[input_token_index]; +// let pool_input_token_account = pool_token_accounts[input_token_index]; +// token::transfer( +// CpiContext::new( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: user_input_token_account.to_account_info(), +// to: pool_input_token_account.to_account_info(), +// authority: ctx.accounts.user_transfer_authority.to_account_info(), +// }, +// ), +// input_amount, +// )?; +// +// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); +// +// for i in 0..TOKEN_COUNT { +// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); +// if exact_output_amounts[i] > 0 { +// token::transfer( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::Transfer { +// // source +// from: pool_token_account.to_account_info(), +// to: user_token_account.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// exact_output_amounts[i], +// )?; +// } +// } +// +// if governance_mint_amount > 0 { +// token::mint_to( +// CpiContext::new_with_signer( +// ctx.accounts.token_program.to_account_info(), +// token::MintTo { +// // source +// mint: ctx.accounts.lp_mint.to_account_info(), +// to: ctx.accounts.governance_fee.to_account_info(), +// authority: ctx.accounts.pool.to_account_info(), +// }, +// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], +// ), +// governance_mint_amount, +// )?; +// } +// let pool = &mut ctx.accounts.pool; +// pool.previous_depth = latest_depth; +// Ok(exact_output_amounts.into()) +// } diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index e95d02d3a..f4a61a50d 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -60,7 +60,7 @@ solana_security_txt::security_txt! { #[program] pub mod two_pool { - use {super::*, crate::instructions::defi::add_or_remove::AddOrRemove}; + use super::*; #[access_control(Initialize::accounts(&ctx))] pub fn initialize( @@ -84,15 +84,32 @@ pub mod two_pool { // // handle_add(ctx, input_amounts, minimum_mint_amount) // } + // #[access_control(AddOrRemove::accounts(&ctx))] pub fn add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { let params = AddParams { input_amounts, minimum_mint_amount }; handle_add(ctx, params) // handle_add(ctx, input_amounts, minimum_mint_amount) } - #[access_control(SwapExactInput::accounts(&ctx))] + // #[access_control(SwapExactInput::accounts(&ctx))] + // pub fn swap_exact_input( + // ctx: Context, + // exact_input_amounts: [u64; TOKEN_COUNT], + // output_token_index: u8, + // minimum_output_amount: u64, + // // params: SwapExactInputParams, + // ) -> Result { + // let params = SwapExactInputParams { exact_input_amounts, output_token_index, minimum_output_amount }; + // handle_swap_exact_input(ctx, params) + // // let output_token_index = params.output_token_index as usize; + // // let exact_input_amounts = params.exact_input_amounts; + // // let minimum_output_amount = params.minimum_output_amount; + // // handle_swap_exact_input(ctx, params) + // } + + // #[access_control(ctx.accounts.validate())] pub fn swap_exact_input( - ctx: Context, + ctx: Context, exact_input_amounts: [u64; TOKEN_COUNT], output_token_index: u8, minimum_output_amount: u64, @@ -115,9 +132,20 @@ pub mod two_pool { //returning cpi data from this is a little redundant since it's already passed in the params //but keeping for parity with other ixs // note using Vec instead of [u64; TOKEN_COUNT] since anchor can't handle it properly. - #[access_control(SwapExactOutput::accounts(&ctx))] + // #[access_control(SwapExactOutput::accounts(&ctx))] + // pub fn swap_exact_output( + // ctx: Context, + // maximum_input_amount: u64, + // input_token_index: u8, + // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, + // ) -> Result> { + // let params = SwapExactOutputParams { maximum_input_amount, input_token_index, exact_output_amounts }; + // handle_swap_exact_output(ctx, params) + // } + + // #[access_control(ctx.accounts.validate())] pub fn swap_exact_output( - ctx: Context, + ctx: Context, maximum_input_amount: u64, input_token_index: u8, exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, @@ -127,7 +155,7 @@ pub mod two_pool { } pub fn remove_uniform( - ctx: Context, + ctx: Context, exact_burn_amount: u64, minimum_output_amounts: [u64; TOKEN_COUNT], // params: RemoveUniformParams, @@ -136,9 +164,21 @@ pub mod two_pool { handle_remove_uniform(ctx, params) } - #[access_control(RemoveExactBurn::accounts(&ctx))] + // #[access_control(RemoveExactBurn::accounts(&ctx))] + // pub fn remove_exact_burn( + // ctx: Context, + // exact_burn_amount: u64, + // output_token_index: u8, + // minimum_output_amount: u64, + // // params: RemoveExactBurnParams, + // ) -> Result { + // let params = RemoveExactBurnParams { exact_burn_amount, output_token_index, minimum_output_amount }; + // handle_remove_exact_burn(ctx, params) + // } + + // #[access_control(AddOrRemove::accounts(&ctx))] pub fn remove_exact_burn( - ctx: Context, + ctx: Context, exact_burn_amount: u64, output_token_index: u8, minimum_output_amount: u64, @@ -148,9 +188,9 @@ pub mod two_pool { handle_remove_exact_burn(ctx, params) } - #[access_control(RemoveExactOutput::accounts(&ctx))] + // #[access_control(RemoveExactOutput::accounts(&ctx))] pub fn remove_exact_output( - ctx: Context, + ctx: Context, maximum_burn_amount: u64, exact_output_amounts: [u64; TOKEN_COUNT], // params: RemoveExactOutputParams, diff --git a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts index 5ffb18f44..966b03b88 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts @@ -205,20 +205,16 @@ describe("TwoPool", () => { userTransferAuthority.publicKey, payer, ); + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const tx = await twoPoolProgram.methods // .add(addParams) .add(inputAmounts, minimumMintAmount) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: governanceFeeAddr, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userUsdcAtaAddr, - userTokenAccount1: userUsdtAtaAddr, - userLpTokenAccount: userSwimUsdAtaAddr, - tokenProgram: splToken.programId, - }) + .accounts(addOrRemoveAccounts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -264,7 +260,6 @@ describe("TwoPool", () => { payer, ); - const addOrRemoveAccounts = await getAddOrRemoveAccounts( flagshipPool, provider.publicKey, @@ -530,20 +525,16 @@ describe("TwoPool", () => { payer, ); + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const tx = await twoPoolProgram.methods // .removeUniform(removeUniformParams) .removeUniform(exactBurnAmount, minimumOutputAmounts) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: governanceFeeAddr, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userUsdcAtaAddr, - userTokenAccount1: userUsdtAtaAddr, - userLpTokenAccount: userSwimUsdAtaAddr, - tokenProgram: splToken.programId, - }) + .accounts(addOrRemoveAccounts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -640,21 +631,16 @@ describe("TwoPool", () => { userTransferAuthority.publicKey, payer, ); - + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const tx = await twoPoolProgram.methods // .removeExactBurn(removeExactBurnParams) .removeExactBurn(exactBurnAmount, outputTokenIndex, minimumOutputAmount) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: governanceFeeAddr, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userUsdcAtaAddr, - userTokenAccount1: userUsdtAtaAddr, - userLpTokenAccount: userSwimUsdAtaAddr, - tokenProgram: splToken.programId, - }) + .accounts(addOrRemoveAccounts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -753,20 +739,16 @@ describe("TwoPool", () => { payer, ); + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + provider.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const tx = await twoPoolProgram.methods // .removeExactOutput(removeExactOutputParams) .removeExactOutput(maximumBurnAmount, exactOutputAmounts) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: governanceFeeAddr, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: userUsdcAtaAddr, - userTokenAccount1: userUsdtAtaAddr, - userLpTokenAccount: userSwimUsdAtaAddr, - tokenProgram: splToken.programId, - }) + .accounts(addOrRemoveAccounts) .preInstructions([...approveIxs]) .postInstructions([...revokeIxs]) .signers([userTransferAuthority]) @@ -1507,20 +1489,16 @@ describe("TwoPool", () => { userTransferAuthority.publicKey, newUser, ); + const addOrRemoveAccounts = await getAddOrRemoveAccounts( + flagshipPool, + newUser.publicKey, + userTransferAuthority.publicKey, + twoPoolProgram, + ); const tx = await twoPoolProgram.methods // .removeExactBurn(removeExactBurnParams) .removeExactBurn(exactBurnAmount, outputTokenIndex, minimumOutputAmount) - .accounts({ - poolTokenAccount0: poolUsdcAtaAddr, - poolTokenAccount1: poolUsdtAtaAddr, - lpMint: swimUsdKeypair.publicKey, - governanceFee: governanceFeeAddr, - userTransferAuthority: userTransferAuthority.publicKey, - userTokenAccount0: newUserAtaAddrs[0], - userTokenAccount1: newUserAtaAddrs[1], - userLpTokenAccount: newUserAtaAddrs[2], - tokenProgram: splToken.programId, - }) + .accounts(addOrRemoveAccounts) .preInstructions([...createUserAtaIxs, ...approveIxs]) .postInstructions([...revokeIxs]) .signers([payer, userTransferAuthority, newUser]) diff --git a/packages/solana-contracts/src/artifacts/two_pool.json b/packages/solana-contracts/src/artifacts/two_pool.json index 04c6b9943..7aa5130e7 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.json +++ b/packages/solana-contracts/src/artifacts/two_pool.json @@ -427,85 +427,86 @@ "name": "removeUniform", "accounts": [ { - "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": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -531,81 +532,86 @@ "name": "removeExactBurn", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -628,81 +634,86 @@ "name": "removeExactOutput", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -1581,6 +1592,118 @@ ] } }, + { + "name": "RemoveExactBurnParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "RemoveExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumBurnAmount", + "type": "u64" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "RemoveUniformParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "minimumOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "SwapExactInputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactInputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "SwapExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumInputAmount", + "type": "u64" + }, + { + "name": "inputTokenIndex", + "type": "u8" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, { "name": "AdjustAmpFactorParams", "type": { @@ -1830,118 +1953,6 @@ ] } }, - { - "name": "RemoveExactBurnParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactBurnAmount", - "type": "u64" - }, - { - "name": "outputTokenIndex", - "type": "u8" - }, - { - "name": "minimumOutputAmount", - "type": "u64" - } - ] - } - }, - { - "name": "RemoveExactOutputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "maximumBurnAmount", - "type": "u64" - }, - { - "name": "exactOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, - { - "name": "RemoveUniformParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactBurnAmount", - "type": "u64" - }, - { - "name": "minimumOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, - { - "name": "SwapExactInputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactInputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - }, - { - "name": "outputTokenIndex", - "type": "u8" - }, - { - "name": "minimumOutputAmount", - "type": "u64" - } - ] - } - }, - { - "name": "SwapExactOutputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "maximumInputAmount", - "type": "u64" - }, - { - "name": "inputTokenIndex", - "type": "u8" - }, - { - "name": "exactOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, { "name": "PoolFee", "type": { @@ -2189,6 +2200,11 @@ "code": 6036, "name": "ConversionError", "msg": "Conversion error" + }, + { + "code": 6037, + "name": "BurnAmountExceedsTotalSupply", + "msg": "Burn amount exceeds lp total supply" } ] } \ No newline at end of file diff --git a/packages/solana-contracts/src/artifacts/two_pool.ts b/packages/solana-contracts/src/artifacts/two_pool.ts index f19a5eff6..9d75f58e6 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.ts +++ b/packages/solana-contracts/src/artifacts/two_pool.ts @@ -427,85 +427,86 @@ export type TwoPool = { "name": "removeUniform", "accounts": [ { - "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": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -531,81 +532,86 @@ export type TwoPool = { "name": "removeExactBurn", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -628,81 +634,86 @@ export type TwoPool = { "name": "removeExactOutput", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -1581,6 +1592,118 @@ export type TwoPool = { ] } }, + { + "name": "RemoveExactBurnParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "RemoveExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumBurnAmount", + "type": "u64" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "RemoveUniformParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "minimumOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "SwapExactInputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactInputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "SwapExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumInputAmount", + "type": "u64" + }, + { + "name": "inputTokenIndex", + "type": "u8" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, { "name": "AdjustAmpFactorParams", "type": { @@ -1695,248 +1818,136 @@ export type TwoPool = { { "name": "AnchorCreator", "type": { - "kind": "struct", - "fields": [ - { - "name": "address", - "type": "publicKey" - }, - { - "name": "verified", - "type": "bool" - }, - { - "name": "share", - "type": "u8" - } - ] - } - }, - { - "name": "AnchorUses", - "type": { - "kind": "struct", - "fields": [ - { - "name": "useMethod", - "type": { - "defined": "AnchorUseMethod" - } - }, - { - "name": "remaining", - "type": "u64" - }, - { - "name": "total", - "type": "u64" - } - ] - } - }, - { - "name": "AnchorCollection", - "type": { - "kind": "struct", - "fields": [ - { - "name": "verified", - "type": "bool" - }, - { - "name": "key", - "type": "publicKey" - } - ] - } - }, - { - "name": "PrepareFeeChangeParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "lpFee", - "type": { - "defined": "DecimalU64Anchor" - } - }, - { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } - } - ] - } - }, - { - "name": "UpdateLpMetadataParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "newUpdateAuthority", - "type": { - "option": "publicKey" - } - }, - { - "name": "data", - "type": { - "option": { - "defined": "AnchorDataV2" - } - } - }, - { - "name": "primarySaleHappened", - "type": { - "option": "bool" - } - }, - { - "name": "isMutable", - "type": { - "option": "bool" - } - } - ] - } - }, - { - "name": "InitializeParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "ampFactor", - "type": { - "defined": "DecimalU64Anchor" - } + "kind": "struct", + "fields": [ + { + "name": "address", + "type": "publicKey" }, { - "name": "lpFee", - "type": { - "defined": "DecimalU64Anchor" - } + "name": "verified", + "type": "bool" }, { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } + "name": "share", + "type": "u8" } ] } }, { - "name": "RemoveExactBurnParams", + "name": "AnchorUses", "type": { "kind": "struct", "fields": [ { - "name": "exactBurnAmount", - "type": "u64" + "name": "useMethod", + "type": { + "defined": "AnchorUseMethod" + } }, { - "name": "outputTokenIndex", - "type": "u8" + "name": "remaining", + "type": "u64" }, { - "name": "minimumOutputAmount", + "name": "total", "type": "u64" } ] } }, { - "name": "RemoveExactOutputParams", + "name": "AnchorCollection", "type": { "kind": "struct", "fields": [ { - "name": "maximumBurnAmount", - "type": "u64" + "name": "verified", + "type": "bool" }, { - "name": "exactOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } + "name": "key", + "type": "publicKey" } ] } }, { - "name": "RemoveUniformParams", + "name": "PrepareFeeChangeParams", "type": { "kind": "struct", "fields": [ { - "name": "exactBurnAmount", - "type": "u64" + "name": "lpFee", + "type": { + "defined": "DecimalU64Anchor" + } }, { - "name": "minimumOutputAmounts", + "name": "governanceFee", "type": { - "array": [ - "u64", - 2 - ] + "defined": "DecimalU64Anchor" } } ] } }, { - "name": "SwapExactInputParams", + "name": "UpdateLpMetadataParams", "type": { "kind": "struct", "fields": [ { - "name": "exactInputAmounts", + "name": "newUpdateAuthority", "type": { - "array": [ - "u64", - 2 - ] + "option": "publicKey" } }, { - "name": "outputTokenIndex", - "type": "u8" + "name": "data", + "type": { + "option": { + "defined": "AnchorDataV2" + } + } }, { - "name": "minimumOutputAmount", - "type": "u64" + "name": "primarySaleHappened", + "type": { + "option": "bool" + } + }, + { + "name": "isMutable", + "type": { + "option": "bool" + } } ] } }, { - "name": "SwapExactOutputParams", + "name": "InitializeParams", "type": { "kind": "struct", "fields": [ { - "name": "maximumInputAmount", - "type": "u64" + "name": "ampFactor", + "type": { + "defined": "DecimalU64Anchor" + } }, { - "name": "inputTokenIndex", - "type": "u8" + "name": "lpFee", + "type": { + "defined": "DecimalU64Anchor" + } }, { - "name": "exactOutputAmounts", + "name": "governanceFee", "type": { - "array": [ - "u64", - 2 - ] + "defined": "DecimalU64Anchor" } } ] @@ -2189,6 +2200,11 @@ export type TwoPool = { "code": 6036, "name": "ConversionError", "msg": "Conversion error" + }, + { + "code": 6037, + "name": "BurnAmountExceedsTotalSupply", + "msg": "Burn amount exceeds lp total supply" } ] }; @@ -2622,85 +2638,86 @@ export const IDL: TwoPool = { "name": "removeUniform", "accounts": [ { - "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": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -2726,81 +2743,86 @@ export const IDL: TwoPool = { "name": "removeExactBurn", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -2823,81 +2845,86 @@ export const IDL: TwoPool = { "name": "removeExactOutput", "accounts": [ { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_0.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TokenAccount", - "path": "pool_token_account_1.mint" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Mint", - "path": "lp_mint" + "name": "swap", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_0.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TokenAccount", + "path": "pool_token_account_1.mint" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Mint", + "path": "lp_mint" + } + ] } - ] - } - }, - { - "name": "poolTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "poolTokenAccount1", - "isMut": true, - "isSigner": false - }, - { - "name": "lpMint", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceFee", - "isMut": true, - "isSigner": false - }, - { - "name": "userTransferAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "userTokenAccount0", - "isMut": true, - "isSigner": false - }, - { - "name": "userTokenAccount1", - "isMut": true, - "isSigner": false + }, + { + "name": "poolTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "poolTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "lpMint", + "isMut": true, + "isSigner": false + }, + { + "name": "governanceFee", + "isMut": true, + "isSigner": false + }, + { + "name": "userTransferAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount0", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount1", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ] }, { "name": "userLpTokenAccount", "isMut": true, "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false } ], "args": [ @@ -3776,6 +3803,118 @@ export const IDL: TwoPool = { ] } }, + { + "name": "RemoveExactBurnParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "RemoveExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumBurnAmount", + "type": "u64" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "RemoveUniformParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactBurnAmount", + "type": "u64" + }, + { + "name": "minimumOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, + { + "name": "SwapExactInputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "exactInputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + }, + { + "name": "outputTokenIndex", + "type": "u8" + }, + { + "name": "minimumOutputAmount", + "type": "u64" + } + ] + } + }, + { + "name": "SwapExactOutputParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maximumInputAmount", + "type": "u64" + }, + { + "name": "inputTokenIndex", + "type": "u8" + }, + { + "name": "exactOutputAmounts", + "type": { + "array": [ + "u64", + 2 + ] + } + } + ] + } + }, { "name": "AdjustAmpFactorParams", "type": { @@ -4025,118 +4164,6 @@ export const IDL: TwoPool = { ] } }, - { - "name": "RemoveExactBurnParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactBurnAmount", - "type": "u64" - }, - { - "name": "outputTokenIndex", - "type": "u8" - }, - { - "name": "minimumOutputAmount", - "type": "u64" - } - ] - } - }, - { - "name": "RemoveExactOutputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "maximumBurnAmount", - "type": "u64" - }, - { - "name": "exactOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, - { - "name": "RemoveUniformParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactBurnAmount", - "type": "u64" - }, - { - "name": "minimumOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, - { - "name": "SwapExactInputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "exactInputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - }, - { - "name": "outputTokenIndex", - "type": "u8" - }, - { - "name": "minimumOutputAmount", - "type": "u64" - } - ] - } - }, - { - "name": "SwapExactOutputParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "maximumInputAmount", - "type": "u64" - }, - { - "name": "inputTokenIndex", - "type": "u8" - }, - { - "name": "exactOutputAmounts", - "type": { - "array": [ - "u64", - 2 - ] - } - } - ] - } - }, { "name": "PoolFee", "type": { @@ -4384,6 +4411,11 @@ export const IDL: TwoPool = { "code": 6036, "name": "ConversionError", "msg": "Conversion error" + }, + { + "code": 6037, + "name": "BurnAmountExceedsTotalSupply", + "msg": "Burn amount exceeds lp total supply" } ] }; From cb63d2cc67b4c51d35af9a2b018116520eeb05f6 Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 25 Oct 2022 13:02:33 -0400 Subject: [PATCH 13/17] refactor(solana-contracts): remove unused files --- .../src/instructions/two_pool_cpi/add.rs | 176 ------------- .../src/instructions/two_pool_cpi/mod.rs | 7 - .../two_pool_cpi/remove_exact_burn.rs | 198 --------------- .../two_pool_cpi/remove_exact_output.rs | 121 --------- .../two_pool_cpi/remove_uniform.rs | 101 -------- .../two_pool_cpi/swap_exact_input.rs | 187 -------------- .../two_pool_cpi/swap_exact_output.rs | 186 -------------- .../wormhole/transfer_native_with_payload.rs | 11 +- .../programs/two-pool/src/instructions/add.rs | 170 ------------- .../src/instructions/defi/add_or_remove.rs | 7 +- .../programs/two-pool/src/instructions/mod.rs | 11 +- .../src/instructions/remove_exact_burn.rs | 207 ---------------- .../src/instructions/remove_exact_output.rs | 214 ---------------- .../src/instructions/remove_uniform.rs | 147 ----------- .../src/instructions/swap_exact_input.rs | 222 ----------------- .../src/instructions/swap_exact_output.rs | 231 ------------------ 16 files changed, 11 insertions(+), 2185 deletions(-) delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/add.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs deleted file mode 100644 index 3036c75ce..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/add.rs +++ /dev/null @@ -1,176 +0,0 @@ -use { - crate::{error::*, Propeller}, - anchor_lang::{prelude::*}, - anchor_spl::{ - associated_token::get_associated_token_address, - token::{Mint, Token, TokenAccount}, - }, - two_pool::{state::TwoPool}, -}; - -#[derive(Accounts)] -pub struct Add<'info> { - #[account( - seeds = [ b"propeller".as_ref(), lp_mint.key().as_ref()], - bump = propeller.bump, - constraint = !propeller.is_paused @ PropellerError::IsPaused, - )] - pub propeller: Box>, - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - seeds::program = two_pool_program.key() - )] - pub pool: Box>, - // /// TODO: could be removed if initialized with pool_v2 - // /// CHECK: checked in CPI - // 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], - )] - 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], - )] - pub pool_token_account_1: Box>, - #[account( - mut, - address = pool.lp_mint_key, - constraint = propeller.swim_usd_mint == lp_mint.key(), - )] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint, - address = pool.governance_fee_key, - )] - pub governance_fee: Box>, - ///CHECK: checked in CPI - pub user_transfer_authority: Signer<'info>, - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - pub user_lp_token_account: Box>, - - pub token_program: Program<'info, Token>, - - pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -} - -impl<'info> Add<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - require_keys_eq!(ctx.accounts.lp_mint.key(), ctx.accounts.propeller.swim_usd_mint); - Ok(()) - } -} - -// pub fn handle_add( -// ctx: Context, -// input_amounts: [u64; TOKEN_COUNT], -// minimum_mint_amount: u64, -// memo: &[u8], -// propeller_enabled: bool, -// target_chain: u16, -// ) -> Result { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::Add { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// -// let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; -// let return_val = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("add return_val: {:?}", return_val); -// is_transfer_amount_sufficient( -// &ctx.accounts.propeller, -// &ctx.accounts.lp_mint, -// propeller_enabled, -// target_chain, -// return_val, -// )?; -// Ok(return_val) -// } - -// pub fn handle_cross_chain_add( -// ctx: Context, -// input_amounts: [u64; TOKEN_COUNT], -// minimum_mint_amount: u64, -// ) -> Result { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::Add { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let result = two_pool::cpi::add(cpi_ctx, input_amounts, minimum_mint_amount)?; -// let return_val = result.get(); -// anchor_lang::prelude::msg!("cross_chain_add return_val: {:?}", return_val); -// Ok(return_val) -// } -// -// pub fn handle_propeller_add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], max_fee: u64) -> Result { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::Add { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let result = two_pool::cpi::add(cpi_ctx, input_amounts, PROPELLER_MINIMUM_OUTPUT_AMOUNT)?; -// let output_amount = result.get(); -// anchor_lang::prelude::msg!("propeller_add output_amount: {:?}", output_amount); -// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); -// Ok(output_amount) -// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs index be7dd1f43..0559195b4 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/mod.rs @@ -1,8 +1 @@ -pub mod add; -pub mod remove_exact_burn; -pub mod remove_exact_output; -pub mod remove_uniform; -pub mod swap_exact_input; -pub mod swap_exact_output; -// pub mod to_swim_usd; pub mod init_to_swim_usd; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs deleted file mode 100644 index ab7e41c6c..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_burn.rs +++ /dev/null @@ -1,198 +0,0 @@ -// use { -// crate::{ -// constants::{PROPELLER_MINIMUM_OUTPUT_AMOUNT, REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX}, -// error::*, -// Propeller, -// }, -// anchor_lang::{prelude::*, solana_program::program::invoke}, -// anchor_spl::token::{Mint, Token, TokenAccount}, -// two_pool::{state::TwoPool}, -// }; -// -// #[derive(Accounts)] -// pub struct RemoveExactBurn<'info> { -// #[account( -// seeds = [ -// b"propeller".as_ref(), -// pool_token_account_0.mint.as_ref(), -// ], -// bump = propeller.bump, -// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, -// )] -// pub propeller: Account<'info, Propeller>, -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump, -// seeds::program = two_pool_program.key() -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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>, -// #[account(executable, address = spl_memo::id())] -// ///CHECK: memo program -// pub memo: UncheckedAccount<'info>, -// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -// pub swim_usd_mint: Account<'info, Mint>, -// } -// -// // pub fn handle_remove_exact_burn( -// // ctx: Context, -// // exact_burn_amount: u64, -// // // output_token_index: u8, -// // minimum_output_amount: u64, -// // memo: &[u8], -// // propeller_enabled: bool, -// // target_chain: u16, -// // ) -> Result { -// // let cpi_ctx = CpiContext::new( -// // ctx.accounts.two_pool_program.to_account_info(), -// // two_pool::cpi::accounts::RemoveExactBurn { -// // pool: ctx.accounts.pool.to_account_info(), -// // pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// // pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// // lp_mint: ctx.accounts.lp_mint.to_account_info(), -// // governance_fee: ctx.accounts.governance_fee.to_account_info(), -// // user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// // user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// // user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// // user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// // token_program: ctx.accounts.token_program.to_account_info(), -// // }, -// // ); -// // let result = two_pool::cpi::remove_exact_burn( -// // cpi_ctx, -// // exact_burn_amount, -// // REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, -// // minimum_output_amount, -// // )?; -// // let return_val = result.get(); -// // let memo_ix = spl_memo::build_memo(memo, &[]); -// // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// // anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", return_val); -// // is_transfer_amount_sufficient( -// // &ctx.accounts.propeller, -// // &ctx.accounts.token_bridge_mint, -// // propeller_enabled, -// // target_chain, -// // return_val, -// // )?; -// // Ok(return_val) -// // } -// -// pub fn handle_cross_chain_remove_exact_burn( -// ctx: Context, -// exact_burn_amount: u64, -// minimum_output_amount: u64, -// memo: &[u8], -// ) -> Result { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::AddOrRemove { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let result = two_pool::cpi::remove_exact_burn( -// cpi_ctx, -// exact_burn_amount, -// REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, -// minimum_output_amount, -// )?; -// let output_amount = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); -// Ok(output_amount) -// } -// -// pub fn handle_propeller_remove_exact_burn( -// ctx: Context, -// exact_burn_amount: u64, -// memo: &[u8], -// max_fee: u64, -// ) -> Result { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::RemoveExactBurn { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let result = two_pool::cpi::remove_exact_burn( -// cpi_ctx, -// exact_burn_amount, -// REMOVE_EXACT_BURN_OUTPUT_TOKEN_INDEX, -// PROPELLER_MINIMUM_OUTPUT_AMOUNT, -// )?; -// let output_amount = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("remove_exact_burn return_val: {:?}", output_amount); -// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); -// Ok(output_amount) -// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs deleted file mode 100644 index bf27cbd0f..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_exact_output.rs +++ /dev/null @@ -1,121 +0,0 @@ -// use { -// crate::{error::*, Propeller}, -// anchor_lang::{prelude::*, solana_program::program::invoke}, -// anchor_spl::token::{Mint, Token, TokenAccount}, -// two_pool::{state::TwoPool}, -// }; -// -// #[derive(Accounts)] -// pub struct RemoveExactOutput<'info> { -// #[account( -// seeds = [ -// b"propeller".as_ref(), -// pool_token_account_0.mint.as_ref(), -// ], -// bump = propeller.bump, -// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, -// )] -// pub propeller: Account<'info, Propeller>, -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump, -// seeds::program = two_pool_program.key() -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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>, -// #[account(executable, address = spl_memo::id())] -// ///CHECK: memo program -// pub memo: UncheckedAccount<'info>, -// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -// pub swim_usd_mint: Account<'info, Mint>, -// } -// -// pub fn handle_remove_exact_output( -// ctx: Context, -// maximum_burn_amount: u64, -// exact_output_amount: u64, -// memo: &[u8], -// _propeller_enabled: bool, -// _target_chain: u16, -// ) -> Result> { -// // is_transfer_amount_sufficient( -// // &ctx.accounts.propeller, -// // &ctx.accounts.token_bridge_mint, -// // propeller_enabled, -// // target_chain, -// // exact_output_amount, -// // )?; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::RemoveExactOutput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// -// let exact_output_amounts = [exact_output_amount, 0]; -// let result = two_pool::cpi::remove_exact_output(cpi_ctx, maximum_burn_amount, exact_output_amounts)?; -// let return_val = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("remove_exact_output return_val: {:?}", return_val); -// Ok(return_val) -// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs deleted file mode 100644 index 545e3e15a..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/remove_uniform.rs +++ /dev/null @@ -1,101 +0,0 @@ -// use { -// anchor_lang::{prelude::*, solana_program::program::invoke}, -// anchor_spl::token::{Mint, Token, TokenAccount}, -// two_pool::{state::TwoPool, TOKEN_COUNT}, -// }; -// -// #[derive(Accounts)] -// pub struct RemoveUniform<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump, -// seeds::program = two_pool_program.key() -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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>, -// #[account(executable, address = spl_memo::id())] -// ///CHECK: memo program -// pub memo: UncheckedAccount<'info>, -// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -// } -// -// pub fn handle_remove_uniform( -// ctx: Context, -// exact_burn_amount: u64, -// minimum_output_amounts: [u64; TOKEN_COUNT], -// memo: &[u8], -// ) -> Result> { -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::RemoveUniform { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// user_lp_token_account: ctx.accounts.user_lp_token_account.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// -// let result = two_pool::cpi::remove_uniform(cpi_ctx, exact_burn_amount, minimum_output_amounts)?; -// let return_val = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("remove_uniform return_val: {:?}", return_val); -// Ok(return_val) -// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs deleted file mode 100644 index 3fb98bd6c..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_input.rs +++ /dev/null @@ -1,187 +0,0 @@ -// use { -// crate::{ -// constants::{METAPOOL_SWIM_USD_INDEX, PROPELLER_MINIMUM_OUTPUT_AMOUNT}, -// Propeller, PropellerError, -// }, -// anchor_lang::{prelude::*}, -// anchor_spl::token::{Mint, Token, TokenAccount}, -// two_pool::{state::TwoPool}, -// }; -// -// #[derive(Accounts)] -// pub struct SwapExactInput<'info> { -// #[account( -// seeds = [ -// b"propeller".as_ref(), -// pool_token_account_0.mint.as_ref(), -// ], -// bump = propeller.bump, -// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, -// constraint = !propeller.is_paused @ PropellerError::IsPaused, -// )] -// pub propeller: Account<'info, Propeller>, -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump, -// seeds::program = two_pool_program.key() -// )] -// pub pool: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: 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>, -// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -// pub swim_usd_mint: Account<'info, Mint>, -// } -// -// // pub fn handle_swap_exact_input( -// // ctx: Context, -// // exact_input_amount: u64, -// // // exact_input_amounts: [u64; TOKEN_COUNT], -// // // output_token_index: u8, -// // minimum_output_amount: u64, -// // memo: &[u8], -// // propeller_enabled: bool, -// // target_chain: u16, -// // ) -> Result { -// // require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); -// // let exact_input_amounts = [0, exact_input_amount]; -// // let cpi_ctx = CpiContext::new( -// // ctx.accounts.two_pool_program.to_account_info(), -// // two_pool::cpi::accounts::SwapExactInput { -// // pool: ctx.accounts.pool.to_account_info(), -// // pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// // pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// // lp_mint: ctx.accounts.lp_mint.to_account_info(), -// // governance_fee: ctx.accounts.governance_fee.to_account_info(), -// // user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// // user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// // user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// // token_program: ctx.accounts.token_program.to_account_info(), -// // }, -// // ); -// // -// // let result = two_pool::cpi::swap_exact_input( -// // cpi_ctx, -// // exact_input_amounts, -// // SWAP_EXACT_INPUT_OUTPUT_TOKEN_INDEX, -// // minimum_output_amount, -// // )?; -// // let return_val = result.get(); -// // let memo_ix = spl_memo::build_memo(memo, &[]); -// // invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// // anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); -// // is_transfer_amount_sufficient( -// // &ctx.accounts.propeller, -// // &ctx.accounts.token_bridge_mint, -// // propeller_enabled, -// // target_chain, -// // return_val, -// // )?; -// // Ok(return_val) -// // } -// -// pub fn handle_cross_chain_swap_exact_input( -// ctx: Context, -// exact_input_amount: u64, -// minimum_output_amount: u64, -// ) -> Result { -// require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); -// let exact_input_amounts = [0, exact_input_amount]; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::SwapExactInput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// -// let result = -// two_pool::cpi::swap_exact_input(cpi_ctx, exact_input_amounts, METAPOOL_SWIM_USD_INDEX, minimum_output_amount)?; -// let return_val = result.get(); -// anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", return_val); -// Ok(return_val) -// } -// -// pub fn handle_propeller_swap_exact_input( -// ctx: Context, -// exact_input_amount: u64, -// max_fee: u64, -// ) -> Result { -// require_gt!(exact_input_amount, 0, PropellerError::InvalidSwapExactInputInputAmount); -// let exact_input_amounts = [0, exact_input_amount]; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::SwapExactInput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// -// let result = two_pool::cpi::swap_exact_input( -// cpi_ctx, -// exact_input_amounts, -// METAPOOL_SWIM_USD_INDEX, -// PROPELLER_MINIMUM_OUTPUT_AMOUNT, -// )?; -// let output_amount = result.get(); -// anchor_lang::prelude::msg!("swap_exact_input return_val: {:?}", output_amount); -// require_gt!(output_amount, max_fee, PropellerError::InsufficientAmount); -// Ok(output_amount) -// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs b/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs deleted file mode 100644 index da30ffea5..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/two_pool_cpi/swap_exact_output.rs +++ /dev/null @@ -1,186 +0,0 @@ -// use { -// crate::{constants::SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX, error::*, Propeller}, -// anchor_lang::{prelude::*, solana_program::program::invoke}, -// anchor_spl::token::{Mint, Token, TokenAccount}, -// two_pool::{state::TwoPool}, -// }; -// -// #[derive(Accounts)] -// pub struct SwapExactOutput<'info> { -// #[account( -// seeds = [ -// b"propeller".as_ref(), -// pool_token_account_0.mint.as_ref(), -// ], -// bump = propeller.bump, -// has_one = swim_usd_mint @ PropellerError::InvalidSwimUsdMint, -// )] -// pub propeller: Account<'info, Propeller>, -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump, -// seeds::program = two_pool_program.key() -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: 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>, -// #[account(executable, address = spl_memo::id())] -// ///CHECK: memo program -// pub memo: UncheckedAccount<'info>, -// pub two_pool_program: Program<'info, two_pool::program::TwoPool>, -// pub swim_usd_mint: Account<'info, Mint>, -// } -// -// pub fn handle_swap_exact_output( -// ctx: Context, -// maximum_input_amount: u64, -// exact_output_amount: u64, -// // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, -// memo: &[u8], -// _propeller_enabled: bool, -// _target_chain: u16, -// ) -> Result> { -// // is_transfer_amount_sufficient( -// // &ctx.accounts.propeller, -// // &ctx.accounts.token_bridge_mint, -// // propeller_enabled, -// // target_chain, -// // exact_output_amount, -// // )?; -// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::SwapExactOutput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let exact_output_amounts = [exact_output_amount, 0]; -// let result = -// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; -// let return_val: Vec = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); -// -// Ok(return_val) -// } -// -// pub fn handle_cross_chain_swap_exact_output( -// ctx: Context, -// maximum_input_amount: u64, -// exact_output_amount: u64, -// memo: &[u8], -// ) -> Result { -// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::SwapExactOutput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let exact_output_amounts = [exact_output_amount, 0]; -// let result = -// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; -// let return_val: Vec = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("cross_chain_swap_exact_output return_val[0]: {:?}", return_val.first()); -// //TODO: adding this check just for testing purposes. remove later. -// require_eq!(return_val.first().unwrap(), &exact_output_amount); -// Ok(exact_output_amount) -// } -// -// pub fn handle_propeller_swap_exact_output( -// ctx: Context, -// maximum_input_amount: u64, -// exact_output_amount: u64, -// // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, -// memo: &[u8], -// max_fee: u64, -// ) -> Result> { -// require_gt!(exact_output_amount, max_fee, PropellerError::InsufficientAmount); -// let input_token_index = SWAP_EXACT_OUTPUT_INPUT_TOKEN_INDEX; -// let cpi_ctx = CpiContext::new( -// ctx.accounts.two_pool_program.to_account_info(), -// two_pool::cpi::accounts::SwapExactOutput { -// pool: ctx.accounts.pool.to_account_info(), -// pool_token_account_0: ctx.accounts.pool_token_account_0.to_account_info(), -// pool_token_account_1: ctx.accounts.pool_token_account_1.to_account_info(), -// lp_mint: ctx.accounts.lp_mint.to_account_info(), -// governance_fee: ctx.accounts.governance_fee.to_account_info(), -// user_transfer_authority: ctx.accounts.user_transfer_authority.to_account_info(), -// user_token_account_0: ctx.accounts.user_token_account_0.to_account_info(), -// user_token_account_1: ctx.accounts.user_token_account_1.to_account_info(), -// token_program: ctx.accounts.token_program.to_account_info(), -// }, -// ); -// let exact_output_amounts = [exact_output_amount, 0]; -// let result = -// two_pool::cpi::swap_exact_output(cpi_ctx, maximum_input_amount, input_token_index, exact_output_amounts)?; -// let return_val: Vec = result.get(); -// let memo_ix = spl_memo::build_memo(memo, &[]); -// invoke(&memo_ix, &[ctx.accounts.memo.to_account_info()])?; -// anchor_lang::prelude::msg!("swap_exact_output return_val: {:?}", return_val); -// -// Ok(return_val) -// } 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 37175e13c..7e864897b 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 @@ -1,14 +1,11 @@ use { crate::{ - constants::CURRENT_SWIM_PAYLOAD_VERSION, error::*, target_chain_map::TargetChainMap, wormhole::SwimPayload, Propeller, TokenBridge, Wormhole, TRANSFER_NATIVE_WITH_PAYLOAD_INSTRUCTION, + constants::CURRENT_SWIM_PAYLOAD_VERSION, error::*, target_chain_map::TargetChainMap, wormhole::SwimPayload, + Propeller, TokenBridge, Wormhole, TRANSFER_NATIVE_WITH_PAYLOAD_INSTRUCTION, }, anchor_lang::{ prelude::*, - solana_program::{ - instruction::Instruction, - program::{invoke_signed}, - sysvar::SysvarId, - }, + solana_program::{instruction::Instruction, program::invoke_signed, sysvar::SysvarId}, }, anchor_spl::{ associated_token::get_associated_token_address, @@ -192,7 +189,7 @@ pub struct TransferNativeWithPayload<'info> { } impl<'info> TransferNativeWithPayload<'info> { - //Note: some of the checks are excessive (checked in CPI etc) and add.rs to compute budget but since we now have access to requesting + //Note: some of the checks are excessive (checked in CPI etc) and add to compute budget but since we now have access to requesting // up to 1.4M compute budget per transaction, better safe than sorry to perform them. pub fn accounts(ctx: &Context) -> Result<()> { require_keys_eq!( diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs b/packages/solana-contracts/programs/two-pool/src/instructions/add.rs deleted file mode 100644 index b2d74cef7..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/add.rs +++ /dev/null @@ -1,170 +0,0 @@ -use { - crate::{common, error::*, gen_pool_signer_seeds, invariant::Invariant, TwoPool, TOKEN_COUNT}, - anchor_lang::prelude::*, - anchor_spl::token::{self, Mint, Token, TokenAccount}, - std::iter::zip, -}; - -#[derive(Accounts)] -pub struct Add<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool_token_account_0.mint.as_ref(), - pool_token_account_1.mint.as_ref(), - lp_mint.key().as_ref(), - ], - bump = pool.bump, - )] - pub pool: Box>, - #[account( - mut, - address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, - )] - pub pool_token_account_0: Box>, - #[account( - mut, - address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, - )] - pub pool_token_account_1: Box>, - #[account( - mut, - address = pool.lp_mint_key @ PoolError::InvalidMintAccount, - )] - pub lp_mint: Box>, - #[account( - mut, - token::mint = lp_mint, - address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, - )] - pub governance_fee: Box>, - pub user_transfer_authority: Signer<'info>, - #[account( - mut, - token::mint = pool_token_account_0.mint, - )] - pub user_token_account_0: Box>, - #[account( - mut, - token::mint = pool_token_account_1.mint, - )] - pub user_token_account_1: Box>, - - #[account( - mut, - token::mint = lp_mint, - )] - pub user_lp_token_account: Box>, - - pub token_program: Program<'info, Token>, -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct AddParams { - pub input_amounts: [u64; TOKEN_COUNT], - pub minimum_mint_amount: u64, -} - -impl<'info> Add<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - let pool_state = &ctx.accounts.pool; - require!(!pool_state.is_paused, PoolError::PoolIsPaused); - Ok(()) - } -} - -// -pub fn handle_add_old( - ctx: Context, - params: AddParams, - // input_amounts: [u64; TOKEN_COUNT], - // minimum_mint_amount: u64, -) -> Result { - let input_amounts = params.input_amounts; - let minimum_mint_amount = params.minimum_mint_amount; - require!(input_amounts.iter().any(|&x| x > 0), PoolError::AddRequiresAtLeastOneToken); - let lp_total_supply = ctx.accounts.lp_mint.supply; - //initial add to pool must add all tokens - if lp_total_supply == 0 { - require!(input_amounts.iter().all(|&x| x > 0), PoolError::InitialAddRequiresAllTokens); - } - - let pool = &ctx.accounts.pool; - let user_token_accounts = [&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; - let pool_token_accounts = [&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; - let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - let current_ts = Clock::get()?.unix_timestamp; - require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); - let (user_amount, governance_mint_amount, latest_depth) = Invariant::::add( - &common::array_equalize(input_amounts, pool.token_decimal_equalizers), - &common::array_equalize(pool_balances, pool.token_decimal_equalizers), - pool.amp_factor.get(current_ts), - pool.lp_fee.get(), - pool.governance_fee.get(), - common::to_equalized(lp_total_supply, pool.lp_decimal_equalizer), - pool.previous_depth.into(), - )?; - let (mint_amount, governance_mint_amount, latest_depth) = common::result_from_equalized( - user_amount, - pool.lp_decimal_equalizer, - governance_mint_amount, - pool.lp_decimal_equalizer, - latest_depth, - ); - require_gte!(mint_amount, minimum_mint_amount, PoolError::OutsideSpecifiedLimits); - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); - for input_amount in input_amounts.iter().take(TOKEN_COUNT) { - let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - if *input_amount > 0u64 { - let pool_token_account = pool_token_account.to_account_info(); - let user_token_account = user_token_account.to_account_info(); - let user_transfer_authority = ctx.accounts.user_transfer_authority.to_account_info(); - token::transfer( - CpiContext::new( - ctx.accounts.token_program.to_account_info(), - token::Transfer { - from: user_token_account.clone(), - to: pool_token_account.clone(), - authority: user_transfer_authority.clone(), - }, - ), - *input_amount, - )?; - } - } - - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.user_lp_token_account.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - mint_amount, - )?; - - if governance_mint_amount > 0 { - token::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token::MintTo { - // source - mint: ctx.accounts.lp_mint.to_account_info(), - to: ctx.accounts.governance_fee.to_account_info(), - authority: ctx.accounts.pool.to_account_info(), - }, - &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - ), - governance_mint_amount, - )?; - } - - let pool_state = &mut ctx.accounts.pool; - pool_state.previous_depth = latest_depth; - Ok(mint_amount) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs index d6126babf..01dcd4f02 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs @@ -6,7 +6,7 @@ use { error::*, gen_pool_signer_seeds, get_current_ts, invariant::Invariant, - AddParams, TwoPool, TOKEN_COUNT, + TwoPool, TOKEN_COUNT, }, anchor_lang::prelude::*, anchor_spl::{ @@ -43,6 +43,11 @@ impl<'info> AddOrRemove<'info> { } } +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct AddParams { + pub input_amounts: [u64; TOKEN_COUNT], + pub minimum_mint_amount: u64, +} pub fn handle_add( ctx: Context, params: AddParams, diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs index 6f8ecfeee..d7253ab28 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/mod.rs @@ -2,19 +2,10 @@ use { crate::error::*, anchor_lang::{prelude::*, require_gt, solana_program::clock::UnixTimestamp}, }; -pub use { - add::*, defi::*, governance::*, initialize::*, marginal_prices::*, remove_exact_burn::*, remove_exact_output::*, - remove_uniform::*, swap_exact_input::*, swap_exact_output::*, -}; +pub use {defi::*, governance::*, initialize::*, marginal_prices::*}; -pub mod add; pub mod initialize; pub mod marginal_prices; -pub mod remove_exact_burn; -pub mod remove_exact_output; -pub mod remove_uniform; -pub mod swap_exact_input; -pub mod swap_exact_output; pub mod defi; pub mod governance; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs deleted file mode 100644 index 3c88faafb..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_burn.rs +++ /dev/null @@ -1,207 +0,0 @@ -// use { -// crate::{ -// common::{array_equalize, result_from_equalized, to_equalized}, -// error::*, -// gen_pool_signer_seeds, -// invariant::Invariant, -// TwoPool, TOKEN_COUNT, -// }, -// anchor_lang::prelude::*, -// anchor_spl::{ -// token, -// token::{Mint, Token, TokenAccount}, -// }, -// std::iter::zip, -// }; -// -// #[derive(AnchorSerialize, AnchorDeserialize)] -// pub struct RemoveExactBurnParams { -// pub exact_burn_amount: u64, -// pub output_token_index: u8, -// pub minimum_output_amount: u64, -// } -// -// #[derive(Accounts)] -// pub struct RemoveExactBurn<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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> RemoveExactBurn<'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_exact_burn_old( -// ctx: Context, -// remove_exact_burn_params: RemoveExactBurnParams, -// ) -> Result { -// let output_token_index = remove_exact_burn_params.output_token_index as usize; -// let exact_burn_amount = remove_exact_burn_params.exact_burn_amount; -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// require!(output_token_index < TOKEN_COUNT, PoolError::InvalidRemoveExactBurnParameters); -// require_gt!(exact_burn_amount, 0, PoolError::InvalidRemoveExactBurnParameters); -// require_gt!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveExactBurnParameters); -// -// let pool = &ctx.accounts.pool; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// let _lp_mint = &ctx.accounts.lp_mint; -// let _governance_fee = &ctx.accounts.governance_fee; -// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_token_accounts = [user_token_account_0, user_token_account_1]; -// -// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; -// -// let current_ts = Clock::get()?.unix_timestamp; -// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); -// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_burn( -// to_equalized(exact_burn_amount, pool.lp_decimal_equalizer), -// output_token_index, -// &array_equalize(pool_balances, pool.token_decimal_equalizers), -// pool.amp_factor.get(current_ts), -// pool.lp_fee.get(), -// pool.governance_fee.get(), -// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), -// pool.previous_depth.into(), -// )?; -// let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( -// user_amount, -// pool.token_decimal_equalizers[output_token_index], -// governance_mint_amount, -// pool.lp_decimal_equalizer, -// latest_depth, -// ); -// let minimum_output_amount = remove_exact_burn_params.minimum_output_amount; -// require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); -// -// let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// token::burn( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Burn { -// mint: ctx.accounts.lp_mint.to_account_info(), -// from: ctx.accounts.user_lp_token_account.to_account_info(), -// authority: ctx.accounts.user_transfer_authority.to_account_info(), -// }, -// ), -// exact_burn_amount, -// )?; -// -// let user_output_token_account = user_token_accounts[output_token_index]; -// let pool_output_token_account = pool_token_accounts[output_token_index]; -// token::transfer( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: pool_output_token_account.to_account_info(), -// to: user_output_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// output_amount, -// )?; -// -// if governance_mint_amount > 0 { -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.governance_fee.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// governance_mint_amount, -// )?; -// } -// let pool = &mut ctx.accounts.pool; -// pool.previous_depth = latest_depth; -// Ok(output_amount) -// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs deleted file mode 100644 index b8d9d906b..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_exact_output.rs +++ /dev/null @@ -1,214 +0,0 @@ -// use { -// crate::{ -// common::{array_equalize, result_from_equalized, to_equalized}, -// error::*, -// gen_pool_signer_seeds, get_current_ts, -// invariant::Invariant, -// TwoPool, TOKEN_COUNT, -// }, -// anchor_lang::prelude::*, -// anchor_spl::{ -// token, -// token::{Mint, Token, TokenAccount}, -// }, -// std::iter::zip, -// }; -// -// #[derive(AnchorSerialize, AnchorDeserialize)] -// pub struct RemoveExactOutputParams { -// pub maximum_burn_amount: u64, -// pub exact_output_amounts: [u64; TOKEN_COUNT], -// } -// -// #[derive(Accounts)] -// pub struct RemoveExactOutput<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// 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> RemoveExactOutput<'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_exact_output( -// ctx: Context, -// remove_exact_output_params: RemoveExactOutputParams, -// ) -> Result> { -// let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; -// let exact_output_amounts = remove_exact_output_params.exact_output_amounts; -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// -// require!(exact_output_amounts.iter().any(|amount| *amount > 0), PoolError::InvalidRemoveExactOutputParameters); -// require_gt!(maximum_burn_amount, 0u64, PoolError::InvalidRemoveExactOutputParameters); -// let are_output_amounts_valid = exact_output_amounts -// .iter() -// .zip(pool_balances.iter()) -// .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); -// require!(are_output_amounts_valid, PoolError::InvalidRemoveExactOutputParameters); -// -// let pool = &ctx.accounts.pool; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let _lp_mint = &ctx.accounts.lp_mint; -// let _governance_fee = &ctx.accounts.governance_fee; -// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_token_accounts = [user_token_account_0, user_token_account_1]; -// -// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; -// -// let current_ts = get_current_ts()?; -// -// let (burn_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_output( -// &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), -// &array_equalize(pool_balances, pool.token_decimal_equalizers), -// pool.amp_factor.get(current_ts), -// pool.lp_fee.get(), -// pool.governance_fee.get(), -// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), -// pool.previous_depth.into(), -// )?; -// let (burn_amount, governance_mint_amount, latest_depth) = result_from_equalized( -// burn_amount, -// pool.lp_decimal_equalizer, -// governance_mint_amount, -// pool.lp_decimal_equalizer, -// latest_depth, -// ); -// -// let maximum_burn_amount = remove_exact_output_params.maximum_burn_amount; -// require_gte!(maximum_burn_amount, burn_amount, PoolError::OutsideSpecifiedLimits); -// -// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// token::burn( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Burn { -// mint: ctx.accounts.lp_mint.to_account_info(), -// from: ctx.accounts.user_lp_token_account.to_account_info(), -// authority: ctx.accounts.user_transfer_authority.to_account_info(), -// }, -// ), -// burn_amount, -// )?; -// -// for i in 0..TOKEN_COUNT { -// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); -// if exact_output_amounts[i] > 0 { -// token::transfer( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: pool_token_account.to_account_info(), -// to: user_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// exact_output_amounts[i], -// )?; -// } -// } -// -// if governance_mint_amount > 0 { -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.governance_fee.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// governance_mint_amount, -// )?; -// } -// let pool = &mut ctx.accounts.pool; -// pool.previous_depth = latest_depth; -// Ok(exact_output_amounts.into()) -// } 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 deleted file mode 100644 index 70de6c722..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/remove_uniform.rs +++ /dev/null @@ -1,147 +0,0 @@ -// use { -// crate::{error::*, gen_pool_signer_seeds, DecimalU64, TwoPool, TOKEN_COUNT}, -// anchor_lang::prelude::*, -// anchor_spl::{ -// token, -// token::{Mint, Token, TokenAccount}, -// }, -// std::iter::zip, -// }; -// -// #[derive(AnchorSerialize, AnchorDeserialize)] -// pub struct RemoveUniformParams { -// pub exact_burn_amount: u64, -// pub minimum_output_amounts: [u64; TOKEN_COUNT], -// } -// -// #[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 = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Box>, -// #[account( -// mut, -// address = pool.token_keys[0] @ PoolError::PoolTokenAccountExpected, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// address = pool.token_keys[1] @ PoolError::PoolTokenAccountExpected, -// )] -// pub pool_token_account_1: Box>, -// #[account( -// mut, -// address = pool.lp_mint_key @ PoolError::InvalidMintAccount, -// )] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint, -// address = pool.governance_fee_key @ PoolError::InvalidGovernanceFeeAccount, -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// #[account( -// mut, -// token::mint = lp_mint, -// )] -// pub user_lp_token_account: Box>, -// -// pub token_program: Program<'info, Token>, -// } -// -// pub fn handle_remove_uniform( -// ctx: Context, -// remove_uniform_params: RemoveUniformParams, -// ) -> Result> { -// let exact_burn_amount = remove_uniform_params.exact_burn_amount; -// let minimum_output_amounts = remove_uniform_params.minimum_output_amounts; -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveUniformParameters); -// require_gte!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveUniformParameters); -// -// let pool = &ctx.accounts.pool; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// -// let user_share = DecimalU64::from(exact_burn_amount) / lp_total_supply; -// //u64 can store 19 decimals, previous_depth can theoretically go up to TOKEN_COUNT * u64::MAX -// //hence, just to be safe, we allow for previous depth to have up to 20 decimals -// //therefore we can only multiply with a number with at most 18 decimals to stay within -// //the 38 max decimals range of u128 -// const DECIMAL_UPSHIFT: u32 = 18; -// let user_depth = (pool.previous_depth * ((user_share * 10u64.pow(DECIMAL_UPSHIFT)).trunc() as u128)) -// / 10u128.pow(DECIMAL_UPSHIFT); -// let latest_depth = pool.previous_depth - user_depth; -// -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_token_accounts = [user_token_account_0, user_token_account_1]; -// -// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; -// -// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// -// let mut output_amounts = vec![]; -// for i in 0..TOKEN_COUNT { -// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); -// let output_amount = (pool_balances[i] * user_share).trunc(); -// output_amounts.push(output_amount); -// require_gte!(output_amount, minimum_output_amounts[i], PoolError::OutsideSpecifiedLimits); -// token::transfer( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: pool_token_account.to_account_info(), -// to: user_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// output_amount, -// )?; -// } -// -// token::burn( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Burn { -// mint: ctx.accounts.lp_mint.to_account_info(), -// from: ctx.accounts.user_lp_token_account.to_account_info(), -// authority: ctx.accounts.user_transfer_authority.to_account_info(), -// }, -// ), -// exact_burn_amount, -// )?; -// -// let pool = &mut ctx.accounts.pool; -// pool.previous_depth = latest_depth; -// -// Ok(output_amounts) -// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs deleted file mode 100644 index 4431688a4..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_input.rs +++ /dev/null @@ -1,222 +0,0 @@ -// use { -// crate::{ -// common::{array_equalize, result_from_equalized, to_equalized}, -// error::*, -// gen_pool_signer_seeds, -// invariant::Invariant, -// TwoPool, TOKEN_COUNT, -// }, -// anchor_lang::prelude::*, -// anchor_spl::{ -// token, -// token::{Mint, Token, TokenAccount}, -// }, -// std::iter::zip, -// }; -// -// /// Swaps in the exact specified amounts for -// /// at least `minimum_out_amount` of the output_token specified -// /// by output_token_index -// /// -// /// Accounts expected by this instruction: -// /// 0. `[w]` The pool state account -// /// 1. `[]` pool authority -// /// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts -// /// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint -// /// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account -// /// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account -// /// 6. ..6 + TOKEN_COUNT `[w]` user token accounts -// #[derive(Accounts)] -// pub struct SwapExactInput<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: Box>, -// -// pub token_program: Program<'info, Token>, -// } -// -// impl<'info> SwapExactInput<'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(()) -// } -// } -// -// #[derive(AnchorSerialize, AnchorDeserialize)] -// pub struct SwapExactInputParams { -// pub exact_input_amounts: [u64; TOKEN_COUNT], -// pub output_token_index: u8, -// pub minimum_output_amount: u64, -// } -// -// pub fn handle_swap_exact_input( -// ctx: Context, -// swap_exact_input_params: SwapExactInputParams, -// // exact_input_amounts: [u64; TOKEN_COUNT], -// // output_token_index: u8, -// // minimum_output_amount: u64, -// ) -> Result { -// // let output_token_index = output_token_index as usize; -// let output_token_index = swap_exact_input_params.output_token_index as usize; -// let exact_input_amounts = swap_exact_input_params.exact_input_amounts; -// let minimum_output_amount = swap_exact_input_params.minimum_output_amount; -// if exact_input_amounts.iter().all(|amount| *amount == 0) -// || output_token_index >= TOKEN_COUNT -// || exact_input_amounts[output_token_index] != 0 -// { -// return err!(PoolError::InvalidSwapExactInputParameters); -// } -// -// let pool = &ctx.accounts.pool; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// let _lp_mint = &ctx.accounts.lp_mint; -// let _governance_fee = &ctx.accounts.governance_fee; -// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_token_accounts = [user_token_account_0, user_token_account_1]; -// -// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; -// -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// let current_ts = Clock::get()?.unix_timestamp; -// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); -// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_input( -// &array_equalize(exact_input_amounts, pool.token_decimal_equalizers), -// output_token_index, -// &array_equalize(pool_balances, pool.token_decimal_equalizers), -// pool.amp_factor.get(current_ts), -// pool.lp_fee.get(), -// pool.governance_fee.get(), -// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), -// pool.previous_depth.into(), -// )?; -// let (output_amount, governance_mint_amount, latest_depth) = result_from_equalized( -// user_amount, -// pool.token_decimal_equalizers[output_token_index], -// governance_mint_amount, -// pool.lp_decimal_equalizer, -// latest_depth, -// ); -// -// require_gte!(output_amount, minimum_output_amount, PoolError::OutsideSpecifiedLimits); -// -// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// for i in 0..TOKEN_COUNT { -// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); -// if exact_input_amounts[i] > 0 { -// token::transfer( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: user_token_account.to_account_info(), -// to: pool_token_account.to_account_info(), -// authority: ctx.accounts.user_transfer_authority.to_account_info(), -// }, -// ), -// exact_input_amounts[i], -// )?; -// } -// } -// let user_output_token_account = user_token_accounts[output_token_index]; -// let pool_output_token_account = pool_token_accounts[output_token_index]; -// token::transfer( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: pool_output_token_account.to_account_info(), -// to: user_output_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// output_amount, -// )?; -// -// if governance_mint_amount > 0 { -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.governance_fee.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// governance_mint_amount, -// )?; -// } -// let pool = &mut ctx.accounts.pool; -// pool.previous_depth = latest_depth; -// Ok(output_amount) -// } diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs b/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs deleted file mode 100644 index 446163d26..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/swap_exact_output.rs +++ /dev/null @@ -1,231 +0,0 @@ -// use { -// crate::{ -// common::{array_equalize, result_from_equalized, to_equalized}, -// error::*, -// gen_pool_signer_seeds, -// invariant::Invariant, -// TwoPool, TOKEN_COUNT, -// }, -// anchor_lang::prelude::*, -// anchor_spl::{ -// token, -// token::{Mint, Token, TokenAccount}, -// }, -// std::iter::zip, -// }; -// -// /// Swaps in the exact specified amounts for -// /// at least `minimum_out_amount` of the output_token specified -// /// by output_token_index -// /// -// /// Accounts expected by this instruction: -// /// 0. `[w]` The pool state account -// /// 1. `[]` pool authority -// /// 2. ..2 + TOKEN_COUNT `[w]` pool's token accounts -// /// 3. ..3 + TOKEN_COUNT `[w]` LP Token Mint -// /// 4. ..4 + TOKEN_COUNT `[w]` governance_fee_account -// /// 5. ..5 + TOKEN_COUNT `[s]` user transfer authority account -// /// 6. ..6 + TOKEN_COUNT `[w]` user token accounts -// #[derive(Accounts)] -// pub struct SwapExactOutput<'info> { -// #[account( -// mut, -// seeds = [ -// b"two_pool".as_ref(), -// pool_token_account_0.mint.as_ref(), -// pool_token_account_1.mint.as_ref(), -// lp_mint.key().as_ref(), -// ], -// bump = pool.bump -// )] -// pub pool: Account<'info, TwoPool>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[0], -// token::authority = pool, -// )] -// pub pool_token_account_0: Box>, -// #[account( -// mut, -// token::mint = pool.token_mint_keys[1], -// token::authority = pool, -// )] -// pub pool_token_account_1: Box>, -// #[account(mut)] -// pub lp_mint: Box>, -// #[account( -// mut, -// token::mint = lp_mint -// )] -// pub governance_fee: Box>, -// -// pub user_transfer_authority: Signer<'info>, -// -// #[account( -// mut, -// token::mint = pool_token_account_0.mint, -// )] -// pub user_token_account_0: Box>, -// -// #[account( -// mut, -// token::mint = pool_token_account_1.mint, -// )] -// pub user_token_account_1: 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> SwapExactOutput<'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 -// ); -// msg!("finished accounts context check"); -// Ok(()) -// } -// } -// -// #[derive(AnchorSerialize, AnchorDeserialize)] -// pub struct SwapExactOutputParams { -// pub maximum_input_amount: u64, -// pub input_token_index: u8, -// pub exact_output_amounts: [u64; TOKEN_COUNT], -// } -// -// pub fn handle_swap_exact_output( -// ctx: Context, -// swap_exact_output_params: SwapExactOutputParams, -// ) -> Result> { -// let input_token_index = swap_exact_output_params.input_token_index as usize; -// let exact_output_amounts = swap_exact_output_params.exact_output_amounts; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// let are_output_amounts_valid = exact_output_amounts.iter().any(|amount| *amount == 0); -// require!(are_output_amounts_valid, PoolError::InvalidSwapExactOutputParameters); -// require!(input_token_index < TOKEN_COUNT, PoolError::InvalidSwapExactOutputParameters); -// require!(exact_output_amounts[input_token_index] == 0, PoolError::InvalidSwapExactOutputParameters); -// // || exact_output_amounts[input_token_index] != 0 -// // if exact_output_amounts.iter().all(|amount| *amount == 0) -// // || input_token_index >= TOKEN_COUNT -// // || exact_output_amounts[input_token_index] != 0 -// // { -// // return err!(PoolError::InvalidSwapExactOutputParameters); -// // } -// let are_pool_balances_sufficient = exact_output_amounts -// .iter() -// .zip(pool_balances.iter()) -// .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); -// require!(are_pool_balances_sufficient, PoolError::InsufficientPoolTokenAccountBalance); -// -// let pool = &ctx.accounts.pool; -// let pool_token_account_0 = &ctx.accounts.pool_token_account_0; -// let pool_token_account_1 = &ctx.accounts.pool_token_account_1; -// let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; -// let _lp_mint = &ctx.accounts.lp_mint; -// let _governance_fee = &ctx.accounts.governance_fee; -// // let user_transfer_auth = &ctx.accounts.user_transfer_authority; -// let user_token_account_0 = &ctx.accounts.user_token_account_0; -// let user_token_account_1 = &ctx.accounts.user_token_account_1; -// let user_token_accounts = [user_token_account_0, user_token_account_1]; -// -// let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; -// -// let lp_total_supply = ctx.accounts.lp_mint.supply; -// let current_ts = Clock::get()?.unix_timestamp; -// require_gt!(current_ts, 0i64, PoolError::InvalidTimestamp); -// let (user_amount, governance_mint_amount, latest_depth) = Invariant::::swap_exact_output( -// input_token_index, -// &array_equalize(exact_output_amounts, pool.token_decimal_equalizers), -// &array_equalize(pool_balances, pool.token_decimal_equalizers), -// pool.amp_factor.get(current_ts), -// pool.lp_fee.get(), -// pool.governance_fee.get(), -// to_equalized(lp_total_supply, pool.lp_decimal_equalizer), -// pool.previous_depth.into(), -// )?; -// let (input_amount, governance_mint_amount, latest_depth) = result_from_equalized( -// user_amount, -// pool.token_decimal_equalizers[input_token_index], -// governance_mint_amount, -// pool.lp_decimal_equalizer, -// latest_depth, -// ); -// -// let maximum_input_amount = swap_exact_output_params.maximum_input_amount; -// require_gte!(maximum_input_amount, input_amount, PoolError::OutsideSpecifiedLimits); -// -// let user_input_token_account = user_token_accounts[input_token_index]; -// let pool_input_token_account = pool_token_accounts[input_token_index]; -// token::transfer( -// CpiContext::new( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: user_input_token_account.to_account_info(), -// to: pool_input_token_account.to_account_info(), -// authority: ctx.accounts.user_transfer_authority.to_account_info(), -// }, -// ), -// input_amount, -// )?; -// -// let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); -// -// for i in 0..TOKEN_COUNT { -// let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); -// if exact_output_amounts[i] > 0 { -// token::transfer( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::Transfer { -// // source -// from: pool_token_account.to_account_info(), -// to: user_token_account.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// exact_output_amounts[i], -// )?; -// } -// } -// -// if governance_mint_amount > 0 { -// token::mint_to( -// CpiContext::new_with_signer( -// ctx.accounts.token_program.to_account_info(), -// token::MintTo { -// // source -// mint: ctx.accounts.lp_mint.to_account_info(), -// to: ctx.accounts.governance_fee.to_account_info(), -// authority: ctx.accounts.pool.to_account_info(), -// }, -// &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], -// ), -// governance_mint_amount, -// )?; -// } -// let pool = &mut ctx.accounts.pool; -// pool.previous_depth = latest_depth; -// Ok(exact_output_amounts.into()) -// } From 4086eab0715ef9ca4a0928dff8161254ba04c96e Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 25 Oct 2022 13:13:27 -0400 Subject: [PATCH 14/17] refactor(solana-contracts): remove commented out code --- .../src/instructions/defi/add_or_remove.rs | 207 +----------------- .../programs/two-pool/src/lib.rs | 68 ------ 2 files changed, 3 insertions(+), 272 deletions(-) diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs index 01dcd4f02..978cc2e2f 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/add_or_remove.rs @@ -99,67 +99,14 @@ pub fn handle_add( pool_token_account, *input_amount, )?; - // if *input_amount > 0u64 { - // // let pool_token_account = pool_token_account.to_account_info(); - // // let user_token_account = user_token_account.to_account_info(); - // // let user_transfer_authority = ctx.accounts.swap.user_transfer_authority.to_account_info(); - // // ctx.accounts.swap.transfer_from_user_to_pool( - // // user_token_account, - // // user_transfer_authority, - // // pool_token_account, - // // *input_amount, - // // )?; - // // token::transfer( - // // CpiContext::new( - // // ctx.accounts.swap.token_program.to_account_info(), - // // token::Transfer { - // // from: user_token_account.clone(), - // // to: pool_token_account.clone(), - // // authority: user_transfer_authority.clone(), - // // }, - // // ), - // // *input_amount, - // // )?; - // } } - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.swap.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.swap.lp_mint.to_account_info(), - // to: ctx.accounts.user_lp_token_account.to_account_info(), - // authority: ctx.accounts.swap.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], - // ), - // mint_amount, - // )?; - // mint user lp tokens ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.user_lp_token_account, mint_amount)?; // mint governance fee ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.swap.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.swap.lp_mint.to_account_info(), - // to: ctx.accounts.swap.governance_fee.to_account_info(), - // authority: ctx.accounts.swap.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.swap.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - - // let pool_state = &mut ctx.accounts.swap.pool; - // pool_state.previous_depth = latest_depth; + ctx.accounts.swap.update_previous_depth(latest_depth)?; Ok(mint_amount) } @@ -182,19 +129,6 @@ pub fn handle_remove_exact_burn( require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveExactBurnParameters); require_gt!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveExactBurnParameters); - // let pool = &ctx.accounts.swap.pool; - // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - // let _lp_mint = &ctx.accounts.lp_mint; - // let _governance_fee = &ctx.accounts.governance_fee; - // // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - // let user_token_account_0 = &ctx.accounts.user_token_account_0; - // let user_token_account_1 = &ctx.accounts.user_token_account_1; - // let user_token_accounts = [user_token_account_0, user_token_account_1]; - // - // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - let pool = &ctx.accounts.swap.pool; require!(!pool.is_paused, PoolError::PoolIsPaused); let user_token_accounts = [&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; @@ -225,17 +159,6 @@ pub fn handle_remove_exact_burn( // let _token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); ctx.accounts.burn_user_lp_tokens(exact_burn_amount)?; - // token::burn( - // CpiContext::new( - // ctx.accounts.token_program.to_account_info(), - // token::Burn { - // mint: ctx.accounts.lp_mint.to_account_info(), - // from: ctx.accounts.user_lp_token_account.to_account_info(), - // authority: ctx.accounts.user_transfer_authority.to_account_info(), - // }, - // ), - // exact_burn_amount, - // )?; let user_output_token_account = user_token_accounts[output_token_index]; let pool_output_token_account = pool_token_accounts[output_token_index]; @@ -244,40 +167,9 @@ pub fn handle_remove_exact_burn( user_output_token_account, output_amount, )?; - // token::transfer( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: pool_output_token_account.to_account_info(), - // to: user_output_token_account.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // output_amount, - // )?; ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; - // ctx.accounts.swap.mint_governance_fee(governance_mint_amount)?; - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.lp_mint.to_account_info(), - // to: ctx.accounts.governance_fee.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - - // let pool = &mut ctx.accounts.swap.pool; - // pool.previous_depth = latest_depth; + ctx.accounts.swap.update_previous_depth(latest_depth)?; Ok(output_amount) } @@ -301,7 +193,6 @@ pub fn handle_remove_exact_output( let pool_balances = [ctx.accounts.swap.pool_token_account_0.amount, ctx.accounts.swap.pool_token_account_1.amount]; let lp_total_supply = ctx.accounts.swap.lp_mint.supply; - // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; require!(exact_output_amounts.iter().any(|amount| *amount > 0), PoolError::InvalidRemoveExactOutputParameters); require_gt!(maximum_burn_amount, 0u64, PoolError::InvalidRemoveExactOutputParameters); @@ -311,18 +202,6 @@ pub fn handle_remove_exact_output( .all(|(output_amount, pool_balance)| *output_amount < *pool_balance); require!(are_output_amounts_valid, PoolError::InvalidRemoveExactOutputParameters); - // let pool = &ctx.accounts.pool; - // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - // let _lp_mint = &ctx.accounts.lp_mint; - // let _governance_fee = &ctx.accounts.governance_fee; - // // let user_transfer_auth = &ctx.accounts.user_transfer_authority; - // let user_token_account_0 = &ctx.accounts.user_token_account_0; - // let user_token_account_1 = &ctx.accounts.user_token_account_1; - // let user_token_accounts = [user_token_account_0, user_token_account_1]; - // - // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - let current_ts = get_current_ts()?; let (burn_amount, governance_mint_amount, latest_depth) = Invariant::::remove_exact_output( @@ -348,17 +227,6 @@ pub fn handle_remove_exact_output( let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); ctx.accounts.burn_user_lp_tokens(burn_amount)?; - // token::burn( - // CpiContext::new( - // ctx.accounts.token_program.to_account_info(), - // token::Burn { - // mint: ctx.accounts.lp_mint.to_account_info(), - // from: ctx.accounts.user_lp_token_account.to_account_info(), - // authority: ctx.accounts.user_transfer_authority.to_account_info(), - // }, - // ), - // burn_amount, - // )?; for i in 0..TOKEN_COUNT { let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); @@ -367,41 +235,9 @@ pub fn handle_remove_exact_output( user_token_account, exact_output_amounts[i], )?; - // if exact_output_amounts[i] > 0 { - // // token::transfer( - // // CpiContext::new_with_signer( - // // ctx.accounts.token_program.to_account_info(), - // // token::Transfer { - // // // source - // // from: pool_token_account.to_account_info(), - // // to: user_token_account.to_account_info(), - // // authority: ctx.accounts.pool.to_account_info(), - // // }, - // // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // // ), - // // exact_output_amounts[i], - // // )?; - // } } ctx.accounts.swap.mint_lp_tokens(&ctx.accounts.swap.governance_fee, governance_mint_amount)?; - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.lp_mint.to_account_info(), - // to: ctx.accounts.governance_fee.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - // let pool = &mut ctx.accounts.pool; - // pool.previous_depth = latest_depth; ctx.accounts.swap.update_previous_depth(latest_depth)?; Ok(exact_output_amounts.into()) } @@ -422,11 +258,6 @@ pub fn handle_remove_uniform( require_gt!(exact_burn_amount, 0u64, PoolError::InvalidRemoveUniformParameters); require_gte!(lp_total_supply, exact_burn_amount, PoolError::InvalidRemoveUniformParameters); - // let pool = &ctx.accounts.pool; - // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - //Note: this is the only ix that can be called even if the pool is paused. let pool = &ctx.accounts.swap.pool; let user_token_accounts = &[&ctx.accounts.swap.user_token_account_0, &ctx.accounts.swap.user_token_account_1]; @@ -443,12 +274,6 @@ pub fn handle_remove_uniform( / 10u128.pow(DECIMAL_UPSHIFT); let latest_depth = pool.previous_depth - user_depth; - // let user_token_account_0 = &ctx.accounts.user_token_account_0; - // let user_token_account_1 = &ctx.accounts.user_token_account_1; - // let user_token_accounts = [user_token_account_0, user_token_account_1]; - // - // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); let mut output_amounts = vec![]; @@ -458,37 +283,11 @@ pub fn handle_remove_uniform( output_amounts.push(output_amount); require_gte!(output_amount, minimum_output_amounts[i], PoolError::OutsideSpecifiedLimits); ctx.accounts.swap.transfer_from_pool_to_user(&pool_token_account, &user_token_account, output_amount)?; - // token::transfer( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: pool_token_account.to_account_info(), - // to: user_token_account.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // output_amount, - // )?; } ctx.accounts.burn_user_lp_tokens(exact_burn_amount)?; - // token::burn( - // CpiContext::new( - // ctx.accounts.token_program.to_account_info(), - // token::Burn { - // mint: ctx.accounts.lp_mint.to_account_info(), - // from: ctx.accounts.user_lp_token_account.to_account_info(), - // authority: ctx.accounts.user_transfer_authority.to_account_info(), - // }, - // ), - // exact_burn_amount, - // )?; + ctx.accounts.swap.update_previous_depth(latest_depth)?; - // - // let pool = &mut ctx.accounts.pool; - // pool.previous_depth = latest_depth; Ok(output_amounts) } diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index f4a61a50d..d80a6a905 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -24,14 +24,6 @@ pub mod state; // #[macro_use] mod macros; -//Note - using this b/c of not all bytes read error. found from using this - https://brson.github.io/2021/06/08/rust-on-solana -// use solana_program::borsh::try_from_slice_unchecked; -// const ENACT_DELAY: UnixTimestamp = 3 * 86400; -// const MAX_DECIMAL_DIFFERENCE: u8 = 8; -// -// type AtomicT = u64; -// type DecT = DecimalU64; - pub const TOKEN_COUNT: usize = 2; //TODO: option to have separate programIds depending on cluster. probably not needed and should keep the same @@ -72,18 +64,6 @@ pub mod two_pool { handle_initialize(ctx, amp_factor, lp_fee, governance_fee) } - // #[access_control(Add::accounts(&ctx))] - // pub fn add( - // ctx: Context, - // input_amounts: [u64; TOKEN_COUNT], - // minimum_mint_amount: u64, - // // params: AddParams - // ) -> Result { - // let params = AddParams { input_amounts, minimum_mint_amount }; - // handle_add_old(ctx, params) - // // handle_add(ctx, input_amounts, minimum_mint_amount) - // } - // #[access_control(AddOrRemove::accounts(&ctx))] pub fn add(ctx: Context, input_amounts: [u64; TOKEN_COUNT], minimum_mint_amount: u64) -> Result { let params = AddParams { input_amounts, minimum_mint_amount }; @@ -91,22 +71,6 @@ pub mod two_pool { // handle_add(ctx, input_amounts, minimum_mint_amount) } - // #[access_control(SwapExactInput::accounts(&ctx))] - // pub fn swap_exact_input( - // ctx: Context, - // exact_input_amounts: [u64; TOKEN_COUNT], - // output_token_index: u8, - // minimum_output_amount: u64, - // // params: SwapExactInputParams, - // ) -> Result { - // let params = SwapExactInputParams { exact_input_amounts, output_token_index, minimum_output_amount }; - // handle_swap_exact_input(ctx, params) - // // let output_token_index = params.output_token_index as usize; - // // let exact_input_amounts = params.exact_input_amounts; - // // let minimum_output_amount = params.minimum_output_amount; - // // handle_swap_exact_input(ctx, params) - // } - // #[access_control(ctx.accounts.validate())] pub fn swap_exact_input( ctx: Context, @@ -122,26 +86,6 @@ pub mod two_pool { // let minimum_output_amount = params.minimum_output_amount; // handle_swap_exact_input(ctx, params) } - // pub fn swap_exact_input( - // ctx: Context, - // params: SwapExactInputParams, - // ) -> Result { - // handle_swap_exact_input(ctx, params) - // } - - //returning cpi data from this is a little redundant since it's already passed in the params - //but keeping for parity with other ixs - // note using Vec instead of [u64; TOKEN_COUNT] since anchor can't handle it properly. - // #[access_control(SwapExactOutput::accounts(&ctx))] - // pub fn swap_exact_output( - // ctx: Context, - // maximum_input_amount: u64, - // input_token_index: u8, - // exact_output_amounts: [u64; TOKEN_COUNT], // params: SwapExactOutputParams, - // ) -> Result> { - // let params = SwapExactOutputParams { maximum_input_amount, input_token_index, exact_output_amounts }; - // handle_swap_exact_output(ctx, params) - // } // #[access_control(ctx.accounts.validate())] pub fn swap_exact_output( @@ -164,18 +108,6 @@ pub mod two_pool { handle_remove_uniform(ctx, params) } - // #[access_control(RemoveExactBurn::accounts(&ctx))] - // pub fn remove_exact_burn( - // ctx: Context, - // exact_burn_amount: u64, - // output_token_index: u8, - // minimum_output_amount: u64, - // // params: RemoveExactBurnParams, - // ) -> Result { - // let params = RemoveExactBurnParams { exact_burn_amount, output_token_index, minimum_output_amount }; - // handle_remove_exact_burn(ctx, params) - // } - // #[access_control(AddOrRemove::accounts(&ctx))] pub fn remove_exact_burn( ctx: Context, From da26acfcf1f461151cf1dde06b2251767fce52ea Mon Sep 17 00:00:00 2001 From: swimricky Date: Tue, 25 Oct 2022 13:15:16 -0400 Subject: [PATCH 15/17] refactor: remove more commented out code --- .../two-pool/src/instructions/defi/swap.rs | 162 +----------------- 1 file changed, 1 insertion(+), 161 deletions(-) diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs b/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs index d0c31254e..4ee4b8fc6 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/defi/swap.rs @@ -72,32 +72,6 @@ pub struct Swap<'info> { } impl<'info> Swap<'info> { - // pub fn validate(&self) -> Result<()> { - // let pool_state = &self.pool; - // - // require_keys_eq!( - // self.pool_token_account_0.key(), - // pool_state.token_keys[0], - // PoolError::PoolTokenAccountExpected - // ); - // require_keys_eq!( - // self.pool_token_account_1.key(), - // pool_state.token_keys[1], - // PoolError::PoolTokenAccountExpected - // ); - // require_keys_eq!(self.lp_mint.key(), pool_state.lp_mint_key, PoolError::InvalidMintAccount); - // require_keys_eq!( - // self.governance_fee.key(), - // pool_state.governance_fee_key, - // PoolError::InvalidGovernanceFeeAccount - // ); - // msg!("finished accounts context check"); - // Ok(()) - // } - // pub fn accounts(ctx: &Context) -> Result<()> { - // ctx.accounts.validate() - // } - pub fn update_previous_depth(&mut self, latest_depth: u128) -> Result<()> { let pool_state = &mut self.pool; pool_state.previous_depth = latest_depth; @@ -125,22 +99,6 @@ impl<'info> Swap<'info> { )?; } Ok(()) - - // let seeds = gen_pool_signer_seeds( - // &self.pool.key(), - // &self.pool.token_mint_keys[0], - // &self.pool.token_mint_keys[1], - // &self.lp_mint.key(), - // ); - // let cpi_accounts = Transfer { - // from: user_token_account.to_account_info(), - // to: pool_token_account.to_account_info(), - // authority: self.user_transfer_authority.to_account_info(), - // }; - // let cpi_program = self.token_program.to_account_info(); - // let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); - // token::transfer(cpi_ctx, amount)?; - // Ok(()) } pub fn transfer_from_pool_to_user( @@ -185,27 +143,6 @@ impl<'info> Swap<'info> { } Ok(()) } - - // pub fn burn_lp_tokens(&self, from: &Account<'info, TokenAccount>, authority: ) - - // pub fn mint_governance_fee(&self, governance_mint_amount: u64) -> Result<()> { - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // self.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: self.lp_mint.to_account_info(), - // to: self.governance_fee.to_account_info(), - // authority: self.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(self.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - // Ok(()) - // } } #[derive(AnchorSerialize, AnchorDeserialize)] @@ -236,16 +173,6 @@ pub fn handle_swap_exact_input( let pool = &ctx.accounts.pool; require!(!pool.is_paused, PoolError::PoolIsPaused); - // let pool_token_account_0 = &ctx.accounts.pool_token_account_0; - // let pool_token_account_1 = &ctx.accounts.pool_token_account_1; - // let pool_balances = [ctx.accounts.pool_token_account_0.amount, ctx.accounts.pool_token_account_1.amount]; - // - // let user_token_account_0 = &ctx.accounts.user_token_account_0; - // let user_token_account_1 = &ctx.accounts.user_token_account_1; - // let user_token_accounts = [user_token_account_0, user_token_account_1]; - // - // let pool_token_accounts = [pool_token_account_0, pool_token_account_1]; - let user_token_accounts = &[&ctx.accounts.user_token_account_0, &ctx.accounts.user_token_account_1]; let pool_token_accounts = &[&ctx.accounts.pool_token_account_0, &ctx.accounts.pool_token_account_1]; let pool_balances = pool_token_accounts.map(|account| account.amount); @@ -277,20 +204,6 @@ pub fn handle_swap_exact_input( let user_transfer_auth = &ctx.accounts.user_transfer_authority; for i in 0..TOKEN_COUNT { let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); - // if exact_input_amounts[i] > 0 { - // token::transfer( - // CpiContext::new( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: user_token_account.to_account_info(), - // to: pool_token_account.to_account_info(), - // authority: ctx.accounts.user_transfer_authority.to_account_info(), - // }, - // ), - // exact_input_amounts[i], - // )?; - // } ctx.accounts.transfer_from_user_to_pool( user_token_account, user_transfer_auth, @@ -300,40 +213,11 @@ pub fn handle_swap_exact_input( } let user_output_token_account = user_token_accounts[output_token_index]; let pool_output_token_account = pool_token_accounts[output_token_index]; + ctx.accounts.transfer_from_pool_to_user(&pool_output_token_account, &user_output_token_account, output_amount)?; - // token::transfer( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: pool_output_token_account.to_account_info(), - // to: user_output_token_account.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // output_amount, - // )?; ctx.accounts.mint_lp_tokens(&ctx.accounts.governance_fee, governance_mint_amount)?; - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.lp_mint.to_account_info(), - // to: ctx.accounts.governance_fee.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - // let pool = &mut ctx.accounts.pool; - // pool.previous_depth = latest_depth; ctx.accounts.update_previous_depth(latest_depth)?; Ok(output_amount) } @@ -411,60 +295,16 @@ pub fn handle_swap_exact_output( pool_input_token_account, input_amount, )?; - // token::transfer( - // CpiContext::new( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: user_input_token_account.to_account_info(), - // to: pool_input_token_account.to_account_info(), - // authority: user_transfer_auth.to_account_info(), - // }, - // ), - // input_amount, - // )?; let mut token_accounts = zip(user_token_accounts.into_iter(), pool_token_accounts.into_iter()); for i in 0..TOKEN_COUNT { let (user_token_account, pool_token_account) = token_accounts.next().unwrap(); ctx.accounts.transfer_from_pool_to_user(pool_token_account, user_token_account, exact_output_amounts[i])?; - // if exact_output_amounts[i] > 0 { - // token::transfer( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::Transfer { - // // source - // from: pool_token_account.to_account_info(), - // to: user_token_account.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // exact_output_amounts[i], - // )?; - // } } ctx.accounts.mint_lp_tokens(&ctx.accounts.governance_fee, governance_mint_amount)?; - // if governance_mint_amount > 0 { - // token::mint_to( - // CpiContext::new_with_signer( - // ctx.accounts.token_program.to_account_info(), - // token::MintTo { - // // source - // mint: ctx.accounts.lp_mint.to_account_info(), - // to: ctx.accounts.governance_fee.to_account_info(), - // authority: ctx.accounts.pool.to_account_info(), - // }, - // &[&gen_pool_signer_seeds!(ctx.accounts.pool)[..]], - // ), - // governance_mint_amount, - // )?; - // } - // let pool = &mut ctx.accounts.pool; - // pool.previous_depth = latest_depth; ctx.accounts.update_previous_depth(latest_depth)?; Ok(exact_output_amounts.into()) } From 8286ba6b157420ae14c036f59a15d1121e2f71c7 Mon Sep 17 00:00:00 2001 From: swimricky Date: Wed, 26 Oct 2022 08:45:42 -0400 Subject: [PATCH 16/17] refactor(solana-contracts): remove unnecessary contexts for gov ixs --- .../programs/two-pool/src/error.rs | 4 + .../governance/adjust_amp_factor.rs | 31 - .../change_governance_fee_account.rs | 37 - .../governance/change_pause_key.rs | 19 - .../governance/common_governance.rs | 32 - .../governance/create_lp_metadata.rs | 128 -- .../governance/enact_fee_change.rs | 35 - .../governance/enact_governance_transition.rs | 31 - .../src/instructions/governance/governance.rs | 190 +++ .../instructions/governance/lp_metadata.rs | 264 +++++ .../src/instructions/governance/mod.rs | 37 +- .../src/instructions/governance/mpl.rs | 94 -- .../governance/prepare_fee_change.rs | 43 - .../prepare_governance_transition.rs | 31 - .../src/instructions/governance/set_paused.rs | 33 - .../governance/update_lp_metadata.rs | 69 -- .../programs/two-pool/src/lib.rs | 57 +- .../two-pool/tests/governance_test.rs | 129 +- .../src/__tests__/twoPool/pool.test.ts | 51 +- .../src/artifacts/two_pool.json | 508 ++++---- .../src/artifacts/two_pool.ts | 1048 ++++++++--------- 21 files changed, 1394 insertions(+), 1477 deletions(-) delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/change_pause_key.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs create mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs create mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/lp_metadata.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_fee_change.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs delete mode 100644 packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs diff --git a/packages/solana-contracts/programs/two-pool/src/error.rs b/packages/solana-contracts/programs/two-pool/src/error.rs index 9f3dc5563..6ef147de6 100644 --- a/packages/solana-contracts/programs/two-pool/src/error.rs +++ b/packages/solana-contracts/programs/two-pool/src/error.rs @@ -74,6 +74,8 @@ pub enum PoolError { InvalidTokenIndex, #[msg("Invalid Pause Key")] InvalidPauseKey, + #[msg("Invalid New Pause Key")] + InvalidNewPauseKey, #[msg("Not a valid Switchboard account")] InvalidSwitchboardAccount, #[msg("Switchboard feed has not been updated in 5 minutes")] @@ -86,6 +88,8 @@ pub enum PoolError { ConversionError, #[msg("Burn amount exceeds lp total supply")] BurnAmountExceedsTotalSupply, + #[msg("Invalid Upcoming Governance Key")] + InvalidUpcomingGovernanceKey, } // impl From for ProgramError { diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs deleted file mode 100644 index 16a2c25c8..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/adjust_amp_factor.rs +++ /dev/null @@ -1,31 +0,0 @@ -use { - crate::{ - common_governance::*, get_current_ts, DecimalU64Anchor, - }, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct AdjustAmpFactor<'info> { - pub common_governance: CommonGovernance<'info>, -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct AdjustAmpFactorParams { - pub target_ts: i64, - pub target_value: DecimalU64Anchor, -} - -impl<'info> AdjustAmpFactor<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_adjust_amp_factor(ctx: Context, params: AdjustAmpFactorParams) -> Result<()> { - let pool = &mut ctx.accounts.common_governance.pool; - let current_ts = get_current_ts()?; - pool.amp_factor.set_target(current_ts, params.target_value.into(), params.target_ts)?; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs deleted file mode 100644 index 212b91ee8..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_governance_fee_account.rs +++ /dev/null @@ -1,37 +0,0 @@ -use { - crate::{ - common_governance::*, error::*, - }, - anchor_lang::prelude::*, - anchor_spl::token::TokenAccount, -}; - -#[derive(Accounts)] -pub struct ChangeGovernanceFeeAccount<'info> { - pub common_governance: CommonGovernance<'info>, - #[account( - token::mint = common_governance.pool.lp_mint_key - )] - pub new_governance_fee: Account<'info, TokenAccount>, -} - -impl<'info> ChangeGovernanceFeeAccount<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_change_governance_fee_account( - ctx: Context, - new_governance_fee_key: Pubkey, -) -> Result<()> { - require_keys_eq!( - ctx.accounts.new_governance_fee.key(), - new_governance_fee_key, - PoolError::InvalidGovernanceFeeAccount - ); - let pool = &mut ctx.accounts.common_governance.pool; - pool.governance_fee_key = new_governance_fee_key; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_pause_key.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_pause_key.rs deleted file mode 100644 index 06dd4e94c..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/change_pause_key.rs +++ /dev/null @@ -1,19 +0,0 @@ -use {crate::common_governance::*, anchor_lang::prelude::*}; - -#[derive(Accounts)] -pub struct ChangePauseKey<'info> { - pub common_governance: CommonGovernance<'info>, -} - -impl<'info> ChangePauseKey<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { - let pool = &mut ctx.accounts.common_governance.pool; - pool.pause_key = new_pause_key; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs deleted file mode 100644 index 7fa2500ce..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/common_governance.rs +++ /dev/null @@ -1,32 +0,0 @@ -use { - crate::{error::*, TwoPool}, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct CommonGovernance<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool.get_token_mint_0().as_ref(), - pool.get_token_mint_1().as_ref(), - pool.lp_mint_key.as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - - pub governance: Signer<'info>, -} - -impl<'info> CommonGovernance<'info> { - pub fn accounts(common_governance: &CommonGovernance) -> Result<()> { - require_keys_eq!( - common_governance.governance.key(), - common_governance.pool.governance_key, - PoolError::InvalidGovernanceAccount - ); - Ok(()) - } -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs deleted file mode 100644 index 1e0eb3771..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/create_lp_metadata.rs +++ /dev/null @@ -1,128 +0,0 @@ -use { - crate::{common_governance::*, error::*, gen_pool_signer_seeds, AnchorDataV2}, - anchor_lang::prelude::*, - anchor_spl::{ - metadata::{create_metadata_accounts_v2, CreateMetadataAccountsV2, Metadata}, - token::Mint, - }, -}; - -#[derive(Accounts)] -pub struct CreateLpMetadata<'info> { - pub common_governance: CommonGovernance<'info>, - /// this didn't work for some reason. - pub create_metadata_accounts: CreateMetadataAccounts<'info>, - // /// CHECK: Checked in CPI - // pub metadata: AccountInfo<'info>, - // pub mint: Account<'info, Mint>, - // // pub mint_authority: AccountInfo<'info>, - // #[account(mut)] - // pub payer: Signer<'info>, - // // ///CHECK: Checked in CPI - // // pub update_authority: AccountInfo<'info>, - // pub system_program: Program<'info, System>, - // pub rent: Sysvar<'info, Rent>, - #[account( - executable, - address = Metadata::id() - )] - ///CHECK: mpl_token_metadata program - pub mpl_token_metadata: Program<'info, Metadata>, -} - -//pub fn find_metadata_account(mint: &Pubkey) -> (Pubkey, u8) { -// Pubkey::find_program_address( -// &[PREFIX.as_bytes(), crate::id().as_ref(), mint.as_ref()], -// &crate::id(), -// ) -// } - -#[derive(Accounts)] -pub struct CreateMetadataAccounts<'info> { - #[account(mut)] - /// CHECK: Checked in CPI - pub metadata: UncheckedAccount<'info>, - pub mint: Account<'info, Mint>, - /// CHECK: Checked in CPI - pub mint_authority: UncheckedAccount<'info>, - #[account(mut)] - pub payer: Signer<'info>, - ///CHECK: Checked in CPI - pub update_authority: UncheckedAccount<'info>, - pub system_program: Program<'info, System>, - pub rent: Sysvar<'info, Rent>, -} - -impl<'info> CreateMetadataAccounts<'info> { - pub fn to_create_metadata_accounts_v2(&self) -> CreateMetadataAccountsV2<'info> { - CreateMetadataAccountsV2 { - metadata: self.metadata.to_account_info(), - mint: self.mint.to_account_info(), - mint_authority: self.mint_authority.to_account_info(), - payer: self.payer.to_account_info(), - update_authority: self.update_authority.to_account_info(), - system_program: self.system_program.to_account_info(), - rent: self.rent.to_account_info(), - } - } -} - -// impl<'info> From for CreateMetadataAccountsV2<'info> { -// fn from(ctx: Context) -> Self<'info> { -// CreateMetadataAccountsV2 { -// metadata: ctx.accounts.metadata.to_account_info(), -// mint: ctx.accounts.mint.to_account_info(), -// mint_authority: ctx.accounts.mint_authority.to_account_info(), -// payer: ctx.accounts.payer.to_account_info(), -// update_authority: ctx.accounts.update_authority.to_account_info(), -// system_program: ctx.accounts.system_program.to_account_info(), -// rent: ctx.accounts.rent.to_account_info(), -// } -// } -// -// fn from(accounts: CreateMetadataAccounts) -> Self { -// CreateMetadataAccountsV2 { -// metadata: accounts.metadata.to_account_info(), -// mint: accounts.mint.to_account_info(), -// mint_authority: accounts.mint_authority.to_account_info(), -// payer: accounts.payer.to_account_info(), -// update_authority: accounts.update_authority.to_account_info(), -// system_program: accounts.system_program.to_account_info(), -// rent: accounts.rent.to_account_info(), -// } -// } -// } - -impl<'info> CreateLpMetadata<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - require_keys_eq!( - ctx.accounts.common_governance.pool.lp_mint_key.key(), - ctx.accounts.create_metadata_accounts.mint.key(), - PoolError::InvalidMintAccount - ); - Ok(()) - } -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct CreateLpMetadataParams { - pub data: AnchorDataV2, - pub is_mutable: bool, - //default to true? update auth is pool state itself and should be a signer - pub update_authority_is_signer: bool, -} - -pub fn handle_create_lp_metadata(ctx: Context, params: CreateLpMetadataParams) -> Result<()> { - create_metadata_accounts_v2( - CpiContext::new_with_signer( - ctx.accounts.mpl_token_metadata.to_account_info(), - ctx.accounts.create_metadata_accounts.to_create_metadata_accounts_v2(), - &[&gen_pool_signer_seeds!(ctx.accounts.common_governance.pool)[..]], - ), - params.data.into(), - params.is_mutable, - params.update_authority_is_signer, - )?; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs deleted file mode 100644 index f2237e2bf..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_fee_change.rs +++ /dev/null @@ -1,35 +0,0 @@ -use { - crate::{ - common_governance::*, error::*, get_current_ts, PoolFee, - }, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct EnactFeeChange<'info> { - pub common_governance: CommonGovernance<'info>, -} - -impl<'info> EnactFeeChange<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_enact_fee_change(ctx: Context) -> Result<()> { - let pool = &mut ctx.accounts.common_governance.pool; - require_neq!(pool.fee_transition_ts, 0i64, PoolError::InvalidEnact); - let current_ts = get_current_ts()?; - require_gte!(current_ts, pool.fee_transition_ts, PoolError::InsufficientDelay); - // Note: no longer allowing pubkey::default() as governance_fee_account even if gov_fee == 0 - // if pool.prepared_governance_fee.get() > DecimalU64::from(0) { - // require_keys_neq!(pool.governance_fee_key, Pubkey::default(), PoolError::InvalidGovernanceFeeAccount); - // } - pool.lp_fee = pool.prepared_lp_fee.clone(); - pool.governance_fee = pool.prepared_governance_fee.clone(); - pool.prepared_lp_fee = PoolFee::default(); - pool.prepared_governance_fee = PoolFee::default(); - pool.fee_transition_ts = 0i64; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs deleted file mode 100644 index 329fed2de..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/enact_governance_transition.rs +++ /dev/null @@ -1,31 +0,0 @@ -use { - crate::{common_governance::*, error::*, get_current_ts}, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct EnactGovernanceTransition<'info> { - pub common_governance: CommonGovernance<'info>, -} - -impl<'info> EnactGovernanceTransition<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { - let pool = &mut ctx.accounts.common_governance.pool; - require_neq!(pool.governance_transition_ts, 0i64, PoolError::InvalidEnact); - require_keys_neq!(pool.prepared_governance_key, Pubkey::default(), PoolError::InvalidEnact); - - let current_ts = get_current_ts()?; - - require_gte!(current_ts, pool.governance_transition_ts, PoolError::InsufficientDelay); - - pool.governance_key = pool.prepared_governance_key; - pool.prepared_governance_key = Pubkey::default(); - pool.governance_transition_ts = 0i64; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs new file mode 100644 index 000000000..23ef6ff86 --- /dev/null +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs @@ -0,0 +1,190 @@ +use { + crate::{ + decimal::DecimalU64, + error::*, + instructions::{get_current_ts, ENACT_DELAY}, + pool_fee::PoolFee, + DecimalU64Anchor, TwoPool, + }, + anchor_lang::prelude::*, + anchor_spl::token::TokenAccount, +}; + +#[derive(Accounts)] +pub struct Governance<'info> { + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool.get_token_mint_0().as_ref(), + pool.get_token_mint_1().as_ref(), + pool.lp_mint_key.as_ref(), + ], + bump = pool.bump, + has_one = governance_key @ PoolError::InvalidGovernanceAccount + )] + pub pool: Account<'info, TwoPool>, + + pub governance_key: Signer<'info>, +} + +/* Update Amp Factor */ + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct AdjustAmpFactorParams { + pub target_ts: i64, + pub target_value: DecimalU64Anchor, +} + +pub fn handle_adjust_amp_factor(ctx: Context, params: AdjustAmpFactorParams) -> Result<()> { + let pool = &mut ctx.accounts.pool; + let current_ts = get_current_ts()?; + pool.amp_factor.set_target(current_ts, params.target_value.into(), params.target_ts)?; + Ok(()) +} + +/* Update Fees */ + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct PrepareFeeChangeParams { + pub lp_fee: DecimalU64Anchor, + pub governance_fee: DecimalU64Anchor, +} + +pub fn handle_prepare_fee_change( + ctx: Context, + // params: PrepareFeeChangeParams, + lp_fee: DecimalU64Anchor, + governance_fee: DecimalU64Anchor, +) -> Result<()> { + let lp_fee: DecimalU64 = lp_fee.into(); + let governance_fee: DecimalU64 = governance_fee.into(); + require_gt!(DecimalU64::from(1), lp_fee + governance_fee, PoolError::InvalidFeeInput); + let pool = &mut ctx.accounts.pool; + pool.prepared_lp_fee = PoolFee::new(lp_fee)?; + pool.prepared_governance_fee = PoolFee::new(governance_fee)?; + + let current_ts = get_current_ts()?; + + pool.fee_transition_ts = current_ts + ENACT_DELAY; + Ok(()) +} + +pub fn handle_enact_fee_change(ctx: Context) -> Result<()> { + let pool = &mut ctx.accounts.pool; + require_neq!(pool.fee_transition_ts, 0i64, PoolError::InvalidEnact); + let current_ts = get_current_ts()?; + require_gte!(current_ts, pool.fee_transition_ts, PoolError::InsufficientDelay); + // Note: no longer allowing pubkey::default() as governance_fee_account even if gov_fee == 0 + // if pool.prepared_governance_fee.get() > DecimalU64::from(0) { + // require_keys_neq!(pool.governance_fee_key, Pubkey::default(), PoolError::InvalidGovernanceFeeAccount); + // } + pool.lp_fee = pool.prepared_lp_fee.clone(); + pool.governance_fee = pool.prepared_governance_fee.clone(); + pool.prepared_lp_fee = PoolFee::default(); + pool.prepared_governance_fee = PoolFee::default(); + pool.fee_transition_ts = 0i64; + Ok(()) +} + +/* Update Governance Fee Account */ + +#[derive(Accounts)] +pub struct ChangeGovernanceFeeAccount<'info> { + pub governance: Governance<'info>, + #[account(token::mint = governance.pool.lp_mint_key)] + pub new_governance_fee: Account<'info, TokenAccount>, +} + +pub fn handle_change_governance_fee_account( + ctx: Context, + new_governance_fee_key: Pubkey, +) -> Result<()> { + require_keys_eq!( + ctx.accounts.new_governance_fee.key(), + new_governance_fee_key, + PoolError::InvalidGovernanceFeeAccount + ); + let pool = &mut ctx.accounts.governance.pool; + pool.governance_fee_key = new_governance_fee_key; + Ok(()) +} + +/* Update Governance Account */ + +#[derive(Accounts)] +pub struct PrepareGovernanceTransition<'info> { + pub governance: Governance<'info>, + pub upcoming_governance_key: Signer<'info>, +} + +pub fn handle_prepare_governance_transition( + ctx: Context, + upcoming_governance_key: Pubkey, +) -> Result<()> { + require_keys_eq!( + upcoming_governance_key, + ctx.accounts.upcoming_governance_key.key(), + PoolError::InvalidUpcomingGovernanceKey + ); + let pool = &mut ctx.accounts.governance.pool; + pool.prepared_governance_key = upcoming_governance_key; + + let current_ts = get_current_ts()?; + pool.governance_transition_ts = current_ts + ENACT_DELAY; + + Ok(()) +} + +pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { + let pool = &mut ctx.accounts.pool; + require_neq!(pool.governance_transition_ts, 0i64, PoolError::InvalidEnact); + require_keys_neq!(pool.prepared_governance_key, Pubkey::default(), PoolError::InvalidEnact); + + let current_ts = get_current_ts()?; + + require_gte!(current_ts, pool.governance_transition_ts, PoolError::InsufficientDelay); + + pool.governance_key = pool.prepared_governance_key; + pool.prepared_governance_key = Pubkey::default(); + pool.governance_transition_ts = 0i64; + Ok(()) +} + +/* Pause */ + +#[derive(Accounts)] +pub struct ChangePauseKey<'info> { + pub governance: Governance<'info>, + pub new_pause_key: Signer<'info>, +} + +pub fn handle_change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { + require_keys_eq!(ctx.accounts.new_pause_key.key(), new_pause_key, PoolError::InvalidNewPauseKey); + let pool = &mut ctx.accounts.governance.pool; + pool.pause_key = new_pause_key; + Ok(()) +} + +#[derive(Accounts)] +pub struct SetPaused<'info> { + #[account( + mut, + seeds = [ + b"two_pool".as_ref(), + pool.get_token_mint_0().as_ref(), + pool.get_token_mint_1().as_ref(), + pool.lp_mint_key.as_ref(), + ], + bump = pool.bump, + has_one = pause_key @ PoolError::InvalidPauseKey + )] + pub pool: Account<'info, TwoPool>, + pub pause_key: Signer<'info>, +} + +pub fn handle_set_paused(ctx: Context, paused: bool) -> Result<()> { + let pool = &mut ctx.accounts.pool; + pool.is_paused = paused; + Ok(()) +} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/lp_metadata.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/lp_metadata.rs new file mode 100644 index 000000000..8cfd1e4db --- /dev/null +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/lp_metadata.rs @@ -0,0 +1,264 @@ +use { + crate::{error::*, gen_pool_signer_seeds, governance::*}, + anchor_lang::prelude::*, + anchor_spl::{ + metadata::{ + create_metadata_accounts_v2, update_metadata_accounts_v2, CreateMetadataAccountsV2, Metadata, + UpdateMetadataAccountsV2, + }, + token::Mint, + }, + mpl_token_metadata::state::{Collection, Creator, DataV2, UseMethod, Uses}, +}; + +#[derive(Accounts)] +pub struct CreateLpMetadata<'info> { + pub governance: Governance<'info>, + /// this didn't work for some reason. + pub create_metadata_accounts: CreateMetadataAccounts<'info>, + pub mpl_token_metadata: Program<'info, Metadata>, +} + +//pub fn find_metadata_account(mint: &Pubkey) -> (Pubkey, u8) { +// Pubkey::find_program_address( +// &[PREFIX.as_bytes(), crate::id().as_ref(), mint.as_ref()], +// &crate::id(), +// ) +// } + +#[derive(Accounts)] +pub struct CreateMetadataAccounts<'info> { + #[account(mut)] + /// CHECK: Checked in CPI + pub metadata: UncheckedAccount<'info>, + pub mint: Account<'info, Mint>, + /// CHECK: Checked in CPI + pub mint_authority: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, + ///CHECK: Checked in CPI + pub update_authority: UncheckedAccount<'info>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent>, +} + +impl<'info> CreateMetadataAccounts<'info> { + pub fn to_create_metadata_accounts_v2(&self) -> CreateMetadataAccountsV2<'info> { + CreateMetadataAccountsV2 { + metadata: self.metadata.to_account_info(), + mint: self.mint.to_account_info(), + mint_authority: self.mint_authority.to_account_info(), + payer: self.payer.to_account_info(), + update_authority: self.update_authority.to_account_info(), + system_program: self.system_program.to_account_info(), + rent: self.rent.to_account_info(), + } + } +} + +// impl<'info> From for CreateMetadataAccountsV2<'info> { +// fn from(ctx: Context) -> Self<'info> { +// CreateMetadataAccountsV2 { +// metadata: ctx.accounts.metadata.to_account_info(), +// mint: ctx.accounts.mint.to_account_info(), +// mint_authority: ctx.accounts.mint_authority.to_account_info(), +// payer: ctx.accounts.payer.to_account_info(), +// update_authority: ctx.accounts.update_authority.to_account_info(), +// system_program: ctx.accounts.system_program.to_account_info(), +// rent: ctx.accounts.rent.to_account_info(), +// } +// } +// +// fn from(accounts: CreateMetadataAccounts) -> Self { +// CreateMetadataAccountsV2 { +// metadata: accounts.metadata.to_account_info(), +// mint: accounts.mint.to_account_info(), +// mint_authority: accounts.mint_authority.to_account_info(), +// payer: accounts.payer.to_account_info(), +// update_authority: accounts.update_authority.to_account_info(), +// system_program: accounts.system_program.to_account_info(), +// rent: accounts.rent.to_account_info(), +// } +// } +// } + +impl<'info> CreateLpMetadata<'info> { + pub fn accounts(ctx: &Context) -> Result<()> { + require_keys_eq!( + ctx.accounts.governance.pool.lp_mint_key.key(), + ctx.accounts.create_metadata_accounts.mint.key(), + PoolError::InvalidMintAccount + ); + Ok(()) + } +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct CreateLpMetadataParams { + pub data: AnchorDataV2, + pub is_mutable: bool, + //default to true? update auth is pool state itself and should be a signer + pub update_authority_is_signer: bool, +} + +pub fn handle_create_lp_metadata(ctx: Context, params: CreateLpMetadataParams) -> Result<()> { + create_metadata_accounts_v2( + CpiContext::new_with_signer( + ctx.accounts.mpl_token_metadata.to_account_info(), + ctx.accounts.create_metadata_accounts.to_create_metadata_accounts_v2(), + &[&gen_pool_signer_seeds!(ctx.accounts.governance.pool)[..]], + ), + params.data.into(), + params.is_mutable, + params.update_authority_is_signer, + )?; + Ok(()) +} + +#[derive(Accounts)] +pub struct UpdateLpMetadata<'info> { + pub governance: Governance<'info>, + pub update_metadata_accounts: UpdateMetadataAccounts<'info>, + #[account( + executable, + address = Metadata::id() + )] + ///CHECK: mpl_token_metadata program + pub mpl_token_metadata: Program<'info, Metadata>, +} + +impl<'info> UpdateLpMetadata<'info> { + pub fn accounts(ctx: &Context) -> Result<()> { + Ok(()) + } +} + +#[derive(Accounts)] +pub struct UpdateMetadataAccounts<'info> { + #[account(mut)] + ///CHECK: Checked in CPI + pub metadata: UncheckedAccount<'info>, + /// CHECK: Checked in CPI + pub update_authority: UncheckedAccount<'info>, +} + +impl<'info> UpdateMetadataAccounts<'info> { + pub fn to_update_metadata_accounts_v2(&self) -> UpdateMetadataAccountsV2<'info> { + UpdateMetadataAccountsV2 { + metadata: self.metadata.to_account_info(), + update_authority: self.update_authority.to_account_info(), + } + } +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct UpdateLpMetadataParams { + pub new_update_authority: Option, + pub data: Option, + pub primary_sale_happened: Option, + pub is_mutable: Option, +} + +pub fn handle_update_lp_metadata(ctx: Context, params: UpdateLpMetadataParams) -> Result<()> { + update_metadata_accounts_v2( + CpiContext::new_with_signer( + ctx.accounts.mpl_token_metadata.to_account_info(), + ctx.accounts.update_metadata_accounts.to_update_metadata_accounts_v2(), + &[&gen_pool_signer_seeds!(ctx.accounts.governance.pool)[..]], + ), + params.new_update_authority, + params.data.map(|data| data.into()), + params.primary_sale_happened, + params.is_mutable, + ) +} + +// copied from https://github.com/CalebEverett/nftfactory/blob/master/programs/nftfactory/src/lib.rs + +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone)] +pub struct AnchorDataV2 { + /// The name of the asset + pub name: String, + /// The symbol for the asset + pub symbol: String, + /// URI pointing to JSON representing the asset + pub uri: String, + /// Royalty basis points that goes to creators in secondary sales (0-10000) + pub seller_fee_basis_points: u16, + /// Array of creators, optional + pub creators: Option>, + /// Collection + pub collection: Option, + /// Uses + pub uses: Option, +} + +impl From for DataV2 { + fn from(item: AnchorDataV2) -> Self { + DataV2 { + name: item.name, + symbol: item.symbol, + uri: item.uri, + seller_fee_basis_points: item.seller_fee_basis_points, + creators: item.creators.map(|a| a.into_iter().map(|v| v.into()).collect()), + collection: item.collection.map(|v| v.into()), + uses: item.uses.map(|v| v.into()), + } + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] +pub struct AnchorCreator { + pub address: Pubkey, + pub verified: bool, + // In percentages, NOT basis points ;) Watch out! + pub share: u8, +} + +impl From for Creator { + fn from(item: AnchorCreator) -> Self { + Creator { address: item.address, verified: item.verified, share: item.share } + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] +pub enum AnchorUseMethod { + Burn, + Multiple, + Single, +} + +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] +pub struct AnchorUses { + pub use_method: AnchorUseMethod, + pub remaining: u64, + pub total: u64, +} + +impl From for Uses { + fn from(item: AnchorUses) -> Self { + Uses { use_method: item.use_method.into(), remaining: item.remaining, total: item.total } + } +} + +impl From for UseMethod { + fn from(item: AnchorUseMethod) -> Self { + match item { + AnchorUseMethod::Burn => UseMethod::Burn, + AnchorUseMethod::Multiple => UseMethod::Burn, + AnchorUseMethod::Single => UseMethod::Burn, + } + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] +pub struct AnchorCollection { + pub verified: bool, + pub key: Pubkey, +} + +impl From for Collection { + fn from(item: AnchorCollection) -> Self { + Collection { verified: item.verified, key: item.key } + } +} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs index d9505bb09..d98be4342 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs @@ -1,20 +1,27 @@ pub use { - adjust_amp_factor::*, change_governance_fee_account::*, change_pause_key::*, common_governance::*, - create_lp_metadata::*, enact_fee_change::*, enact_governance_transition::*, mpl::*, prepare_fee_change::*, - prepare_governance_transition::*, set_paused::*, update_lp_metadata::*, + // create_lp_metadata::*, + // adjust_amp_factor::*, change_governance_fee_account::*, change_pause_key::*, + governance::*, + lp_metadata::*, + // enact_fee_change::*, enact_governance_transition::*, + // mpl::*, + // prepare_fee_change::*, + // prepare_governance_transition::*, set_paused::*, + // update_lp_metadata::*, }; -pub mod adjust_amp_factor; -pub mod change_governance_fee_account; -pub mod change_pause_key; -pub mod common_governance; -pub mod create_lp_metadata; -pub mod enact_fee_change; -pub mod enact_governance_transition; -pub mod mpl; -pub mod prepare_fee_change; -pub mod prepare_governance_transition; -pub mod set_paused; -pub mod update_lp_metadata; +// pub mod adjust_amp_factor; +// pub mod change_governance_fee_account; +// pub mod change_pause_key; +// pub mod create_lp_metadata; +pub mod governance; +pub mod lp_metadata; +// pub mod enact_fee_change; +// pub mod enact_governance_transition; +// pub mod mpl; +// pub mod prepare_fee_change; +// pub mod prepare_governance_transition; +// pub mod set_paused; +// pub mod update_lp_metadata; pub const ENACT_DELAY: i64 = 3 * 86400; diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs deleted file mode 100644 index 3da90dd1c..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mpl.rs +++ /dev/null @@ -1,94 +0,0 @@ -use { - anchor_lang::prelude::*, - mpl_token_metadata::state::{Collection, Creator, DataV2, UseMethod, Uses}, -}; - -// copied from https://github.com/CalebEverett/nftfactory/blob/master/programs/nftfactory/src/lib.rs - -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone)] -pub struct AnchorDataV2 { - /// The name of the asset - pub name: String, - /// The symbol for the asset - pub symbol: String, - /// URI pointing to JSON representing the asset - pub uri: String, - /// Royalty basis points that goes to creators in secondary sales (0-10000) - pub seller_fee_basis_points: u16, - /// Array of creators, optional - pub creators: Option>, - /// Collection - pub collection: Option, - /// Uses - pub uses: Option, -} - -impl From for DataV2 { - fn from(item: AnchorDataV2) -> Self { - DataV2 { - name: item.name, - symbol: item.symbol, - uri: item.uri, - seller_fee_basis_points: item.seller_fee_basis_points, - creators: item.creators.map(|a| a.into_iter().map(|v| v.into()).collect()), - collection: item.collection.map(|v| v.into()), - uses: item.uses.map(|v| v.into()), - } - } -} - -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] -pub struct AnchorCreator { - pub address: Pubkey, - pub verified: bool, - // In percentages, NOT basis points ;) Watch out! - pub share: u8, -} - -impl From for Creator { - fn from(item: AnchorCreator) -> Self { - Creator { address: item.address, verified: item.verified, share: item.share } - } -} - -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] -pub enum AnchorUseMethod { - Burn, - Multiple, - Single, -} - -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] -pub struct AnchorUses { - pub use_method: AnchorUseMethod, - pub remaining: u64, - pub total: u64, -} - -impl From for Uses { - fn from(item: AnchorUses) -> Self { - Uses { use_method: item.use_method.into(), remaining: item.remaining, total: item.total } - } -} - -impl From for UseMethod { - fn from(item: AnchorUseMethod) -> Self { - match item { - AnchorUseMethod::Burn => UseMethod::Burn, - AnchorUseMethod::Multiple => UseMethod::Burn, - AnchorUseMethod::Single => UseMethod::Burn, - } - } -} - -#[derive(AnchorSerialize, AnchorDeserialize, PartialEq, Eq, Debug, Clone, Copy)] -pub struct AnchorCollection { - pub verified: bool, - pub key: Pubkey, -} - -impl From for Collection { - fn from(item: AnchorCollection) -> Self { - Collection { verified: item.verified, key: item.key } - } -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_fee_change.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_fee_change.rs deleted file mode 100644 index 4d9da91a6..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_fee_change.rs +++ /dev/null @@ -1,43 +0,0 @@ -use { - crate::{ - common_governance::*, error::*, get_current_ts, governance::ENACT_DELAY, DecimalU64, DecimalU64Anchor, PoolFee, - }, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct PrepareFeeChange<'info> { - pub common_governance: CommonGovernance<'info>, -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct PrepareFeeChangeParams { - pub lp_fee: DecimalU64Anchor, - pub governance_fee: DecimalU64Anchor, -} - -impl<'info> PrepareFeeChange<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_prepare_fee_change( - ctx: Context, - // params: PrepareFeeChangeParams, - lp_fee: DecimalU64Anchor, - governance_fee: DecimalU64Anchor, -) -> Result<()> { - let lp_fee: DecimalU64 = lp_fee.into(); - let governance_fee: DecimalU64 = governance_fee.into(); - require_gt!(DecimalU64::from(1), lp_fee + governance_fee, PoolError::InvalidFeeInput); - let pool = &mut ctx.accounts.common_governance.pool; - pool.prepared_lp_fee = PoolFee::new(lp_fee)?; - pool.prepared_governance_fee = PoolFee::new(governance_fee)?; - - let current_ts = get_current_ts()?; - - pool.fee_transition_ts = current_ts + ENACT_DELAY; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs deleted file mode 100644 index 42beba854..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/prepare_governance_transition.rs +++ /dev/null @@ -1,31 +0,0 @@ -use { - crate::{ - common_governance::*, get_current_ts, governance::ENACT_DELAY, - }, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct PrepareGovernanceTransition<'info> { - pub common_governance: CommonGovernance<'info>, -} - -impl<'info> PrepareGovernanceTransition<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -pub fn handle_prepare_governance_transition( - ctx: Context, - upcoming_governance_key: Pubkey, -) -> Result<()> { - let pool = &mut ctx.accounts.common_governance.pool; - pool.prepared_governance_key = upcoming_governance_key; - - let current_ts = get_current_ts()?; - pool.governance_transition_ts = current_ts + ENACT_DELAY; - - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs deleted file mode 100644 index b25a53dcf..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/set_paused.rs +++ /dev/null @@ -1,33 +0,0 @@ -use { - crate::{error::*, TwoPool}, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct SetPaused<'info> { - #[account( - mut, - seeds = [ - b"two_pool".as_ref(), - pool.get_token_mint_0().as_ref(), - pool.get_token_mint_1().as_ref(), - pool.lp_mint_key.as_ref(), - ], - bump = pool.bump - )] - pub pool: Account<'info, TwoPool>, - pub pause_key: Signer<'info>, -} - -impl<'info> SetPaused<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - require_keys_eq!(ctx.accounts.pause_key.key(), ctx.accounts.pool.pause_key, PoolError::InvalidPauseKey); - Ok(()) - } -} - -pub fn handle_set_paused(ctx: Context, paused: bool) -> Result<()> { - let pool = &mut ctx.accounts.pool; - pool.is_paused = paused; - Ok(()) -} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs deleted file mode 100644 index 7648192b6..000000000 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/update_lp_metadata.rs +++ /dev/null @@ -1,69 +0,0 @@ -use { - crate::{common_governance::*, gen_pool_signer_seeds, AnchorDataV2}, - anchor_lang::prelude::*, - anchor_spl::{ - metadata::{ - update_metadata_accounts_v2, Metadata, - UpdateMetadataAccountsV2, - }, - }, -}; - -#[derive(Accounts)] -pub struct UpdateLpMetadata<'info> { - pub common_governance: CommonGovernance<'info>, - pub update_metadata_accounts: UpdateMetadataAccounts<'info>, - #[account( - executable, - address = Metadata::id() - )] - ///CHECK: mpl_token_metadata program - pub mpl_token_metadata: Program<'info, Metadata>, -} - -impl<'info> UpdateLpMetadata<'info> { - pub fn accounts(ctx: &Context) -> Result<()> { - CommonGovernance::accounts(&ctx.accounts.common_governance)?; - Ok(()) - } -} - -#[derive(Accounts)] -pub struct UpdateMetadataAccounts<'info> { - #[account(mut)] - ///CHECK: Checked in CPI - pub metadata: UncheckedAccount<'info>, - /// CHECK: Checked in CPI - pub update_authority: UncheckedAccount<'info>, -} - -impl<'info> UpdateMetadataAccounts<'info> { - pub fn to_update_metadata_accounts_v2(&self) -> UpdateMetadataAccountsV2<'info> { - UpdateMetadataAccountsV2 { - metadata: self.metadata.to_account_info(), - update_authority: self.update_authority.to_account_info(), - } - } -} - -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct UpdateLpMetadataParams { - pub new_update_authority: Option, - pub data: Option, - pub primary_sale_happened: Option, - pub is_mutable: Option, -} - -pub fn handle_update_lp_metadata(ctx: Context, params: UpdateLpMetadataParams) -> Result<()> { - update_metadata_accounts_v2( - CpiContext::new_with_signer( - ctx.accounts.mpl_token_metadata.to_account_info(), - ctx.accounts.update_metadata_accounts.to_update_metadata_accounts_v2(), - &[&gen_pool_signer_seeds!(ctx.accounts.common_governance.pool)[..]], - ), - params.new_update_authority, - params.data.map(|data| data.into()), - params.primary_sale_happened, - params.is_mutable, - ) -} diff --git a/packages/solana-contracts/programs/two-pool/src/lib.rs b/packages/solana-contracts/programs/two-pool/src/lib.rs index d80a6a905..211df3608 100644 --- a/packages/solana-contracts/programs/two-pool/src/lib.rs +++ b/packages/solana-contracts/programs/two-pool/src/lib.rs @@ -102,13 +102,11 @@ pub mod two_pool { ctx: Context, exact_burn_amount: u64, minimum_output_amounts: [u64; TOKEN_COUNT], - // params: RemoveUniformParams, ) -> Result> { let params = RemoveUniformParams { exact_burn_amount, minimum_output_amounts }; handle_remove_uniform(ctx, params) } - // #[access_control(AddOrRemove::accounts(&ctx))] pub fn remove_exact_burn( ctx: Context, exact_burn_amount: u64, @@ -120,55 +118,46 @@ pub mod two_pool { handle_remove_exact_burn(ctx, params) } - // #[access_control(RemoveExactOutput::accounts(&ctx))] pub fn remove_exact_output( ctx: Context, maximum_burn_amount: u64, exact_output_amounts: [u64; TOKEN_COUNT], - // params: RemoveExactOutputParams, ) -> Result> { let params = RemoveExactOutputParams { maximum_burn_amount, exact_output_amounts }; handle_remove_exact_output(ctx, params) } - //TODO: using 2 instead of TOKEN_COUNT const since anchor can't handle it properly. + //Note: using 2 instead of TOKEN_COUNT const since anchor can't handle it properly. #[access_control(MarginalPrices::accounts(&ctx))] - // pub fn marginal_prices(ctx: Context) -> Result { pub fn marginal_prices(ctx: Context) -> Result<[BorshDecimal; 2]> { handle_marginal_prices(ctx) } /** Governance Ixs **/ - #[access_control(PrepareGovernanceTransition::accounts(&ctx))] - pub fn prepare_governance_transition( - ctx: Context, - upcoming_governance_key: Pubkey, - ) -> Result<()> { - handle_prepare_governance_transition(ctx, upcoming_governance_key) - } - #[access_control(EnactGovernanceTransition::accounts(&ctx))] - pub fn enact_governance_transition(ctx: Context) -> Result<()> { - handle_enact_governance_transition(ctx) + pub fn adjust_amp_factor( + // ctx: Context, + ctx: Context, + target_ts: i64, + target_value: DecimalU64Anchor, + // params: AdjustAmpFactorParams, + ) -> Result<()> { + let params = AdjustAmpFactorParams { target_ts, target_value }; + handle_adjust_amp_factor(ctx, params) } - #[access_control(PrepareFeeChange::accounts(&ctx))] pub fn prepare_fee_change( - ctx: Context, + ctx: Context, lp_fee: DecimalU64Anchor, governance_fee: DecimalU64Anchor, - // params: PrepareFeeChangeParams, ) -> Result<()> { - // handle_prepare_fee_change(ctx, params) handle_prepare_fee_change(ctx, lp_fee, governance_fee) } - #[access_control(EnactFeeChange::accounts(&ctx))] - pub fn enact_fee_change(ctx: Context) -> Result<()> { + pub fn enact_fee_change(ctx: Context) -> Result<()> { handle_enact_fee_change(ctx) } - #[access_control(ChangeGovernanceFeeAccount::accounts(&ctx))] pub fn change_governance_fee_account( ctx: Context, new_governance_fee_key: Pubkey, @@ -176,27 +165,25 @@ pub mod two_pool { handle_change_governance_fee_account(ctx, new_governance_fee_key) } - #[access_control(AdjustAmpFactor::accounts(&ctx))] - pub fn adjust_amp_factor( - ctx: Context, - target_ts: i64, - target_value: DecimalU64Anchor, - // params: AdjustAmpFactorParams, + pub fn prepare_governance_transition( + ctx: Context, + upcoming_governance_key: Pubkey, ) -> Result<()> { - let params = AdjustAmpFactorParams { target_ts, target_value }; - handle_adjust_amp_factor(ctx, params) + handle_prepare_governance_transition(ctx, upcoming_governance_key) } - #[access_control(SetPaused::accounts(&ctx))] - pub fn set_paused(ctx: Context, paused: bool) -> Result<()> { - handle_set_paused(ctx, paused) + pub fn enact_governance_transition(ctx: Context) -> Result<()> { + handle_enact_governance_transition(ctx) } - #[access_control(ChangePauseKey::accounts(&ctx))] pub fn change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { handle_change_pause_key(ctx, new_pause_key) } + pub fn set_paused(ctx: Context, paused: bool) -> Result<()> { + handle_set_paused(ctx, paused) + } + #[access_control(CreateLpMetadata::accounts(&ctx))] pub fn create_lp_metadata( ctx: Context, diff --git a/packages/solana-contracts/programs/two-pool/tests/governance_test.rs b/packages/solana-contracts/programs/two-pool/tests/governance_test.rs index 5546f3bdd..aea8c6888 100644 --- a/packages/solana-contracts/programs/two-pool/tests/governance_test.rs +++ b/packages/solana-contracts/programs/two-pool/tests/governance_test.rs @@ -62,10 +62,11 @@ async fn test_governance_transition() { let prepare_gov_transition_ix = program .request() .accounts(two_pool::accounts::PrepareGovernanceTransition { - common_governance: two_pool::accounts::CommonGovernance { + governance: two_pool::accounts::Governance { pool: pt_ctxt.pool_key, - governance: pt_ctxt.get_governance().pubkey(), + governance_key: pt_ctxt.get_governance().pubkey(), }, + upcoming_governance_key: new_governance_key.pubkey(), }) .args(two_pool::instruction::PrepareGovernanceTransition { upcoming_governance_key: new_governance_key.pubkey(), @@ -80,7 +81,7 @@ async fn test_governance_transition() { let prepare_gov_transition_txn = Transaction::new_signed_with_payer( &[prepare_gov_transition_ix], Some(&pt_ctxt.get_payer().pubkey()), - &[pt_ctxt.get_payer(), pt_ctxt.get_governance()], + &[pt_ctxt.get_payer(), pt_ctxt.get_governance(), &new_governance_key], recent_blockhash, ); @@ -95,11 +96,9 @@ async fn test_governance_transition() { let enact_gov_transition_ix = program .request() - .accounts(two_pool::accounts::EnactGovernanceTransition { - common_governance: two_pool::accounts::CommonGovernance { - pool: pt_ctxt.pool_key, - governance: pt_ctxt.get_governance().pubkey(), - }, + .accounts(two_pool::accounts::Governance { + pool: pt_ctxt.pool_key, + governance_key: pt_ctxt.get_governance().pubkey(), }) .args(two_pool::instruction::EnactGovernanceTransition {}) .instructions() @@ -144,6 +143,76 @@ async fn test_governance_transition() { assert_eq!(pool_state.governance_key, new_governance_key.pubkey()); assert_eq!(pool_state.prepared_governance_key, Pubkey::default()); assert_eq!(pool_state.governance_transition_ts, 0i64); + + let lp_fee = DecimalU64Anchor { value: 400u64, decimals: 6u8 }; + let governance_fee = DecimalU64Anchor { value: 200u64, decimals: 6u8 }; + + // governance ixs with old key should fail. + + let prepare_fee_change_ix_fail = program + .request() + .accounts(two_pool::accounts::Governance { + pool: pt_ctxt.pool_key, + governance_key: pt_ctxt.get_governance().pubkey(), + }) + .args(two_pool::instruction::PrepareFeeChange { + lp_fee, + governance_fee, + // params: PrepareFeeChangeParams { + // lp_fee, + // governance_fee, + // }, + }) + .instructions() + .unwrap() + .pop() + .unwrap(); + + let recent_blockhash = pt_ctxt.get_latest_blockhash().await; + + let prepare_fee_change_txn_fail = Transaction::new_signed_with_payer( + &[prepare_fee_change_ix_fail], + Some(&pt_ctxt.get_payer().pubkey()), + &[pt_ctxt.get_payer(), pt_ctxt.get_governance()], + recent_blockhash, + ); + + pt_ctxt + .process_transaction(prepare_fee_change_txn_fail) + .await + .expect_err("prepare fee change should fail with old governance key"); + + // should be able to execute governance ix with new governance key now. + + let prepare_fee_change_ix = program + .request() + .accounts(two_pool::accounts::Governance { + pool: pt_ctxt.pool_key, + governance_key: new_governance_key.pubkey(), + }) + .args(two_pool::instruction::PrepareFeeChange { + lp_fee, + governance_fee, + // params: PrepareFeeChangeParams { + // lp_fee, + // governance_fee, + // }, + }) + .instructions() + .unwrap() + .pop() + .unwrap(); + + let recent_blockhash = pt_ctxt.get_latest_blockhash().await; + + let prepare_fee_change_txn = Transaction::new_signed_with_payer( + &[prepare_fee_change_ix], + Some(&pt_ctxt.get_payer().pubkey()), + &[pt_ctxt.get_payer(), &new_governance_key], + recent_blockhash, + ); + + pt_ctxt.process_transaction(prepare_fee_change_txn).await.unwrap(); } #[tokio::test] @@ -169,22 +238,13 @@ async fn test_fee_change() { let lp_fee = DecimalU64Anchor { value: 400u64, decimals: 6u8 }; let governance_fee = DecimalU64Anchor { value: 200u64, decimals: 6u8 }; - let prepare_gov_transition_ix = program + let prepare_fee_change_ix = program .request() - .accounts(two_pool::accounts::PrepareFeeChange { - common_governance: two_pool::accounts::CommonGovernance { - pool: pt_ctxt.pool_key, - governance: pt_ctxt.get_governance().pubkey(), - }, - }) - .args(two_pool::instruction::PrepareFeeChange { - lp_fee, - governance_fee, - // params: PrepareFeeChangeParams { - // lp_fee, - // governance_fee, - // }, + .accounts(two_pool::accounts::Governance { + pool: pt_ctxt.pool_key, + governance_key: pt_ctxt.get_governance().pubkey(), }) + .args(two_pool::instruction::PrepareFeeChange { lp_fee, governance_fee }) .instructions() .unwrap() .pop() @@ -192,14 +252,14 @@ async fn test_fee_change() { let recent_blockhash = pt_ctxt.get_latest_blockhash().await; - let prepare_gov_transition_txn = Transaction::new_signed_with_payer( - &[prepare_gov_transition_ix], + let prepare_fee_change_txn = Transaction::new_signed_with_payer( + &[prepare_fee_change_ix], Some(&pt_ctxt.get_payer().pubkey()), &[pt_ctxt.get_payer(), pt_ctxt.get_governance()], recent_blockhash, ); - pt_ctxt.process_transaction(prepare_gov_transition_txn).await.unwrap(); + pt_ctxt.process_transaction(prepare_fee_change_txn).await.unwrap(); let pool_state_account = pt_ctxt.get_pool_state_data(pt_ctxt.pool_key).await; let pool_state: TwoPool = TwoPool::try_deserialize(&mut pool_state_account.data.as_slice()).unwrap(); @@ -211,11 +271,9 @@ async fn test_fee_change() { let enact_fee_change_ix = program .request() - .accounts(two_pool::accounts::EnactFeeChange { - common_governance: two_pool::accounts::CommonGovernance { - pool: pt_ctxt.pool_key, - governance: pt_ctxt.get_governance().pubkey(), - }, + .accounts(two_pool::accounts::Governance { + pool: pt_ctxt.pool_key, + governance_key: pt_ctxt.get_governance().pubkey(), }) .args(two_pool::instruction::EnactFeeChange {}) .instructions() @@ -393,16 +451,7 @@ impl DeployedPoolProgramTestContext { system_program: anchor_lang::prelude::System::id(), rent: anchor_lang::prelude::Rent::id(), }) - .args(two_pool::instruction::Initialize { - // params: InitializeParams { - // amp_factor, - // lp_fee, - // governance_fee, - // }, - amp_factor, - lp_fee, - governance_fee, - }) + .args(two_pool::instruction::Initialize { amp_factor, lp_fee, governance_fee }) .instructions() .unwrap() .pop() diff --git a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts index 966b03b88..a9b66c3bb 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts @@ -896,10 +896,8 @@ describe("TwoPool", () => { // .adjustAmpFactor(params) .adjustAmpFactor(targetTs, targetValue) .accounts({ - commonGovernance: { - pool: flagshipPool, - governance: governanceKeypair.publicKey, - }, + pool: flagshipPool, + governanceKey: governanceKeypair.publicKey, }) .signers([governanceKeypair]) .rpc(); @@ -1019,12 +1017,13 @@ describe("TwoPool", () => { const changePauseKeyTxn = await twoPoolProgram.methods .changePauseKey(newPauseKeypair.publicKey) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, + newPauseKey: newPauseKeypair.publicKey, }) - .signers([governanceKeypair]) + .signers([governanceKeypair, newPauseKeypair]) .rpc(); console.info(`changePauseKeyTxn: ${changePauseKeyTxn}`); @@ -1096,10 +1095,8 @@ describe("TwoPool", () => { // .prepareFeeChange(params) .prepareFeeChange(newLpFee, newGovernanceFee) .accounts({ - commonGovernance: { - pool: flagshipPool, - governance: governanceKeypair.publicKey, - }, + pool: flagshipPool, + governanceKey: governanceKeypair.publicKey, }) .signers([governanceKeypair]) .rpc(); @@ -1117,19 +1114,21 @@ describe("TwoPool", () => { }); it("Can prepare governance transitions", async () => { - const upcomingGovernanceKey = Keypair.generate().publicKey; + const upcomingGovernanceKeypair = Keypair.generate(); + const upcomingGovernanceKey = upcomingGovernanceKeypair.publicKey; // const params = { // upcomingGovernanceKey, // }; const prepareGovernanceTransitionTxn = await twoPoolProgram.methods .prepareGovernanceTransition(upcomingGovernanceKey) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, + upcomingGovernanceKey: upcomingGovernanceKey, }) - .signers([governanceKeypair]) + .signers([governanceKeypair, upcomingGovernanceKeypair]) .rpc(); console.info( `send prepareGovernanceTransitionTxn: ${prepareGovernanceTransitionTxn}`, @@ -1157,9 +1156,9 @@ describe("TwoPool", () => { const changeGovFeeTxn = await twoPoolProgram.methods .changeGovernanceFeeAccount(newGovernanceFeeKey) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, newGovernanceFee: newGovernanceFeeKey, }) @@ -1182,9 +1181,9 @@ describe("TwoPool", () => { return twoPoolProgram.methods .changeGovernanceFeeAccount(newGovernanceFeeKey) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, newGovernanceFee: newGovernanceFeeKey, }) @@ -1197,7 +1196,7 @@ describe("TwoPool", () => { // await twoPoolProgram.methods // .changeGovernanceFeeAccount(newGovernanceFeeKey) // .accounts({ - // commonGovernance: { + // governance: { // pool: flagshipPool, // governance: governanceKeypair.publicKey, // }, @@ -1266,9 +1265,9 @@ describe("TwoPool", () => { // .createLpMetadata(params) .createLpMetadata(data, isMutable, updateAuthorityIsSigner) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, createMetadataAccounts: { metadata: metadataPda, @@ -1332,9 +1331,9 @@ describe("TwoPool", () => { isMutable, ) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, updateMetadataAccounts: { metadata: metadataPda, @@ -1394,9 +1393,9 @@ describe("TwoPool", () => { isMutable, ) .accounts({ - commonGovernance: { + governance: { pool: flagshipPool, - governance: governanceKeypair.publicKey, + governanceKey: governanceKeypair.publicKey, }, updateMetadataAccounts: { metadata: metadataPda, diff --git a/packages/solana-contracts/src/artifacts/two_pool.json b/packages/solana-contracts/src/artifacts/two_pool.json index 7aa5130e7..2fe29473c 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.json +++ b/packages/solana-contracts/src/artifacts/two_pool.json @@ -797,153 +797,101 @@ } }, { - "name": "prepareGovernanceTransition", + "name": "adjustAmpFactor", "docs": [ "Governance Ixs *" ], "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] - }, - { - "name": "enactGovernanceTransition", - "accounts": [ + "name": "targetTs", + "type": "i64" + }, { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] - } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + "name": "targetValue", + "type": { + "defined": "DecimalU64Anchor" + } } - ], - "args": [] + ] }, { "name": "prepareFeeChange", "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -965,46 +913,41 @@ "name": "enactFeeChange", "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -1013,7 +956,7 @@ "name": "changeGovernanceFeeAccount", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1048,7 +991,7 @@ } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1068,10 +1011,10 @@ ] }, { - "name": "adjustAmpFactor", + "name": "prepareGovernanceTransition", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1106,28 +1049,27 @@ } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "targetTs", - "type": "i64" - }, - { - "name": "targetValue", - "type": { - "defined": "DecimalU64Anchor" - } + "name": "upcomingGovernanceKey", + "type": "publicKey" } ] }, { - "name": "setPaused", + "name": "enactGovernanceTransition", "accounts": [ { "name": "pool", @@ -1162,23 +1104,18 @@ } }, { - "name": "pauseKey", + "name": "governanceKey", "isMut": false, "isSigner": true } ], - "args": [ - { - "name": "paused", - "type": "bool" - } - ] + "args": [] }, { "name": "changePauseKey", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1213,11 +1150,16 @@ } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -1227,11 +1169,59 @@ } ] }, + { + "name": "setPaused", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, { "name": "createLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1266,7 +1256,7 @@ } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1339,7 +1329,7 @@ "name": "updateLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1374,7 +1364,7 @@ } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1722,6 +1712,26 @@ ] } }, + { + "name": "PrepareFeeChangeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lpFee", + "type": { + "defined": "DecimalU64Anchor" + } + }, + { + "name": "governanceFee", + "type": { + "defined": "DecimalU64Anchor" + } + } + ] + } + }, { "name": "CreateLpMetadataParams", "type": { @@ -1744,6 +1754,40 @@ ] } }, + { + "name": "UpdateLpMetadataParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newUpdateAuthority", + "type": { + "option": "publicKey" + } + }, + { + "name": "data", + "type": { + "option": { + "defined": "AnchorDataV2" + } + } + }, + { + "name": "primarySaleHappened", + "type": { + "option": "bool" + } + }, + { + "name": "isMutable", + "type": { + "option": "bool" + } + } + ] + } + }, { "name": "AnchorDataV2", "type": { @@ -1873,60 +1917,6 @@ ] } }, - { - "name": "PrepareFeeChangeParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "lpFee", - "type": { - "defined": "DecimalU64Anchor" - } - }, - { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } - } - ] - } - }, - { - "name": "UpdateLpMetadataParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "newUpdateAuthority", - "type": { - "option": "publicKey" - } - }, - { - "name": "data", - "type": { - "option": { - "defined": "AnchorDataV2" - } - } - }, - { - "name": "primarySaleHappened", - "type": { - "option": "bool" - } - }, - { - "name": "isMutable", - "type": { - "option": "bool" - } - } - ] - } - }, { "name": "InitializeParams", "type": { @@ -2178,33 +2168,43 @@ }, { "code": 6032, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key" + }, + { + "code": 6033, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6033, + "code": 6034, "name": "StaleFeed", "msg": "Switchboard feed has not been updated in 5 minutes" }, { - "code": 6034, + "code": 6035, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6035, + "code": 6036, "name": "MaxDecimalsExceeded", "msg": "Maximum decimals exceeded" }, { - "code": 6036, + "code": 6037, "name": "ConversionError", "msg": "Conversion error" }, { - "code": 6037, + "code": 6038, "name": "BurnAmountExceedsTotalSupply", "msg": "Burn amount exceeds lp total supply" + }, + { + "code": 6039, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key" } ] } \ No newline at end of file diff --git a/packages/solana-contracts/src/artifacts/two_pool.ts b/packages/solana-contracts/src/artifacts/two_pool.ts index 9d75f58e6..0dcfb296a 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.ts +++ b/packages/solana-contracts/src/artifacts/two_pool.ts @@ -797,153 +797,101 @@ export type TwoPool = { } }, { - "name": "prepareGovernanceTransition", + "name": "adjustAmpFactor", "docs": [ "Governance Ixs *" ], "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] - }, - { - "name": "enactGovernanceTransition", - "accounts": [ + "name": "targetTs", + "type": "i64" + }, { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] - } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + "name": "targetValue", + "type": { + "defined": "DecimalU64Anchor" + } } - ], - "args": [] + ] }, { "name": "prepareFeeChange", "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -965,46 +913,41 @@ export type TwoPool = { "name": "enactFeeChange", "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -1013,7 +956,7 @@ export type TwoPool = { "name": "changeGovernanceFeeAccount", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1048,7 +991,7 @@ export type TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1068,10 +1011,10 @@ export type TwoPool = { ] }, { - "name": "adjustAmpFactor", + "name": "prepareGovernanceTransition", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1106,28 +1049,27 @@ export type TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "targetTs", - "type": "i64" - }, - { - "name": "targetValue", - "type": { - "defined": "DecimalU64Anchor" - } + "name": "upcomingGovernanceKey", + "type": "publicKey" } ] }, { - "name": "setPaused", + "name": "enactGovernanceTransition", "accounts": [ { "name": "pool", @@ -1162,23 +1104,18 @@ export type TwoPool = { } }, { - "name": "pauseKey", + "name": "governanceKey", "isMut": false, "isSigner": true } ], - "args": [ - { - "name": "paused", - "type": "bool" - } - ] + "args": [] }, { "name": "changePauseKey", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1213,11 +1150,16 @@ export type TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -1227,11 +1169,59 @@ export type TwoPool = { } ] }, + { + "name": "setPaused", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, { "name": "createLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1266,7 +1256,7 @@ export type TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1339,7 +1329,7 @@ export type TwoPool = { "name": "updateLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -1374,7 +1364,7 @@ export type TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -1722,6 +1712,26 @@ export type TwoPool = { ] } }, + { + "name": "PrepareFeeChangeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lpFee", + "type": { + "defined": "DecimalU64Anchor" + } + }, + { + "name": "governanceFee", + "type": { + "defined": "DecimalU64Anchor" + } + } + ] + } + }, { "name": "CreateLpMetadataParams", "type": { @@ -1744,6 +1754,40 @@ export type TwoPool = { ] } }, + { + "name": "UpdateLpMetadataParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newUpdateAuthority", + "type": { + "option": "publicKey" + } + }, + { + "name": "data", + "type": { + "option": { + "defined": "AnchorDataV2" + } + } + }, + { + "name": "primarySaleHappened", + "type": { + "option": "bool" + } + }, + { + "name": "isMutable", + "type": { + "option": "bool" + } + } + ] + } + }, { "name": "AnchorDataV2", "type": { @@ -1865,64 +1909,10 @@ export type TwoPool = { { "name": "verified", "type": "bool" - }, - { - "name": "key", - "type": "publicKey" - } - ] - } - }, - { - "name": "PrepareFeeChangeParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "lpFee", - "type": { - "defined": "DecimalU64Anchor" - } - }, - { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } - } - ] - } - }, - { - "name": "UpdateLpMetadataParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "newUpdateAuthority", - "type": { - "option": "publicKey" - } - }, - { - "name": "data", - "type": { - "option": { - "defined": "AnchorDataV2" - } - } - }, - { - "name": "primarySaleHappened", - "type": { - "option": "bool" - } - }, - { - "name": "isMutable", - "type": { - "option": "bool" - } + }, + { + "name": "key", + "type": "publicKey" } ] } @@ -2178,33 +2168,43 @@ export type TwoPool = { }, { "code": 6032, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key" + }, + { + "code": 6033, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6033, + "code": 6034, "name": "StaleFeed", "msg": "Switchboard feed has not been updated in 5 minutes" }, { - "code": 6034, + "code": 6035, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6035, + "code": 6036, "name": "MaxDecimalsExceeded", "msg": "Maximum decimals exceeded" }, { - "code": 6036, + "code": 6037, "name": "ConversionError", "msg": "Conversion error" }, { - "code": 6037, + "code": 6038, "name": "BurnAmountExceedsTotalSupply", "msg": "Burn amount exceeds lp total supply" + }, + { + "code": 6039, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key" } ] }; @@ -3008,153 +3008,101 @@ export const IDL: TwoPool = { } }, { - "name": "prepareGovernanceTransition", + "name": "adjustAmpFactor", "docs": [ "Governance Ixs *" ], "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] - }, - { - "name": "enactGovernanceTransition", - "accounts": [ + "name": "targetTs", + "type": "i64" + }, { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] - } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + "name": "targetValue", + "type": { + "defined": "DecimalU64Anchor" + } } - ], - "args": [] + ] }, { "name": "prepareFeeChange", "accounts": [ { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -3165,57 +3113,52 @@ export const IDL: TwoPool = { } }, { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } - } - ] - }, - { - "name": "enactFeeChange", - "accounts": [ - { - "name": "commonGovernance", - "accounts": [ - { - "name": "pool", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "two_pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool" - }, - { - "kind": "account", - "type": "publicKey", - "account": "TwoPool", - "path": "pool.lp_mint_key" - } - ] - } - }, - { - "name": "governance", - "isMut": false, - "isSigner": true - } - ] + "name": "governanceFee", + "type": { + "defined": "DecimalU64Anchor" + } + } + ] + }, + { + "name": "enactFeeChange", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true } ], "args": [] @@ -3224,7 +3167,7 @@ export const IDL: TwoPool = { "name": "changeGovernanceFeeAccount", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -3259,7 +3202,7 @@ export const IDL: TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -3279,10 +3222,10 @@ export const IDL: TwoPool = { ] }, { - "name": "adjustAmpFactor", + "name": "prepareGovernanceTransition", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -3317,28 +3260,27 @@ export const IDL: TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": true } ], "args": [ { - "name": "targetTs", - "type": "i64" - }, - { - "name": "targetValue", - "type": { - "defined": "DecimalU64Anchor" - } + "name": "upcomingGovernanceKey", + "type": "publicKey" } ] }, { - "name": "setPaused", + "name": "enactGovernanceTransition", "accounts": [ { "name": "pool", @@ -3373,23 +3315,18 @@ export const IDL: TwoPool = { } }, { - "name": "pauseKey", + "name": "governanceKey", "isMut": false, "isSigner": true } ], - "args": [ - { - "name": "paused", - "type": "bool" - } - ] + "args": [] }, { "name": "changePauseKey", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -3424,11 +3361,16 @@ export const IDL: TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } ] + }, + { + "name": "newPauseKey", + "isMut": false, + "isSigner": true } ], "args": [ @@ -3438,11 +3380,59 @@ export const IDL: TwoPool = { } ] }, + { + "name": "setPaused", + "accounts": [ + { + "name": "pool", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "two_pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool" + }, + { + "kind": "account", + "type": "publicKey", + "account": "TwoPool", + "path": "pool.lp_mint_key" + } + ] + } + }, + { + "name": "pauseKey", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "paused", + "type": "bool" + } + ] + }, { "name": "createLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -3477,7 +3467,7 @@ export const IDL: TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -3550,7 +3540,7 @@ export const IDL: TwoPool = { "name": "updateLpMetadata", "accounts": [ { - "name": "commonGovernance", + "name": "governance", "accounts": [ { "name": "pool", @@ -3585,7 +3575,7 @@ export const IDL: TwoPool = { } }, { - "name": "governance", + "name": "governanceKey", "isMut": false, "isSigner": true } @@ -3933,6 +3923,26 @@ export const IDL: TwoPool = { ] } }, + { + "name": "PrepareFeeChangeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lpFee", + "type": { + "defined": "DecimalU64Anchor" + } + }, + { + "name": "governanceFee", + "type": { + "defined": "DecimalU64Anchor" + } + } + ] + } + }, { "name": "CreateLpMetadataParams", "type": { @@ -3955,6 +3965,40 @@ export const IDL: TwoPool = { ] } }, + { + "name": "UpdateLpMetadataParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newUpdateAuthority", + "type": { + "option": "publicKey" + } + }, + { + "name": "data", + "type": { + "option": { + "defined": "AnchorDataV2" + } + } + }, + { + "name": "primarySaleHappened", + "type": { + "option": "bool" + } + }, + { + "name": "isMutable", + "type": { + "option": "bool" + } + } + ] + } + }, { "name": "AnchorDataV2", "type": { @@ -4084,60 +4128,6 @@ export const IDL: TwoPool = { ] } }, - { - "name": "PrepareFeeChangeParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "lpFee", - "type": { - "defined": "DecimalU64Anchor" - } - }, - { - "name": "governanceFee", - "type": { - "defined": "DecimalU64Anchor" - } - } - ] - } - }, - { - "name": "UpdateLpMetadataParams", - "type": { - "kind": "struct", - "fields": [ - { - "name": "newUpdateAuthority", - "type": { - "option": "publicKey" - } - }, - { - "name": "data", - "type": { - "option": { - "defined": "AnchorDataV2" - } - } - }, - { - "name": "primarySaleHappened", - "type": { - "option": "bool" - } - }, - { - "name": "isMutable", - "type": { - "option": "bool" - } - } - ] - } - }, { "name": "InitializeParams", "type": { @@ -4389,33 +4379,43 @@ export const IDL: TwoPool = { }, { "code": 6032, + "name": "InvalidNewPauseKey", + "msg": "Invalid New Pause Key" + }, + { + "code": 6033, "name": "InvalidSwitchboardAccount", "msg": "Not a valid Switchboard account" }, { - "code": 6033, + "code": 6034, "name": "StaleFeed", "msg": "Switchboard feed has not been updated in 5 minutes" }, { - "code": 6034, + "code": 6035, "name": "ConfidenceIntervalExceeded", "msg": "Switchboard feed exceeded provided confidence interval" }, { - "code": 6035, + "code": 6036, "name": "MaxDecimalsExceeded", "msg": "Maximum decimals exceeded" }, { - "code": 6036, + "code": 6037, "name": "ConversionError", "msg": "Conversion error" }, { - "code": 6037, + "code": 6038, "name": "BurnAmountExceedsTotalSupply", "msg": "Burn amount exceeds lp total supply" + }, + { + "code": 6039, + "name": "InvalidUpcomingGovernanceKey", + "msg": "Invalid Upcoming Governance Key" } ] }; From c71c9aee2fe369272142174f35be87effdf0059a Mon Sep 17 00:00:00 2001 From: swimricky Date: Thu, 27 Oct 2022 17:32:03 -0400 Subject: [PATCH 17/17] feat(solana-contracts): update gov & pause ixs no longer requiring upcoming governance & pause keys to be signers --- .../programs/propeller/src/fees.rs | 18 +- .../src/instructions/governance/gov.rs | 47 -- .../src/instructions/governance/governance.rs | 100 ++++ .../src/instructions/governance/mod.rs | 4 +- .../src/instructions/governance/pause.rs | 19 +- .../src/instructions/marginal_price_pool.rs | 14 +- .../wormhole/complete_native_with_payload.rs | 31 +- .../wormhole/transfer_native_with_payload.rs | 102 ++-- .../programs/propeller/src/lib.rs | 24 +- .../programs/propeller/src/state/propeller.rs | 48 +- .../src/instructions/governance/governance.rs | 7 +- .../src/instructions/governance/mod.rs | 23 +- .../two-pool/tests/governance_test.rs | 2 +- .../src/__tests__/propeller/propeller.test.ts | 27 +- .../src/__tests__/twoPool/pool.test.ts | 4 +- .../src/artifacts/propeller.json | 254 ++++++--- .../src/artifacts/propeller.ts | 508 +++++++++++++----- .../src/artifacts/two_pool.json | 4 +- .../src/artifacts/two_pool.ts | 8 +- 19 files changed, 800 insertions(+), 444 deletions(-) delete mode 100644 packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs create mode 100644 packages/solana-contracts/programs/propeller/src/instructions/governance/governance.rs diff --git a/packages/solana-contracts/programs/propeller/src/fees.rs b/packages/solana-contracts/programs/propeller/src/fees.rs index cb68c5513..28452b9a9 100644 --- a/packages/solana-contracts/programs/propeller/src/fees.rs +++ b/packages/solana-contracts/programs/propeller/src/fees.rs @@ -1,14 +1,10 @@ use { - crate::{ - constants::LAMPORTS_PER_SOL_DECIMAL, marginal_price_pool::*, FeeTracker, Propeller, PropellerError, - }, + crate::{constants::LAMPORTS_PER_SOL_DECIMAL, marginal_price_pool::*, FeeTracker, Propeller, PropellerError}, anchor_lang::prelude::*, - anchor_spl::{ - token::{TokenAccount}, - }, + anchor_spl::token::TokenAccount, num_traits::{FromPrimitive, ToPrimitive}, rust_decimal::Decimal, - switchboard_v2::{AggregatorAccountData, SWITCHBOARD_PROGRAM_ID}, + switchboard_v2::{AggregatorAccountData, SwitchboardDecimal, SWITCHBOARD_PROGRAM_ID}, }; pub trait Fees<'info> { @@ -112,10 +108,10 @@ impl<'info> FeeTracking<'info> { .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 max_confidence_interval = f64::MAX; + // // let max_confidence_interval = propeller.max_confidence_interval; + // feed.check_confidence_interval(SwitchboardDecimal::from_f64(max_confidence_interval)) + // .map_err(|_| error!(PropellerError::ConfidenceIntervalExceeded))?; let sol_usd_price: Decimal = feed.get_result()?.try_into()?; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs deleted file mode 100644 index 5108d60d0..000000000 --- a/packages/solana-contracts/programs/propeller/src/instructions/governance/gov.rs +++ /dev/null @@ -1,47 +0,0 @@ -use { - crate::{constants::ENACT_DELAY, error::*, Propeller}, - anchor_lang::prelude::*, -}; - -#[derive(Accounts)] -pub struct Governance<'info> { - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - propeller.swim_usd_mint.as_ref(), - ], - bump = propeller.bump, - has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, - )] - pub propeller: Account<'info, Propeller>, - pub governance_key: Signer<'info>, - pub upcoming_governance_key: Signer<'info>, -} - -pub fn handle_prepare_governance_transition(ctx: Context, upcoming_governance_key: Pubkey) -> Result<()> { - let propeller = &mut ctx.accounts.propeller; - require_keys_neq!(upcoming_governance_key, Pubkey::default(), PropellerError::InvalidUpcomingGovernanceKey); - propeller.prepared_governance_key = upcoming_governance_key; - let current_ts = Clock::get()?.unix_timestamp; - require_gt!(current_ts, 0i64); - propeller.governance_transition_ts = current_ts + ENACT_DELAY; - Ok(()) -} - -pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { - let propeller = &mut ctx.accounts.propeller; - require_neq!(propeller.governance_transition_ts, 0i64, PropellerError::InvalidEnact); - require_keys_neq!(propeller.prepared_governance_key, Pubkey::default(), PropellerError::InvalidEnact); - - let current_ts = Clock::get()?.unix_timestamp; - - require_gt!(current_ts, 0i64); - require_gt!(current_ts, propeller.governance_transition_ts, PropellerError::InsufficientDelay); - - propeller.governance_key = propeller.prepared_governance_key; - propeller.prepared_governance_key = Pubkey::default(); - propeller.governance_transition_ts = 0i64; - - Ok(()) -} diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/governance.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/governance.rs new file mode 100644 index 000000000..02fadd4bc --- /dev/null +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/governance.rs @@ -0,0 +1,100 @@ +use { + crate::{constants::ENACT_DELAY, error::*, Propeller}, + anchor_lang::prelude::*, + two_pool::DecimalU64Anchor, +}; + +#[derive(Accounts)] +pub struct Governance<'info> { + #[account( + mut, + seeds = [ + b"propeller".as_ref(), + propeller.swim_usd_mint.as_ref(), + ], + bump = propeller.bump, + has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, + )] + pub propeller: Account<'info, Propeller>, + pub governance_key: Signer<'info>, +} + +#[derive(Accounts)] +pub struct PrepareGovernanceTransition<'info> { + pub governance: Governance<'info>, + ///CHECK: not specifying type of account since it doesn't matter + pub upcoming_governance_key: UncheckedAccount<'info>, +} +pub fn handle_prepare_governance_transition( + ctx: Context, + upcoming_governance_key: Pubkey, +) -> Result<()> { + let propeller = &mut ctx.accounts.governance.propeller; + require_keys_eq!( + ctx.accounts.upcoming_governance_key.key(), + upcoming_governance_key, + PropellerError::InvalidUpcomingGovernanceKey + ); + require_keys_neq!(upcoming_governance_key, Pubkey::default(), PropellerError::InvalidUpcomingGovernanceKey); + propeller.prepared_governance_key = upcoming_governance_key; + let current_ts = Clock::get()?.unix_timestamp; + require_gt!(current_ts, 0i64); + propeller.governance_transition_ts = current_ts + ENACT_DELAY; + Ok(()) +} + +pub fn handle_enact_governance_transition(ctx: Context) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + require_neq!(propeller.governance_transition_ts, 0i64, PropellerError::InvalidEnact); + require_keys_neq!(propeller.prepared_governance_key, Pubkey::default(), PropellerError::InvalidEnact); + + let current_ts = Clock::get()?.unix_timestamp; + + require_gt!(current_ts, 0i64); + require_gt!(current_ts, propeller.governance_transition_ts, PropellerError::InsufficientDelay); + + propeller.governance_key = propeller.prepared_governance_key; + propeller.prepared_governance_key = Pubkey::default(); + propeller.governance_transition_ts = 0i64; + + Ok(()) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct FeeUpdates { + pub secp_verify_init_fee: Option, + pub secp_verify_fee: Option, + pub post_vaa_fee: Option, + pub init_ata_fee: Option, + pub complete_with_payload_fee: Option, + pub process_swim_payload_fee: Option, +} + +/* Update Fees */ + +pub fn handle_update_fees(ctx: Context, fee_updates: FeeUpdates) -> Result<()> { + Ok(()) +} + +pub fn handle_update_gas_kickstart_amount(ctx: Context, new_gas_kickstart_amount: u64) -> Result<()> { + let propeller = &mut ctx.accounts.propeller; + propeller.gas_kickstart_amount = new_gas_kickstart_amount; + Ok(()) +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct GasOracleUpdates { + pub aggregator: Option, + pub max_staleness: Option, + pub max_confidence_interval: Option, + pub fallback_oracle: Option, +} + +// TODO: bundle marginal pool in this update as well. +// if you update the marginal pool, may need to update gas oracle as well for new intermediate token +// e.g. update marginal pool to swimUSD/uxd pool, oracle needs to give sol/uxd price +// pub fn handle_update_gas_oracle(ctx: Context, gas_oracle_updates: GasOracleUpdates) -> Result<()> { +// let propeller = &mut ctx.accounts.propeller; +// propeller.gas_oracle = new_gas_oracle; +// Ok(()) +// } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs index 3a2131296..7e179f863 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/mod.rs @@ -1,4 +1,4 @@ -pub use {gov::*, pause::*}; +pub use {governance::*, pause::*}; -mod gov; +mod governance; mod pause; diff --git a/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs index 95c0f0489..e1dd82048 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/governance/pause.rs @@ -1,5 +1,5 @@ use { - crate::{error::*, Propeller}, + crate::{error::*, governance::*, Propeller}, anchor_lang::prelude::*, }; @@ -27,24 +27,15 @@ pub fn handle_set_paused(ctx: Context, is_paused: bool) -> Result<()> #[derive(Accounts)] pub struct UpdatePauseKey<'info> { - #[account( - mut, - seeds = [ - b"propeller".as_ref(), - propeller.swim_usd_mint.as_ref(), - ], - bump = propeller.bump, - has_one = governance_key @ PropellerError::InvalidPropellerGovernanceKey, - )] - pub propeller: Box>, - pub governance_key: Signer<'info>, - pub new_pause_key: Signer<'info>, + pub governance: Governance<'info>, + ///CHECK: not specifying type of account since it doesn't matter + pub new_pause_key: UncheckedAccount<'info>, } pub fn handle_change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { require_keys_eq!(new_pause_key, ctx.accounts.new_pause_key.key()); require_keys_neq!(new_pause_key, Pubkey::default(), PropellerError::InvalidNewPauseKey); - let propeller = &mut ctx.accounts.propeller; + let propeller = &mut ctx.accounts.governance.propeller; propeller.pause_key = ctx.accounts.new_pause_key.key(); Ok(()) } diff --git a/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs index e8680aa9b..4d722e1e1 100644 --- a/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs +++ b/packages/solana-contracts/programs/propeller/src/instructions/marginal_price_pool.rs @@ -1,14 +1,7 @@ - use { - crate::{ - error::*, Propeller, TOKEN_COUNT, - }, - anchor_lang::{ - prelude::*, - }, - anchor_spl::{ - token::{Mint, TokenAccount}, - }, + crate::{error::*, Propeller, TOKEN_COUNT}, + anchor_lang::prelude::*, + anchor_spl::token::{Mint, TokenAccount}, // primitive_types::U256, rust_decimal::Decimal, two_pool::{state::TwoPool, BorshDecimal}, @@ -101,6 +94,7 @@ impl<'info> MarginalPricePool<'info> { Ok(marginal_price) } + //TODO: fix/test this - maybe just store decimals in propeller state. pub fn get_swim_usd_mint_decimals(&self, propeller: &Propeller) -> Result { let swim_usd_mint = propeller.swim_usd_mint; let marginal_price_pool = &self.pool; 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 142f2b185..c6b90beeb 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 @@ -1,10 +1,8 @@ -use crate::{ - get_memo_as_utf8, wormhole::SwimPayload, Fees, -}; use { crate::{ - error::*, fees::*, get_message_data, - state::SwimPayloadMessage, ClaimData, MessageData, PayloadTransferWithPayload, Propeller, TokenBridge, Wormhole, COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, + error::*, fees::*, get_memo_as_utf8, get_message_data, state::SwimPayloadMessage, wormhole::SwimPayload, + ClaimData, Fees, MessageData, PayloadTransferWithPayload, Propeller, TokenBridge, Wormhole, + COMPLETE_NATIVE_WITH_PAYLOAD_INSTRUCTION, }, anchor_lang::{ prelude::*, @@ -12,8 +10,7 @@ use { }, anchor_spl::{ associated_token::get_associated_token_address, - token, - token::{Mint, Token, TokenAccount, Transfer}, + token::{self, Mint, Token, TokenAccount, Transfer}, }, solana_program::program::invoke, }; @@ -99,9 +96,11 @@ pub struct CompleteNativeWithPayload<'info> { // )] #[account(mut)] /// CHECK: wormhole claim account to prevent double spending + /// checked in CPI pub claim: UncheckedAccount<'info>, /// CHECK: wormhole endpoint account. seeds = [ vaa.emitter_chain, vaa.emitter_address ] + /// checked in CPI pub endpoint: UncheckedAccount<'info>, /// `to` account in `CompleteNativeWithPayload` #[account( @@ -147,10 +146,10 @@ pub struct CompleteNativeWithPayload<'info> { // /// CHECK: recipient of fees for executing complete transfer (e.g. relayer) // pub fee_recipient: AccountInfo<'info>, #[account( - mut, - seeds = [swim_usd_mint.key().as_ref()], - seeds::program = token_bridge.key(), - bump, + mut, + seeds = [swim_usd_mint.key().as_ref()], + seeds::program = token_bridge.key(), + bump, )] /// CHECK: wormhole_custody_account: seeds = [mint], seeds::program = token_bridge pub custody: UncheckedAccount<'info>, @@ -421,21 +420,11 @@ pub fn handle_propeller_complete_native_with_payload(ctx: Context swimUSD if the payer isn't the actual logical owner. // This is for if the propeller engine is unavailable and the user is manually calling // this ix. They should use the `CompleteNativeWithPayload` ix instead but adding this just in case.\ // if swim payload owner calling though they will need a fee tracker account already. let swim_payload_owner = Pubkey::new_from_array(swim_payload.owner); - let _token_program = &ctx.accounts.complete_native_with_payload.token_program; if swim_payload_owner != ctx.accounts.complete_native_with_payload.payer.key() { let fees_in_lamports = ctx.accounts.calculate_fees_in_lamports()?; // let fees_in_swim_usd_atomic = ctx.accounts.convert_fees_to_swim_usd_atomic(fees_in_lamports)?; 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 7e864897b..51182ce95 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 @@ -27,19 +27,20 @@ pub struct TransferNativeWithPayload<'info> { #[account(mut)] pub payer: Signer<'info>, + #[account( - mut, - seeds = [ b"config".as_ref() ], - bump, - seeds::program = propeller.token_bridge() - )] + mut, + seeds = [ b"config".as_ref() ], + bump, + seeds::program = token_bridge.key() + )] /// CHECK: Token Bridge Config pub token_bridge_config: UncheckedAccount<'info>, #[account( - mut, + mut, address = get_associated_token_address(&payer.key(), &swim_usd_mint.key()), - )] + )] pub user_swim_usd_ata: Box>, #[account(mut)] @@ -58,29 +59,29 @@ pub struct TransferNativeWithPayload<'info> { pub token_bridge: Program<'info, TokenBridge>, #[account( - seeds=[b"custody_signer".as_ref()], - bump, - seeds::program = token_bridge.key() - )] + seeds=[b"custody_signer".as_ref()], + bump, + seeds::program = token_bridge.key() + )] /// CHECK: Only used for bridging assets native to Solana. pub custody_signer: UncheckedAccount<'info>, #[account( - seeds=[b"authority_signer".as_ref()], - bump, - seeds::program = token_bridge.key() - )] + seeds=[b"authority_signer".as_ref()], + bump, + seeds::program = token_bridge.key() + )] /// CHECK: Token Bridge Authority Signer, delegated approval for transfer - pub authority_signer: AccountInfo<'info>, + pub authority_signer: UncheckedAccount<'info>, #[account( - mut, - seeds = [b"Bridge".as_ref()], - bump, - seeds::program = propeller.wormhole() - )] + mut, + seeds = [b"Bridge".as_ref()], + bump, + seeds::program = wormhole.key() + )] /// CHECK: Wormhole Config - pub wormhole_config: AccountInfo<'info>, + pub wormhole_config: UncheckedAccount<'info>, #[account(mut)] // Note: @@ -97,32 +98,32 @@ pub struct TransferNativeWithPayload<'info> { pub wormhole_message: Signer<'info>, #[account( - mut, - seeds = [b"emitter".as_ref()], - bump, - seeds::program = propeller.token_bridge() - )] + mut, + seeds = [b"emitter".as_ref()], + bump, + seeds::program = token_bridge.key() + )] /// CHECK: Wormhole Emitter is PDA representing the Token Bridge Program pub wormhole_emitter: UncheckedAccount<'info>, #[account( - mut, - seeds = [ - b"Sequence".as_ref(), - wormhole_emitter.key().as_ref() - ], - bump, - seeds::program = propeller.wormhole() - )] + mut, + seeds = [ + b"Sequence".as_ref(), + wormhole_emitter.key().as_ref() + ], + bump, + seeds::program = wormhole.key() + )] /// CHECK: Wormhole Sequence Number pub wormhole_sequence: UncheckedAccount<'info>, #[account( - mut, - seeds = [b"fee_collector".as_ref()], - bump, - seeds::program = propeller.wormhole() - )] + mut, + seeds = [b"fee_collector".as_ref()], + bump, + seeds::program = wormhole.key() + )] /// CHECK: Wormhole Fee Collector. leaving as UncheckedAccount since it could be uninitialized for the first transfer. pub wormhole_fee_collector: UncheckedAccount<'info>, @@ -159,9 +160,9 @@ pub struct TransferNativeWithPayload<'info> { /// that case the PDA's address will directly be encoded into the payload /// instead of the sender program's id. #[account( - seeds = [ b"sender".as_ref()], - bump = propeller.sender_bump, - )] + seeds = [ b"sender".as_ref() ], + bump = propeller.sender_bump, + )] /// CHECK: Sender Account pub sender: SystemAccount<'info>, @@ -189,21 +190,6 @@ pub struct TransferNativeWithPayload<'info> { } impl<'info> TransferNativeWithPayload<'info> { - //Note: some of the checks are excessive (checked in CPI etc) and add to compute budget but since we now have access to requesting - // up to 1.4M compute budget per transaction, better safe than sorry to perform them. - pub fn accounts(ctx: &Context) -> Result<()> { - require_keys_eq!( - ctx.accounts.swim_usd_mint.key(), - ctx.accounts.propeller.swim_usd_mint, - PropellerError::InvalidSwimUsdMint - ); - // 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"); - Ok(()) - } - fn invoke_transfer_native_with_payload(&self, transfer_with_payload_data: TransferWithPayloadData) -> Result<()> { let wh_token_transfer_acct_infos = vec![ self.payer.to_account_info(), diff --git a/packages/solana-contracts/programs/propeller/src/lib.rs b/packages/solana-contracts/programs/propeller/src/lib.rs index e184e950e..1eb224d08 100644 --- a/packages/solana-contracts/programs/propeller/src/lib.rs +++ b/packages/solana-contracts/programs/propeller/src/lib.rs @@ -1,9 +1,6 @@ use { - crate::two_pool_cpi::{ - init_to_swim_usd::*, - // remove_exact_burn::*, remove_exact_output::*, remove_uniform::*, swap_exact_output::*, - }, - anchor_lang::{prelude::*}, + crate::two_pool_cpi::init_to_swim_usd::*, + anchor_lang::prelude::*, // crate::two_pool_cpi::*, constants::TOKEN_COUNT, fees::*, @@ -20,7 +17,6 @@ mod state; mod token_bridge; mod wormhole; - pub use {error::*, instructions::*}; declare_id!("9z6G41AyXk73r1E4nTv81drQPtEqupCSAnsLdGV5WGfK"); @@ -43,16 +39,20 @@ pub mod propeller { handle_change_pause_key(ctx, new_pause_key) } - pub fn prepare_governance_transition(ctx: Context, upcoming_governance_key: Pubkey) -> Result<()> { + pub fn prepare_governance_transition( + ctx: Context, + upcoming_governance_key: Pubkey, + ) -> Result<()> { handle_prepare_governance_transition(ctx, upcoming_governance_key) } - pub fn enact_governance_transition(_ctx: Context) -> Result<()> { - Ok(()) + pub fn enact_governance_transition(ctx: Context) -> Result<()> { + handle_enact_governance_transition(ctx) } - // pub fn prepare_fee_change(ctx: Context, fee_updates: FeeUpdates) -> Result<()> {} - // pub fn enact_fee_change(ctx: Context) -> Result<()> {} + pub fn update_fees(ctx: Context, fee_updates: FeeUpdates) -> Result<()> { + handle_update_fees(ctx, fee_updates) + } #[inline(never)] #[access_control( @@ -146,7 +146,6 @@ pub mod propeller { } #[inline(never)] - #[access_control(TransferNativeWithPayload::accounts(&ctx))] pub fn cross_chain_transfer_native_with_payload( ctx: Context, nonce: u32, @@ -158,7 +157,6 @@ pub mod propeller { } #[inline(never)] - #[access_control(TransferNativeWithPayload::accounts(&ctx))] pub fn propeller_transfer_native_with_payload( ctx: Context, nonce: u32, diff --git a/packages/solana-contracts/programs/propeller/src/state/propeller.rs b/packages/solana-contracts/programs/propeller/src/state/propeller.rs index 130500c2f..6b93438e0 100644 --- a/packages/solana-contracts/programs/propeller/src/state/propeller.rs +++ b/packages/solana-contracts/programs/propeller/src/state/propeller.rs @@ -2,9 +2,7 @@ use { crate::{error::PropellerError, TOKEN_COUNT}, anchor_lang::prelude::*, anchor_spl::token::TokenAccount, - std::{ - io::{Write}, - }, + std::io::Write, two_pool::state::TwoPool, }; @@ -38,9 +36,8 @@ pub struct Propeller { // gas kickstart parameters // 1. marginal_price_pool will be pool used to calculate token_bridge_mint -> stablecoin // 2. marginal_price_pool_token_index will be index of token in pool used to calculate token_bridge_mint -> stablecoin - - // pool used to get marginal price - // e.g. usdc-usdt pool + /// pool used to get marginal price of swimUSD -> stablecoin for gas conversion + /// e.g. usdc-usdt pool pub marginal_price_pool: Pubkey, pub marginal_price_pool_token_mint: Pubkey, // index of token used for calculating gas price @@ -49,13 +46,29 @@ pub struct Propeller { // pub evm_routing_contract_address: [u8; 32], pub fee_vault: Pubkey, //32 - /** switchboard **/ + // switchboard + // + // from discord: + // default sol/usd feed has 10K samples => ~0.7 days of data + // https://switchboard.xyz/explorer/3/GvDMxPzN1sCj7L26YDK2HnMRXEQmQ2aemov8YBtPS7vR + // should be safe to use unless we need custom sources or larger history buffer size + // example feed eefn: + // 1. switchboard feed w/ SOL/USD prices from variety of exchanges weighed by 7D volume along w/ history buffer + // 2. switchboard feed w/ oracleTask to fetch Pyth SOL/USD prices every 10 seconds + history buffer + // 3. switchboard feed w/ oracleTask to fetch ChainLink SOL/USD prices every 10 seconds + history buffer + // 4. switchboard feed calculating 1 min TWAP of (1) (2) and (3) and returns median of results pub aggregator: Pubkey, //32 pub max_staleness: i64, //8 // pub max_confidence_interval: i64, //8 //TODO: add this? // pub fallback_oracle: Pubkey, //32 + + // pyth + // + // mango + // conf = price.agg.conf / price.agg.value + // => if conf > 0.10 => conf > 10% of price => filter out } // better to save pda keys on chain and always calculate/derive client side? // - if save pubkeys and don't use #[account(seeds=[...])] then need to manually call or save @@ -83,8 +96,6 @@ impl Propeller { 8 + //process_swim_payload_fee 8 + // complete_with_payload_cost 8 + // process_swim_payload_cost - // 8 + //propeller_min_transfer_amount - // 8 + //propeller_eth_min_transfer_amount 32 + //fee_vault 32 + //aggregator 8; //max_staleness @@ -166,27 +177,8 @@ impl SwimPayloadMessage { // SwimPayload::LEN; // swim_payload } -/// Utility function that verifies: -/// 1. pool_token_index < TOKEN_COUNT -/// 2. marginal_price_pool_token_accounts[pool_token_index].mint = propeller.marginal_price_pool_token_mint -/// 3. marginal_price_pool.token_mint_keys[pool_token_index] = propeller.marginal_price_pool_token_mint -pub fn validate_marginal_prices_pool_accounts<'info>( - propeller: &Propeller, - marginal_price_pool: &Account<'info, TwoPool>, - marginal_price_pool_token_accounts: &[&Account<'info, TokenAccount>; TOKEN_COUNT], -) -> Result<()> { - 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); - require_keys_eq!(marginal_price_pool.token_mint_keys[pool_token_index], propeller.marginal_price_pool_token_mint); - require_keys_eq!(pool_token_account.key(), marginal_price_pool_token_accounts[pool_token_index].key()); - Ok(()) -} - #[cfg(test)] mod tests { - #[test] fn test_non_propeller_swim_payload() {} diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs index 23ef6ff86..5cbfd7c55 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/governance.rs @@ -115,7 +115,8 @@ pub fn handle_change_governance_fee_account( #[derive(Accounts)] pub struct PrepareGovernanceTransition<'info> { pub governance: Governance<'info>, - pub upcoming_governance_key: Signer<'info>, + ///CHECK: not specifying type of account since it doesn't matter + pub upcoming_governance_key: UncheckedAccount<'info>, } pub fn handle_prepare_governance_transition( @@ -156,11 +157,13 @@ pub fn handle_enact_governance_transition(ctx: Context) -> Result<() #[derive(Accounts)] pub struct ChangePauseKey<'info> { pub governance: Governance<'info>, - pub new_pause_key: Signer<'info>, + ///CHECK: not specifying type of account since it doesn't matter + pub new_pause_key: UncheckedAccount<'info>, } pub fn handle_change_pause_key(ctx: Context, new_pause_key: Pubkey) -> Result<()> { require_keys_eq!(ctx.accounts.new_pause_key.key(), new_pause_key, PoolError::InvalidNewPauseKey); + require_keys_neq!(ctx.accounts.new_pause_key.key(), Pubkey::default(), PoolError::InvalidNewPauseKey); let pool = &mut ctx.accounts.governance.pool; pool.pause_key = new_pause_key; Ok(()) diff --git a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs index d98be4342..65491d0e1 100644 --- a/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs +++ b/packages/solana-contracts/programs/two-pool/src/instructions/governance/mod.rs @@ -1,27 +1,6 @@ -pub use { - // create_lp_metadata::*, - // adjust_amp_factor::*, change_governance_fee_account::*, change_pause_key::*, - governance::*, - lp_metadata::*, - // enact_fee_change::*, enact_governance_transition::*, - // mpl::*, - // prepare_fee_change::*, - // prepare_governance_transition::*, set_paused::*, - // update_lp_metadata::*, -}; +pub use {governance::*, lp_metadata::*}; -// pub mod adjust_amp_factor; -// pub mod change_governance_fee_account; -// pub mod change_pause_key; -// pub mod create_lp_metadata; pub mod governance; pub mod lp_metadata; -// pub mod enact_fee_change; -// pub mod enact_governance_transition; -// pub mod mpl; -// pub mod prepare_fee_change; -// pub mod prepare_governance_transition; -// pub mod set_paused; -// pub mod update_lp_metadata; pub const ENACT_DELAY: i64 = 3 * 86400; diff --git a/packages/solana-contracts/programs/two-pool/tests/governance_test.rs b/packages/solana-contracts/programs/two-pool/tests/governance_test.rs index aea8c6888..0b0f44e8b 100644 --- a/packages/solana-contracts/programs/two-pool/tests/governance_test.rs +++ b/packages/solana-contracts/programs/two-pool/tests/governance_test.rs @@ -81,7 +81,7 @@ async fn test_governance_transition() { let prepare_gov_transition_txn = Transaction::new_signed_with_payer( &[prepare_gov_transition_ix], Some(&pt_ctxt.get_payer().pubkey()), - &[pt_ctxt.get_payer(), pt_ctxt.get_governance(), &new_governance_key], + &[pt_ctxt.get_payer(), pt_ctxt.get_governance()], recent_blockhash, ); diff --git a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts index 2da65c512..65c6d7f37 100644 --- a/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts +++ b/packages/solana-contracts/src/__tests__/propeller/propeller.test.ts @@ -1567,11 +1567,17 @@ describe("propeller", () => { const wormholeMessage = web3.Keypair.generate(); const nonce = createNonce().readUInt32LE(0); + const targetChain = CHAIN_ID_ETH; + const [targetChainMap] = await getTargetChainMapAddr( + propeller, + targetChain, + propellerProgram.programId, + ); const transferNativeTxn = await propellerProgram.methods .crossChainTransferNativeWithPayload( nonce, transferAmount, - CHAIN_ID_ETH, + targetChain, evmOwner, ) .accounts({ @@ -1597,6 +1603,7 @@ describe("propeller", () => { // systemProgram, wormhole, tokenProgram: splToken.programId, + targetChainMap, }) .preInstructions([setComputeUnitLimitIx]) .postInstructions([createMemoInstruction(memo.toString("hex"))]) @@ -1706,11 +1713,17 @@ describe("propeller", () => { const maxFee = new BN(100_000); const nonce = createNonce().readUInt32LE(0); + const targetChain = CHAIN_ID_ETH; + const [targetChainMap] = await getTargetChainMapAddr( + propeller, + targetChain, + propellerProgram.programId, + ); const propellerTransferNativeTxn = await propellerProgram.methods .propellerTransferNativeWithPayload( nonce, transferAmount, - CHAIN_ID_ETH, + targetChain, evmOwner, gasKickstart, maxFee, @@ -1740,6 +1753,7 @@ describe("propeller", () => { // systemProgram, wormhole, tokenProgram: splToken.programId, + targetChainMap, }) .preInstructions([setComputeUnitLimitIx]) .postInstructions([createMemoInstruction(memo.toString("hex"))]) @@ -1850,12 +1864,18 @@ describe("propeller", () => { const gasKickstart = false; const maxFee = new BN(100_000); const nonce = createNonce().readUInt32LE(0); + const targetChain = CHAIN_ID_ETH; + const [targetChainMap] = await getTargetChainMapAddr( + propeller, + targetChain, + propellerProgram.programId, + ); const propellerTransferNativeTxn = await propellerProgram.methods .propellerTransferNativeWithPayload( nonce, transferAmount, - CHAIN_ID_ETH, + targetChain, evmOwner, gasKickstart, maxFee, @@ -1885,6 +1905,7 @@ describe("propeller", () => { // systemProgram, wormhole, tokenProgram: splToken.programId, + targetChainMap, }) .preInstructions([setComputeUnitLimitIx]) .transaction(); diff --git a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts index a9b66c3bb..4aef97ff6 100644 --- a/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts +++ b/packages/solana-contracts/src/__tests__/twoPool/pool.test.ts @@ -1023,7 +1023,7 @@ describe("TwoPool", () => { }, newPauseKey: newPauseKeypair.publicKey, }) - .signers([governanceKeypair, newPauseKeypair]) + .signers([governanceKeypair]) .rpc(); console.info(`changePauseKeyTxn: ${changePauseKeyTxn}`); @@ -1128,7 +1128,7 @@ describe("TwoPool", () => { }, upcomingGovernanceKey: upcomingGovernanceKey, }) - .signers([governanceKeypair, upcomingGovernanceKeypair]) + .signers([governanceKeypair]) .rpc(); console.info( `send prepareGovernanceTransitionTxn: ${prepareGovernanceTransitionTxn}`, diff --git a/packages/solana-contracts/src/artifacts/propeller.json b/packages/solana-contracts/src/artifacts/propeller.json index 306491717..6f91399dc 100644 --- a/packages/solana-contracts/src/artifacts/propeller.json +++ b/packages/solana-contracts/src/artifacts/propeller.json @@ -215,34 +215,39 @@ "name": "changePauseKey", "accounts": [ { - "name": "propeller", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] } - ] - } - }, - { - "name": "governanceKey", - "isMut": false, - "isSigner": true + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] }, { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -254,6 +259,52 @@ }, { "name": "prepareGovernanceTransition", + "accounts": [ + { + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] + }, + { + "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", @@ -279,22 +330,12 @@ "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [ - { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] + "args": [] }, { - "name": "enactGovernanceTransition", + "name": "updateFees", "accounts": [ { "name": "propeller", @@ -320,14 +361,16 @@ "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [] + "args": [ + { + "name": "feeUpdates", + "type": { + "defined": "FeeUpdates" + } + } + ] }, { "name": "createTokenNumberMap", @@ -1312,8 +1355,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1390,8 +1432,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1415,8 +1456,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1440,8 +1480,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1460,8 +1499,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1626,8 +1664,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1704,8 +1741,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1729,8 +1765,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1754,8 +1789,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1774,8 +1808,7 @@ "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1992,13 +2025,17 @@ "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -2483,13 +2520,17 @@ "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -4183,6 +4224,10 @@ }, { "name": "marginalPricePool", + "docs": [ + "pool used to get marginal price of swimUSD -> stablecoin for gas conversion", + "e.g. usdc-usdt pool" + ], "type": "publicKey" }, { @@ -4199,9 +4244,6 @@ }, { "name": "aggregator", - "docs": [ - "switchboard *" - ], "type": "publicKey" }, { @@ -4307,6 +4349,82 @@ } ], "types": [ + { + "name": "FeeUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "secpVerifyInitFee", + "type": { + "option": "u64" + } + }, + { + "name": "secpVerifyFee", + "type": { + "option": "u64" + } + }, + { + "name": "postVaaFee", + "type": { + "option": "u64" + } + }, + { + "name": "initAtaFee", + "type": { + "option": "u64" + } + }, + { + "name": "completeWithPayloadFee", + "type": { + "option": "u64" + } + }, + { + "name": "processSwimPayloadFee", + "type": { + "option": "u64" + } + } + ] + } + }, + { + "name": "GasOracleUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "aggregator", + "type": { + "option": "publicKey" + } + }, + { + "name": "maxStaleness", + "type": { + "option": "i64" + } + }, + { + "name": "maxConfidenceInterval", + "type": { + "option": "i64" + } + }, + { + "name": "fallbackOracle", + "type": { + "option": "publicKey" + } + } + ] + } + }, { "name": "InitializeParams", "type": { diff --git a/packages/solana-contracts/src/artifacts/propeller.ts b/packages/solana-contracts/src/artifacts/propeller.ts index 7a3efdd12..ff99d41c9 100644 --- a/packages/solana-contracts/src/artifacts/propeller.ts +++ b/packages/solana-contracts/src/artifacts/propeller.ts @@ -215,34 +215,39 @@ export type Propeller = { "name": "changePauseKey", "accounts": [ { - "name": "propeller", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] } - ] - } - }, - { - "name": "governanceKey", - "isMut": false, - "isSigner": true + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] }, { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -254,6 +259,52 @@ export type Propeller = { }, { "name": "prepareGovernanceTransition", + "accounts": [ + { + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] + }, + { + "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", @@ -279,22 +330,12 @@ export type Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [ - { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] + "args": [] }, { - "name": "enactGovernanceTransition", + "name": "updateFees", "accounts": [ { "name": "propeller", @@ -320,14 +361,16 @@ export type Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [] + "args": [ + { + "name": "feeUpdates", + "type": { + "defined": "FeeUpdates" + } + } + ] }, { "name": "createTokenNumberMap", @@ -1312,8 +1355,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1390,8 +1432,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1415,8 +1456,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1440,8 +1480,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1460,8 +1499,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1626,8 +1664,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1704,8 +1741,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1729,8 +1765,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -1754,8 +1789,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1774,8 +1808,7 @@ export type Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -1992,13 +2025,17 @@ export type Propeller = { "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -2483,13 +2520,17 @@ export type Propeller = { "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -4183,6 +4224,10 @@ export type Propeller = { }, { "name": "marginalPricePool", + "docs": [ + "pool used to get marginal price of swimUSD -> stablecoin for gas conversion", + "e.g. usdc-usdt pool" + ], "type": "publicKey" }, { @@ -4199,9 +4244,6 @@ export type Propeller = { }, { "name": "aggregator", - "docs": [ - "switchboard *" - ], "type": "publicKey" }, { @@ -4307,6 +4349,82 @@ export type Propeller = { } ], "types": [ + { + "name": "FeeUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "secpVerifyInitFee", + "type": { + "option": "u64" + } + }, + { + "name": "secpVerifyFee", + "type": { + "option": "u64" + } + }, + { + "name": "postVaaFee", + "type": { + "option": "u64" + } + }, + { + "name": "initAtaFee", + "type": { + "option": "u64" + } + }, + { + "name": "completeWithPayloadFee", + "type": { + "option": "u64" + } + }, + { + "name": "processSwimPayloadFee", + "type": { + "option": "u64" + } + } + ] + } + }, + { + "name": "GasOracleUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "aggregator", + "type": { + "option": "publicKey" + } + }, + { + "name": "maxStaleness", + "type": { + "option": "i64" + } + }, + { + "name": "maxConfidenceInterval", + "type": { + "option": "i64" + } + }, + { + "name": "fallbackOracle", + "type": { + "option": "publicKey" + } + } + ] + } + }, { "name": "InitializeParams", "type": { @@ -5285,34 +5403,39 @@ export const IDL: Propeller = { "name": "changePauseKey", "accounts": [ { - "name": "propeller", - "isMut": true, - "isSigner": false, - "pda": { - "seeds": [ - { - "kind": "const", - "type": "string", - "value": "propeller" - }, - { - "kind": "account", - "type": "publicKey", - "account": "Propeller", - "path": "propeller.swim_usd_mint" + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] } - ] - } - }, - { - "name": "governanceKey", - "isMut": false, - "isSigner": true + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] }, { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -5324,6 +5447,52 @@ export const IDL: Propeller = { }, { "name": "prepareGovernanceTransition", + "accounts": [ + { + "name": "governance", + "accounts": [ + { + "name": "propeller", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "propeller" + }, + { + "kind": "account", + "type": "publicKey", + "account": "Propeller", + "path": "propeller.swim_usd_mint" + } + ] + } + }, + { + "name": "governanceKey", + "isMut": false, + "isSigner": true + } + ] + }, + { + "name": "upcomingGovernanceKey", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "upcomingGovernanceKey", + "type": "publicKey" + } + ] + }, + { + "name": "enactGovernanceTransition", "accounts": [ { "name": "propeller", @@ -5349,22 +5518,12 @@ export const IDL: Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [ - { - "name": "upcomingGovernanceKey", - "type": "publicKey" - } - ] + "args": [] }, { - "name": "enactGovernanceTransition", + "name": "updateFees", "accounts": [ { "name": "propeller", @@ -5390,14 +5549,16 @@ export const IDL: Propeller = { "name": "governanceKey", "isMut": false, "isSigner": true - }, - { - "name": "upcomingGovernanceKey", - "isMut": false, - "isSigner": true } ], - "args": [] + "args": [ + { + "name": "feeUpdates", + "type": { + "defined": "FeeUpdates" + } + } + ] }, { "name": "createTokenNumberMap", @@ -6382,8 +6543,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -6460,8 +6620,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -6485,8 +6644,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -6510,8 +6668,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -6530,8 +6687,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -6696,8 +6852,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -6774,8 +6929,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -6799,8 +6953,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "token_bridge" } } }, @@ -6824,8 +6977,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -6844,8 +6996,7 @@ export const IDL: Propeller = { "programId": { "kind": "account", "type": "publicKey", - "account": "Propeller", - "path": "propeller" + "path": "wormhole" } } }, @@ -7062,13 +7213,17 @@ export const IDL: Propeller = { "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -7553,13 +7708,17 @@ export const IDL: Propeller = { "seeds = [", "vaa.emitter_address, vaa.emitter_chain, vaa.sequence", "],", - "seeds::program = token_bridge" + "seeds::program = token_bridge", + "checked in CPI" ] }, { "name": "endpoint", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "checked in CPI" + ] }, { "name": "redeemerEscrow", @@ -9253,6 +9412,10 @@ export const IDL: Propeller = { }, { "name": "marginalPricePool", + "docs": [ + "pool used to get marginal price of swimUSD -> stablecoin for gas conversion", + "e.g. usdc-usdt pool" + ], "type": "publicKey" }, { @@ -9269,9 +9432,6 @@ export const IDL: Propeller = { }, { "name": "aggregator", - "docs": [ - "switchboard *" - ], "type": "publicKey" }, { @@ -9377,6 +9537,82 @@ export const IDL: Propeller = { } ], "types": [ + { + "name": "FeeUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "secpVerifyInitFee", + "type": { + "option": "u64" + } + }, + { + "name": "secpVerifyFee", + "type": { + "option": "u64" + } + }, + { + "name": "postVaaFee", + "type": { + "option": "u64" + } + }, + { + "name": "initAtaFee", + "type": { + "option": "u64" + } + }, + { + "name": "completeWithPayloadFee", + "type": { + "option": "u64" + } + }, + { + "name": "processSwimPayloadFee", + "type": { + "option": "u64" + } + } + ] + } + }, + { + "name": "GasOracleUpdates", + "type": { + "kind": "struct", + "fields": [ + { + "name": "aggregator", + "type": { + "option": "publicKey" + } + }, + { + "name": "maxStaleness", + "type": { + "option": "i64" + } + }, + { + "name": "maxConfidenceInterval", + "type": { + "option": "i64" + } + }, + { + "name": "fallbackOracle", + "type": { + "option": "publicKey" + } + } + ] + } + }, { "name": "InitializeParams", "type": { diff --git a/packages/solana-contracts/src/artifacts/two_pool.json b/packages/solana-contracts/src/artifacts/two_pool.json index 2fe29473c..64afef5a0 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.json +++ b/packages/solana-contracts/src/artifacts/two_pool.json @@ -1058,7 +1058,7 @@ { "name": "upcomingGovernanceKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -1159,7 +1159,7 @@ { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ diff --git a/packages/solana-contracts/src/artifacts/two_pool.ts b/packages/solana-contracts/src/artifacts/two_pool.ts index 0dcfb296a..e92b8cbe4 100644 --- a/packages/solana-contracts/src/artifacts/two_pool.ts +++ b/packages/solana-contracts/src/artifacts/two_pool.ts @@ -1058,7 +1058,7 @@ export type TwoPool = { { "name": "upcomingGovernanceKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -1159,7 +1159,7 @@ export type TwoPool = { { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -3269,7 +3269,7 @@ export const IDL: TwoPool = { { "name": "upcomingGovernanceKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [ @@ -3370,7 +3370,7 @@ export const IDL: TwoPool = { { "name": "newPauseKey", "isMut": false, - "isSigner": true + "isSigner": false } ], "args": [