copy_trading/position_manager/
new_pool_loop.rs

1use std::sync::Arc;
2
3use crate::types::position_manager::PositionManager;
4use solana_central::derive_bonding_curve;
5use solana_central::PfBondingCurve;
6use solana_central::Pools;
7
8impl PositionManager {
9  /// Monitor new pool creations and handle Pumpfun bonding curve migrations. When a Pumpfun
10  /// bonding curve completes and migrates to a Pumpswap pool, updates the position's pool
11  /// reference and lookup key to the new pool address.
12  pub async fn new_pool_loop(position_manager: Arc<PositionManager>) {
13    let mut new_pool_receiver = position_manager.new_pool_receiver.resubscribe();
14    while let Ok(pool_arc) = new_pool_receiver.recv().await {
15      let pool = pool_arc.read().unwrap();
16      if *pool.pool_type() != Pools::PumpswapAmm {
17        continue;
18      }
19      /*
20      The pumpswap migrator wallet will always deploy a new pumpswap pool from the bonding curve
21      with SOL as the quote token and the token being traded as base (A). We store the bonding
22      curve address as a key in our positions map so we derive it for this token and see if it
23      exists in our open positions map.
24      */
25      let token_address = pool.token_a_vault_address();
26      let bonding_curve_address = derive_bonding_curve(token_address);
27      let open_positions = position_manager.open_positions.read().unwrap();
28      // We must have an active position
29      if !open_positions.contains_key(&bonding_curve_address) {
30        continue;
31      }
32
33      let position_arc = open_positions.get(&bonding_curve_address).expect("new_pool_loop: Position was located using a bonding curve address but the position was not found in the open positions map.").clone();
34
35      let mut position = position_arc.lock().unwrap();
36
37      let binding = position.pool.read().unwrap();
38      let bonding_curve = binding.as_any().downcast_ref::<PfBondingCurve>().expect("new_pool_loop: Position was located using a bonding curve address but the type fo the pool in the position is not a PfBondingCurve.");
39      let complete = bonding_curve.complete;
40      drop(binding);
41      if complete {
42        /*
43        Update pool in position to be pumpswap pool. Swap position lookup from the token address
44        used to lookup the bonding curve to now use the pool address to lookup the pumpswap pool.
45        */
46        position.pool = pool_arc.clone();
47        position.migrated = true;
48        position.pool_address = *pool.pool_address();
49        // Drop the read lock and aquire a write for insert/removal
50        let mut open_positions = position_manager.open_positions.write().unwrap();
51        /*
52        We are not going to remove the position from being looked up by the bonding curve address
53        in the event that we purchase a token, it migrates, we process the migration, and then the
54        tx confirmation comes in still on the bonding curve. We want to still be able to look it up
55        by market address.
56        */
57        open_positions.insert(*pool.pool_address(), position_arc.clone());
58        println!(
59          "POSITION: Position migrated from bonding curve {} to pumpswap pool {}",
60          token_address,
61          pool.pool_address()
62        );
63      }
64    }
65  }
66}