From ca00680215dea5077ea7d60f3a45173855360813 Mon Sep 17 00:00:00 2001 From: William Date: Wed, 12 Feb 2025 22:46:09 +0800 Subject: [PATCH] update error --- src/jito/api.rs | 8 ++--- src/jito/mod.rs | 42 +++++++++++++--------- src/lib.rs | 95 ++++++++++++++++++++++++------------------------- 3 files changed, 77 insertions(+), 68 deletions(-) diff --git a/src/jito/api.rs b/src/jito/api.rs index f9cf101..56d4645 100644 --- a/src/jito/api.rs +++ b/src/jito/api.rs @@ -3,6 +3,7 @@ use std::env; use anyhow::{Context, Result}; use reqwest::Proxy; use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; use std::convert::TryFrom; use super::TipPercentileData; @@ -45,17 +46,16 @@ pub async fn get_tip_accounts(block_engine_url: &str) -> Result { println!("result: {:?}", result); Ok(result) } + /// tip accounts #[derive(Debug)] pub struct TipAccountResult { pub accounts: Vec, } -impl TryFrom for TipAccountResult { - type Error = anyhow::Error; - fn try_from(value: RpcResponse) -> Result { +impl TipAccountResult { + pub fn from(value: Value) -> Result { let accounts = value - .result .as_array() .context("expected 'result' to be an array")? .iter() diff --git a/src/jito/mod.rs b/src/jito/mod.rs index 3bf0109..58a6194 100644 --- a/src/jito/mod.rs +++ b/src/jito/mod.rs @@ -1,7 +1,7 @@ use std::{convert::TryInto, future::Future, str::FromStr, time::Duration, fmt}; use anyhow::{anyhow, Result}; -use api::{get_tip_accounts, TipAccountResult}; +use api::TipAccountResult; use rand::{rng, seq::IteratorRandom}; use reqwest::Client; use serde::Deserialize; @@ -95,7 +95,19 @@ impl JitoClient { } } - async fn send_request(&self, endpoint: &str, method: &str, params: Option) -> ClientResult { + pub async fn get_tip_accounts(&self) -> Result { + let endpoint = if let Some(uuid) = &self.uuid { + format!("/bundles?uuid={}", uuid) + } else { + "/bundles".to_string() + }; + + let result = self.send_request(&endpoint, "getTipAccounts", None).await?; + let tip_accounts = TipAccountResult::from(result).map_err(|e| anyhow!(e))?; + Ok(tip_accounts) + } + + async fn send_request(&self, endpoint: &str, method: &str, params: Option) -> Result { let url = format!("{}{}", self.base_url, endpoint); let data = json!({ @@ -111,16 +123,16 @@ impl JitoClient { .json(&data) .send() .await - .map_err(|e| ClientError::Other(format!("Request failed: {}", e)))?; + .map_err(|e| anyhow!(format!("Request failed: {}", e)))?; let body = response.json::().await - .map_err(|e| ClientError::Other(format!("Failed to parse response: {}", e)))?; + .map_err(|e| anyhow!(format!("Failed to parse response: {}", e)))?; Ok(body) } pub async fn init_tip_accounts(&self) -> Result<()> { - let accounts: TipAccountResult = get_tip_accounts(&self.base_url).await?.try_into()?; + let accounts = self.get_tip_accounts().await?; let mut tip_accounts = self.tip_accounts.write().await; accounts @@ -186,10 +198,10 @@ impl JitoClient { pub async fn send_transaction( &self, transaction: &Transaction, - ) -> ClientResult { + ) -> Result { let wire_transaction = bincode::serialize(transaction).map_err(|e| { - ClientError::Parse( - "Transaction serialization failed".to_string(), + anyhow!( + "Transaction serialization failed: {}", e.to_string(), ) })?; @@ -208,13 +220,10 @@ impl JitoClient { response["result"] .as_str() .map(|s| s.to_string()) - .ok_or_else(|| ClientError::Parse( - "Invalid response format".to_string(), - "Missing result field".to_string(), - )) + .ok_or_else(|| anyhow!("Invalid response format: missing result field")) } - pub async fn send_bundle(&self, params: Option, uuid: Option) -> ClientResult { + pub async fn send_bundle(&self, params: Option, uuid: Option) -> Result { let mut endpoint = "/bundles".to_string(); if let Some(uuid) = uuid { @@ -225,14 +234,14 @@ impl JitoClient { let transactions = match params { Some(Value::Array(transactions)) => { if transactions.is_empty() { - return Err(ClientError::Other("Bundle must contain at least one transaction".to_string())); + return Err(anyhow!("Bundle must contain at least one transaction")); } if transactions.len() > 5 { - return Err(ClientError::Other("Bundle can contain at most 5 transactions".to_string())); + return Err(anyhow!("Bundle can contain at most 5 transactions")); } transactions }, - _ => return Err(ClientError::Other("Invalid bundle format: expected an array of transactions".to_string())), + _ => return Err(anyhow!("Invalid bundle format: expected an array of transactions")), }; // Wrap the transactions array in another array @@ -241,6 +250,7 @@ impl JitoClient { // Send the wrapped transactions array self.send_request(&endpoint, "sendBundle", Some(params)) .await + .map_err(|e| anyhow!(e)) } pub async fn wait_for_bundle_confirmation( diff --git a/src/lib.rs b/src/lib.rs index f22ab9b..303d436 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,6 @@ use std::sync::Arc; use std::time::Instant; use crate::jito::JitoClient; -use crate::error::ClientError; use borsh::BorshDeserialize; @@ -102,10 +101,10 @@ impl PumpFun { mint: &Keypair, metadata: utils::CreateTokenMetadata, priority_fee: Option, - ) -> Result { + ) -> Result { let ipfs = utils::create_token_metadata(metadata) .await - .map_err(ClientError::UploadMetadataError)?; + .map_err(|_| anyhow!("Failed to upload metadata"))?; let mut instructions = self.create_priority_fee_instructions(priority_fee); @@ -140,10 +139,10 @@ impl PumpFun { amount_sol: u64, slippage_basis_points: Option, priority_fee: Option, - ) -> Result { + ) -> Result { let ipfs = utils::create_token_metadata(metadata) .await - .map_err(ClientError::UploadMetadataError)?; + .map_err(|e| anyhow!(e.to_string()))?; let global_account = self.get_global_account()?; let buy_amount = global_account.get_initial_buy_price(amount_sol); @@ -202,12 +201,12 @@ impl PumpFun { amount_sol: u64, slippage_basis_points: Option, priority_fee: Option, - ) -> Result { + ) -> Result { let global_account = self.get_global_account()?; let bonding_curve_account = self.get_bonding_curve_account(mint)?; let buy_amount = bonding_curve_account .get_buy_price(amount_sol) - .map_err(ClientError::BondingCurveError)?; + .map_err(|e| anyhow!(e))?; let buy_amount_with_slippage = utils::calculate_with_slippage_buy(amount_sol, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE)); @@ -253,11 +252,11 @@ impl PumpFun { max_sol_cost: u64, slippage_basis_points: Option, jito_fee: Option, - ) -> Result { + ) -> Result { let start_time = Instant::now(); let jito_client = self.jito_client.as_ref() - .ok_or_else(|| ClientError::Other("Jito client not found".to_string()))?; + .ok_or_else(|| anyhow!("Jito client not found"))?; let global_account = self.get_global_account()?; let buy_amount_with_slippage = @@ -315,22 +314,22 @@ impl PumpFun { amount_token: Option, slippage_basis_points: Option, priority_fee: Option, - ) -> Result { + ) -> Result { let ata = get_associated_token_address(&self.payer.pubkey(), mint); let balance = self.rpc.get_token_account_balance(&ata)?; let balance_u64 = balance.amount.parse::() - .map_err(|_| ClientError::Other("Failed to parse token balance".to_string()))?; + .map_err(|_| anyhow!("Failed to parse token balance"))?; let amount = amount_token.unwrap_or(balance_u64); if amount == 0 { - return Err(ClientError::Other("Balance is 0".to_string())); + return Err(anyhow!("Balance is 0")); } let global_account = self.get_global_account()?; let bonding_curve_account = self.get_bonding_curve_account(mint)?; let min_sol_output = bonding_curve_account .get_sell_price(amount, global_account.fee_basis_points) - .map_err(ClientError::BondingCurveError)?; + .map_err(|e| anyhow!(e))?; let min_sol_output_with_slippage = utils::calculate_with_slippage_sell( min_sol_output, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), @@ -376,18 +375,18 @@ impl PumpFun { percent: u64, slippage_basis_points: Option, priority_fee: Option, - ) -> Result { + ) -> Result { if percent > 100 { - return Err(ClientError::Other("Percentage must be between 0 and 100".to_string())); + return Err(anyhow!("Percentage must be between 0 and 100")); } let ata = get_associated_token_address(&self.payer.pubkey(), mint); let balance = self.rpc.get_token_account_balance(&ata)?; let balance_u64 = balance.amount.parse::() - .map_err(|_| ClientError::Other("Failed to parse token balance".to_string()))?; + .map_err(|_| anyhow!("Failed to parse token balance"))?; if balance_u64 == 0 { - return Err(ClientError::Other("Balance is 0".to_string())); + return Err(anyhow!("Balance is 0")); } let amount = balance_u64 * percent / 100; @@ -400,18 +399,18 @@ impl PumpFun { percent: u64, slippage_basis_points: Option, jito_fee: Option, - ) -> Result { + ) -> Result { if percent > 100 { - return Err(ClientError::Other("Percentage must be between 0 and 100".to_string())); + return Err(anyhow!("Percentage must be between 0 and 100")); } let ata = get_associated_token_address(&self.payer.pubkey(), mint); let balance = self.rpc.get_token_account_balance(&ata)?; let balance_u64 = balance.amount.parse::() - .map_err(|_| ClientError::Other("Failed to parse token balance".to_string()))?; + .map_err(|_| anyhow!("Failed to parse token balance"))?; if balance_u64 == 0 { - return Err(ClientError::Other("Balance is 0".to_string())); + return Err(anyhow!("Balance is 0")); } let amount = balance_u64 * percent / 100; @@ -425,34 +424,34 @@ impl PumpFun { amount_token: Option, slippage_basis_points: Option, jito_fee: Option, - ) -> Result { + ) -> Result { let start_time = Instant::now(); let jito_client = self.jito_client.as_ref() - .ok_or_else(|| ClientError::Other("Jito client not found".to_string()))?; + .ok_or_else(|| anyhow!("Jito client not found"))?; let ata = get_associated_token_address(&self.payer.pubkey(), mint); let balance = self.rpc.get_token_account_balance(&ata)?; let balance_u64 = balance.amount.parse::() - .map_err(|_| ClientError::Other("Failed to parse token balance".to_string()))?; + .map_err(|_| anyhow!("Failed to parse token balance"))?; let amount = amount_token.unwrap_or(balance_u64); if amount == 0 { - return Err(ClientError::Other("Amount cannot be zero".to_string())); + return Err(anyhow!("Amount cannot be zero")); } let global_account = self.get_global_account()?; let bonding_curve_account = self.get_bonding_curve_account(mint)?; let min_sol_output = bonding_curve_account .get_sell_price(amount, global_account.fee_basis_points) - .map_err(ClientError::BondingCurveError)?; + .map_err(|e| anyhow!(e))?; let min_sol_output_with_slippage = utils::calculate_with_slippage_sell( min_sol_output, slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE), ); let mut instructions = vec![]; - let tip_account = jito_client.get_tip_account().await.map_err(|e| ClientError::Other(e.to_string()))?; + let tip_account = jito_client.get_tip_account().await.map_err(|e| anyhow!(e))?; instructions.push(instruction::sell( &self.payer.clone(), mint, @@ -512,7 +511,7 @@ impl PumpFun { self.payer.pubkey() } - pub fn get_token_balance(&self, account: &Pubkey, mint: &Pubkey) -> Result { + pub fn get_token_balance(&self, account: &Pubkey, mint: &Pubkey) -> Result { let ata = get_associated_token_address(account, mint); if self.rpc.get_account(&ata).is_err() { return Ok(0); @@ -520,18 +519,18 @@ impl PumpFun { let balance = self.rpc.get_token_account_balance(&ata)?; balance.amount.parse::() - .map_err(|_| ClientError::Other("Failed to parse token balance".to_string())) + .map_err(|_| anyhow!("Failed to parse token balance")) } - pub fn get_sol_balance(&self, account: &Pubkey) -> Result { - self.rpc.get_balance(account).map_err(ClientError::SolanaClientError) + pub fn get_sol_balance(&self, account: &Pubkey) -> Result { + self.rpc.get_balance(account).map_err(|_| anyhow!("Failed to get SOL balance")) } - pub fn get_payer_token_balance(&self, mint: &Pubkey) -> Result { + pub fn get_payer_token_balance(&self, mint: &Pubkey) -> Result { self.get_token_balance(&self.payer.pubkey(), mint) } - pub fn get_payer_sol_balance(&self) -> Result { + pub fn get_payer_sol_balance(&self) -> Result { self.get_sol_balance(&self.payer.pubkey()) } @@ -563,22 +562,22 @@ impl PumpFun { } // Account related methods - pub fn get_global_account(&self) -> Result { + pub fn get_global_account(&self) -> Result { let global = Self::get_global_pda(); let account = self.rpc.get_account(&global)?; accounts::GlobalAccount::try_from_slice(&account.data) - .map_err(ClientError::BorshError) + .map_err(|e| anyhow!(e)) } pub fn get_bonding_curve_account( &self, mint: &Pubkey, - ) -> Result { + ) -> Result { let bonding_curve_pda = Self::get_bonding_curve_pda(mint) - .ok_or(ClientError::BondingCurveNotFound)?; + .ok_or(anyhow!("Bonding curve not found"))?; let account = self.rpc.get_account(&bonding_curve_pda)?; accounts::BondingCurveAccount::try_from_slice(&account.data) - .map_err(ClientError::BorshError) + .map_err(|e| anyhow!(e)) } // Subscription related methods @@ -636,7 +635,7 @@ impl PumpFun { }) } - pub async fn get_token_price_in_usdc(&self, token_amount: f64) -> Result { + pub async fn get_token_price_in_usdc(&self, token_amount: f64) -> Result { if token_amount == 0.0 { return Ok(0.0); } @@ -644,39 +643,39 @@ impl PumpFun { let url = "https://api.jup.ag/price/v2?ids=So11111111111111111111111111111111111111112"; let response: serde_json::Value = reqwest::get(url) .await - .map_err(|e: reqwest::Error| ClientError::Other(Box::new(e).to_string()))? + .map_err(|e: reqwest::Error| anyhow!(e))? .json() .await - .map_err(|e: reqwest::Error| ClientError::Other(Box::new(e).to_string()))?; + .map_err(|e: reqwest::Error| anyhow!(e))?; let sol_price_str = response["data"]["So11111111111111111111111111111111111111112"]["price"] .as_str() - .ok_or(ClientError::Other("Failed to find SOL price as a string".into()))?; + .ok_or(anyhow!("Failed to find SOL price as a string"))?; let sol_price_in_usdc: f64 = sol_price_str .parse() - .map_err(|e: std::num::ParseFloatError| ClientError::Other(Box::new(e).to_string()))?; + .map_err(|e: std::num::ParseFloatError| anyhow!(e))?; let token_price_in_usdc = sol_price_in_usdc * token_amount; Ok(token_price_in_usdc) } - pub async fn get_sol_price_in_usdc(&self) -> Result { + pub async fn get_sol_price_in_usdc(&self) -> Result { let url = "https://api.jup.ag/price/v2?ids=So11111111111111111111111111111111111111112"; let response: serde_json::Value = reqwest::get(url) .await - .map_err(|_| ClientError::Anyhow("Failed to install crypto provider"))? + .map_err(|_| anyhow!("Failed to install crypto provider"))? .json() .await - .map_err(|_| ClientError::Anyhow("Failed to install crypto provider"))?; + .map_err(|_| anyhow!("Failed to install crypto provider"))?; let sol_price_str = response["data"]["So11111111111111111111111111111111111111112"]["price"] .as_str() - .ok_or(ClientError::Anyhow("Failed to find SOL price as a string"))?; + .ok_or(anyhow!("Failed to find SOL price as a string"))?; let sol_price_in_usdc: f64 = sol_price_str .parse() - .map_err(|_| ClientError::Anyhow("Failed to parse SOL price as a string"))?; + .map_err(|_| anyhow!("Failed to parse SOL price as a string"))?; Ok(sol_price_in_usdc) }