-
Notifications
You must be signed in to change notification settings - Fork 10
fix: wsol edgecase #461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: wsol edgecase #461
Changes from all commits
a77cc23
1da9d68
abc931d
a29fadf
a3b2d90
8bca362
a79ffe5
55afd42
e4e11f9
0d901f2
0fbcf16
02704af
2c91b9a
cb5e2b6
43f4491
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -832,6 +832,7 @@ impl Service<Svm> { | |
| tx: &VersionedTransaction, | ||
| swap_data: &express_relay_svm::SwapArgs, | ||
| swap_accounts: &SwapAccounts, | ||
| opportunity_swap_data: &OpportunitySvmProgramSwap, | ||
| ) -> Result<(), RestError> { | ||
| let transfer_instructions = self.extract_transfer_instructions(tx).await?; | ||
| if transfer_instructions.len() > 1 { | ||
|
|
@@ -845,6 +846,11 @@ impl Service<Svm> { | |
|
|
||
| // User have to wrap Sol | ||
| if swap_accounts.mint_user == spl_token::native_mint::id() { | ||
| // Sometimes the user doesn't have enough SOL, but we want the transaction to fail in the Express Relay program with InsufficientUserFunds | ||
| // Therefore we allow the user to wrap less SOL than needed so it doesn't fail in the transfer instruction | ||
| let amount_user_to_wrap = | ||
| opportunity_swap_data.get_user_amount_to_wrap(swap_data.amount_user); | ||
|
|
||
| if transfer_instructions.len() != 1 { | ||
| return Err(RestError::InvalidInstruction( | ||
| None, | ||
|
|
@@ -874,11 +880,14 @@ impl Service<Svm> { | |
| }, | ||
| )); | ||
| } | ||
| if swap_data.amount_user != transfer_instruction.lamports { | ||
| // todo: remove swap_data.amount_user != transfer_instruction.lamports once searchers have updated their sdk | ||
| if swap_data.amount_user != transfer_instruction.lamports | ||
| && amount_user_to_wrap != transfer_instruction.lamports | ||
| { | ||
| return Err(RestError::InvalidInstruction( | ||
| Some(transfer_instruction.index), | ||
| InstructionError::InvalidAmountTransferInstruction { | ||
| expected: swap_data.amount_user, | ||
| expected: amount_user_to_wrap, | ||
| found: transfer_instruction.lamports, | ||
| }, | ||
| )); | ||
|
|
@@ -1300,8 +1309,9 @@ impl Service<Svm> { | |
| tx: &VersionedTransaction, | ||
| swap_data: &express_relay_svm::SwapArgs, | ||
| swap_accounts: &SwapAccounts, | ||
| opportunity_swap_data: &OpportunitySvmProgramSwap, | ||
| ) -> Result<(), RestError> { | ||
| self.check_transfer_instruction(tx, swap_data, swap_accounts) | ||
| self.check_transfer_instruction(tx, swap_data, swap_accounts, opportunity_swap_data) | ||
| .await?; | ||
| if swap_accounts.mint_user == spl_token::native_mint::id() { | ||
| // User has to wrap Sol | ||
|
|
@@ -1410,6 +1420,7 @@ impl Service<Svm> { | |
| &bid_data.transaction, | ||
| &swap_data, | ||
| &swap_accounts, | ||
| opportunity_swap_data, | ||
| ) | ||
| .await?; | ||
|
|
||
|
|
@@ -1831,6 +1842,7 @@ mod tests { | |
| AccountMeta, | ||
| Instruction, | ||
| }, | ||
| native_token::LAMPORTS_PER_SOL, | ||
| packet::PACKET_DATA_SIZE, | ||
| pubkey::Pubkey, | ||
| signature::Keypair, | ||
|
|
@@ -1985,7 +1997,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: | ||
| TokenAccountInitializationConfigs::searcher_payer(), | ||
| memo: None, | ||
|
|
@@ -2021,7 +2033,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: | ||
| TokenAccountInitializationConfigs::searcher_payer(), | ||
| memo: None, | ||
|
|
@@ -2057,7 +2069,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: TokenAccountInitializationConfigs { | ||
| user_ata_mint_user: TokenAccountInitializationConfig::SearcherPayer, | ||
| ..TokenAccountInitializationConfigs::searcher_payer() | ||
|
|
@@ -2095,7 +2107,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: | ||
| TokenAccountInitializationConfigs::searcher_payer(), | ||
| memo: None, | ||
|
|
@@ -2140,7 +2152,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: | ||
| TokenAccountInitializationConfigs::searcher_payer(), | ||
| memo: None, | ||
|
|
@@ -2177,7 +2189,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token: fee_token.clone(), | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: TokenAccountInitializationConfigs { | ||
| user_ata_mint_user: TokenAccountInitializationConfig::UserPayer, | ||
| user_ata_mint_searcher: TokenAccountInitializationConfig::UserPayer, | ||
|
|
@@ -2216,7 +2228,7 @@ mod tests { | |
| token_program_searcher: spl_token::id(), | ||
| fee_token, | ||
| referral_fee_bps, | ||
| user_mint_user_balance: 0, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how were all these passing previously?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
| user_mint_user_balance: LAMPORTS_PER_SOL, | ||
| token_account_initialization_configs: | ||
| TokenAccountInitializationConfigs::searcher_payer(), | ||
| memo: Some("memo".to_string()), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,18 +19,21 @@ use { | |
| }, | ||
| ::express_relay::FeeToken as ProgramFeeToken, | ||
| express_relay::state::FEE_SPLIT_PRECISION, | ||
| express_relay_api_types::{ | ||
| opportunity as api, | ||
| opportunity::QuoteTokensWithTokenPrograms, | ||
| express_relay_api_types::opportunity::{ | ||
| self as api, | ||
| QuoteTokensWithTokenPrograms, | ||
| }, | ||
| serde::{ | ||
| Deserialize, | ||
| Serialize, | ||
| }, | ||
| solana_sdk::{ | ||
| clock::Slot, | ||
| program_pack::Pack, | ||
| pubkey::Pubkey, | ||
| rent::Rent, | ||
| }, | ||
| spl_token_2022::state::Account as TokenAccount, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems fine since you're using the token 2022 token account (which is greater than 165 bytes, i think). i don't think there's any real edge cases, this seems to be overcompensating for the user in the case that they have enough SOL to pay for legacy token accounts but not for token 2022 token accounts. but probably worth a comment just noting this down for devX reasons
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's quite tricky because TokenAccount::LEN is actually 165, so this code might not work for token22, won't fix now but added a todo |
||
| std::ops::Deref, | ||
| time::{ | ||
| Duration, | ||
|
|
@@ -277,6 +280,28 @@ pub fn get_opportunity_swap_data(opp: &OpportunitySvm) -> &OpportunitySvmProgram | |
| } | ||
| } | ||
|
|
||
| impl OpportunitySvmProgramSwap { | ||
| pub fn get_user_amount_to_wrap(&self, amount_user: u64) -> u64 { | ||
| let number_of_atas_paid_by_user = [ | ||
| &self.token_account_initialization_configs.user_ata_mint_user, | ||
| &self | ||
| .token_account_initialization_configs | ||
| .user_ata_mint_searcher, | ||
| ] | ||
| .iter() | ||
| .filter(|&&config| matches!(config, TokenAccountInitializationConfig::UserPayer)) | ||
| .count(); | ||
|
|
||
| std::cmp::min( | ||
| amount_user, | ||
| self.user_mint_user_balance.saturating_sub( | ||
| number_of_atas_paid_by_user as u64 | ||
| * Rent::default().minimum_balance(TokenAccount::LEN), // todo: token2022 accounts can be bigger than this, this hack might not work for them | ||
| ), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| impl From<TokenAccountInitializationConfig> for api::TokenAccountInitializationConfig { | ||
| fn from(val: TokenAccountInitializationConfig) -> Self { | ||
| match val { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.