@@ -16,11 +16,14 @@ use shyft_rs_sdk::{
16
16
models:: parsed_transaction_details:: { self , ParsedTransactionDetails } ,
17
17
ShyftApi ,
18
18
} ;
19
- use solana_client:: { nonblocking:: rpc_client:: RpcClient , rpc_config:: RpcTransactionConfig } ;
20
- use solana_sdk:: { commitment_config:: CommitmentConfig , signature:: Signature } ;
19
+ use solana_client:: {
20
+ nonblocking:: rpc_client:: RpcClient , rpc_client:: GetConfirmedSignaturesForAddress2Config ,
21
+ rpc_config:: RpcTransactionConfig ,
22
+ } ;
23
+ use solana_sdk:: { commitment_config:: CommitmentConfig , pubkey:: Pubkey , signature:: Signature } ;
21
24
use solana_transaction_status:: UiTransactionEncoding ;
22
25
23
- use crate :: { get_spinner, PrevBuy , RepeatingWallet } ;
26
+ use crate :: { error :: PrevBuysFetchError , get_spinner, PrevBuy , RepeatingWallet } ;
24
27
25
28
/// Runs the main logic of the solana-copy-trade-detect application.
26
29
///
@@ -45,6 +48,8 @@ pub async fn run(args: &crate::Args) -> Result<Vec<RepeatingWallet>, crate::Erro
45
48
let fresh_swaps = fetch_fresh_swaps ( args) . await ?;
46
49
spinner. finish ( ) ;
47
50
51
+ tracing:: info!( "Fetched {} fresh swaps" , fresh_swaps. len( ) ) ;
52
+
48
53
if fresh_swaps. is_empty ( ) {
49
54
eprintln ! (
50
55
"\n {}" ,
@@ -87,7 +92,10 @@ pub async fn run(args: &crate::Args) -> Result<Vec<RepeatingWallet>, crate::Erro
87
92
88
93
for item in fresh_swaps. iter ( ) {
89
94
if let models:: feed:: Item :: Swap ( swap) = item {
90
- let prev_buys = fetch_prev_buys ( args, & shyft_api, swap) . await ?;
95
+ let prev_buys =
96
+ fetch_prev_buys ( args, & rpc_client, & shyft_api, swap, args. delay_ms ) . await ?;
97
+
98
+ tracing:: info!( "Fetched {} previous buys" , prev_buys. len( ) ) ;
91
99
92
100
for buy in prev_buys. iter ( ) {
93
101
let block_diff = get_block_diff ( & rpc_client, swap, buy, args. delay_ms ) . await ?;
@@ -156,29 +164,99 @@ async fn fetch_fresh_swaps(
156
164
/// # Arguments
157
165
///
158
166
/// * `args` - A reference to the arguments containing the API key, wallet address, and other parameters.
167
+ /// * `rpc_client` - A reference to the Solana RPC client.
159
168
/// * `shyft_api` - A reference to the Shyft API client.
160
169
/// * `swap` - A reference to the swap transaction details.
170
+ /// * `delay_ms` - The delay in milliseconds between requests.
161
171
///
162
172
/// # Errors
163
173
///
164
- /// This function will return an error if the Shyft API request fails.
174
+ /// This function will return an error if the Shyft API request fails or if the transaction parsing fails .
165
175
async fn fetch_prev_buys (
166
176
args : & crate :: Args ,
177
+ rpc_client : & RpcClient ,
167
178
shyft_api : & ShyftApi ,
168
179
swap : & models:: feed:: Swap ,
169
- ) -> Result < Vec < ParsedTransactionDetails > , shyft_rs_sdk:: Error > {
170
- Ok ( filter_buys (
171
- shyft_api
172
- . get_transaction_history (
173
- & swap. token1_address ,
174
- Some ( args. scan_tx_count ) ,
175
- Some ( & swap. tx_hash ) ,
176
- None ,
177
- Some ( true ) ,
178
- None ,
180
+ delay_ms : u64 ,
181
+ ) -> Result < Vec < ParsedTransactionDetails > , PrevBuysFetchError > {
182
+ let successful_signatures =
183
+ fetch_successful_signatures ( rpc_client, swap, args. scan_tx_count as usize , delay_ms)
184
+ . await ?;
185
+ tracing:: info!(
186
+ "Fetched {} successful signatures" ,
187
+ successful_signatures. len( )
188
+ ) ;
189
+
190
+ if successful_signatures. is_empty ( ) {
191
+ tracing:: warn!( "No successful signatures found" ) ;
192
+ return Ok ( Vec :: new ( ) ) ;
193
+ }
194
+
195
+ let parsed_txs = shyft_api
196
+ . get_transaction_parse_selected (
197
+ & successful_signatures
198
+ [ ..std:: cmp:: min ( successful_signatures. len ( ) , args. scan_tx_count as usize ) ] ,
199
+ Some ( true ) ,
200
+ None ,
201
+ )
202
+ . await ?;
203
+
204
+ Ok ( filter_buys ( parsed_txs) )
205
+ }
206
+
207
+ /// Fetches successful transaction signatures for a given swap.
208
+ ///
209
+ /// This function retrieves the transaction signatures for the specified token address
210
+ /// and filters the signatures to include only those that are successful.
211
+ ///
212
+ /// # Arguments
213
+ ///
214
+ /// * `rpc_client` - A reference to the Solana RPC client.
215
+ /// * `swap` - A reference to the swap transaction details.
216
+ /// * `scan_tx_count` - The number of transaction signatures to scan.
217
+ /// * `delay_ms` - The delay in milliseconds between requests.
218
+ ///
219
+ /// # Errors
220
+ ///
221
+ /// This function will return an error if the Solana RPC request fails.
222
+ async fn fetch_successful_signatures (
223
+ rpc_client : & RpcClient ,
224
+ swap : & models:: feed:: Swap ,
225
+ scan_tx_count : usize ,
226
+ delay_ms : u64 ,
227
+ ) -> Result < Vec < String > , solana_client:: client_error:: ClientError > {
228
+ let mut successful_signatures = Vec :: new ( ) ;
229
+
230
+ let mut before_tx = Signature :: from_str ( & swap. tx_hash ) . unwrap ( ) ;
231
+ while successful_signatures. len ( ) < scan_tx_count {
232
+ let tx_signatures = rpc_client
233
+ . get_signatures_for_address_with_config (
234
+ & Pubkey :: from_str ( & swap. token1_address ) . unwrap ( ) ,
235
+ GetConfirmedSignaturesForAddress2Config {
236
+ before : Some ( before_tx) ,
237
+ until : None ,
238
+ limit : None ,
239
+ commitment : Some ( CommitmentConfig :: confirmed ( ) ) ,
240
+ } ,
179
241
)
180
- . await ?,
181
- ) )
242
+ . await ?;
243
+
244
+ tracing:: debug!( "Fetched {} signatures" , tx_signatures. len( ) ) ;
245
+
246
+ if tx_signatures. is_empty ( ) {
247
+ break ;
248
+ }
249
+ before_tx = Signature :: from_str ( & tx_signatures. last ( ) . unwrap ( ) . signature ) . unwrap ( ) ;
250
+
251
+ for signature in tx_signatures. iter ( ) {
252
+ if signature. err . is_none ( ) {
253
+ successful_signatures. push ( signature. signature . to_string ( ) ) ;
254
+ }
255
+ }
256
+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_millis ( delay_ms) ) . await ;
257
+ }
258
+
259
+ Ok ( successful_signatures)
182
260
}
183
261
184
262
/// Filters transactions to include only those that involve a swap where SOL is the input token.
0 commit comments