loom_strategy_backrun/affected_pools_code.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
use alloy_eips::BlockNumberOrTag;
use alloy_network::Network;
use alloy_primitives::Address;
use alloy_provider::Provider;
use alloy_transport::Transport;
use eyre::eyre;
use revm::primitives::Env;
use std::collections::BTreeMap;
use std::sync::Arc;
use tracing::{debug, error};
use loom_core_actors::SharedState;
use loom_defi_pools::protocols::{UniswapV2Protocol, UniswapV3Protocol};
use loom_defi_pools::state_readers::UniswapV3StateReader;
use loom_defi_pools::{MaverickPool, PancakeV3Pool, UniswapV2Pool, UniswapV3Pool};
use loom_evm_db::{AlloyDB, LoomDB};
use loom_types_blockchain::GethStateUpdateVec;
use loom_types_entities::{get_protocol_by_factory, Market, MarketState, Pool, PoolProtocol, PoolWrapper};
pub async fn get_affected_pools_from_code<P, T, N>(
client: P,
market: SharedState<Market>,
state_update: &GethStateUpdateVec,
) -> eyre::Result<BTreeMap<PoolWrapper, Vec<(Address, Address)>>>
where
T: Transport + Clone,
N: Network,
P: Provider<T, N> + Send + Sync + Clone + 'static,
{
let mut market_state = MarketState::new(LoomDB::new());
market_state.state_db.apply_geth_state_update(state_update, true, false);
let mut ret: BTreeMap<PoolWrapper, Vec<(Address, Address)>> = BTreeMap::new();
for state_update_record in state_update.iter() {
for (address, state_update_entry) in state_update_record.iter() {
if let Some(code) = &state_update_entry.code {
if UniswapV2Protocol::is_code(code) {
match market.read().await.get_pool(address) {
None => {
debug!(?address, "Loading UniswapV2 class pool");
let env = Env::default();
let ext_db = AlloyDB::new(client.clone(), BlockNumberOrTag::Latest.into());
let Some(ext_db) = ext_db else {
error!("Cannot create AlloyDB");
continue;
};
let state_db = market_state.state_db.clone().with_ext_db(ext_db);
match UniswapV3StateReader::factory(&state_db, env.clone(), *address) {
Ok(_factory_address) => match UniswapV2Pool::fetch_pool_data_evm(&state_db, env.clone(), *address) {
Ok(pool) => {
let pool = PoolWrapper::new(Arc::new(pool));
let protocol = pool.get_protocol();
let swap_directions = pool.get_swap_directions();
debug!(%address, %protocol, ?swap_directions, "UniswapV2 pool loaded");
ret.insert(pool, swap_directions);
}
Err(err) => {
error!(?address, %err, "Error loading UniswapV2 pool");
}
},
Err(err) => {
error!(?address, %err, "Error loading UniswapV2 factory for pool")
}
}
}
Some(pool) => {
debug!(?address, protocol = ?pool.get_protocol(), "Pool already exists");
}
}
}
if UniswapV3Protocol::is_code(code) {
match market.read().await.get_pool(address) {
None => {
debug!(%address, "Loading UniswapV3 class pool");
let env = Env::default();
let ext_db = AlloyDB::new(client.clone(), BlockNumberOrTag::Latest.into());
let Some(ext_db) = ext_db else {
error!("Cannot create AlloyDB");
continue;
};
let state_db = market_state.state_db.clone().with_ext_db(ext_db);
match UniswapV3StateReader::factory(&state_db, env.clone(), *address) {
Ok(factory_address) => {
match get_protocol_by_factory(factory_address) {
PoolProtocol::PancakeV3 => {
let pool = PancakeV3Pool::fetch_pool_data_evm(&state_db, env.clone(), *address);
match pool {
Ok(pool) => {
let swap_directions = pool.get_swap_directions();
let protocol = pool.get_protocol();
debug!(?address, %protocol, ?swap_directions, "PancakeV3 Pool loaded");
ret.insert(PoolWrapper::new(Arc::new(pool)), swap_directions);
}
Err(err) => {
error!(?address, %err, "Error loading PancakeV3 pool");
}
}
}
PoolProtocol::Maverick => {
let pool = MaverickPool::fetch_pool_data_evm(&state_db, env.clone(), *address);
match pool {
Ok(pool) => {
let pool = PoolWrapper::new(Arc::new(pool));
let swap_directions = pool.get_swap_directions();
let protocol = pool.get_protocol();
debug!(?address, %protocol, ?swap_directions, "Maverick Pool loaded");
ret.insert(pool, swap_directions);
}
Err(err) => {
error!(?address, %err, "Error loading Maverick pool");
}
}
}
_ => match UniswapV3Pool::fetch_pool_data_evm(&state_db, env.clone(), *address) {
Ok(pool) => {
let pool = PoolWrapper::new(Arc::new(pool));
let swap_directions = pool.get_swap_directions();
let protocol = pool.get_protocol();
debug!(
%address,
%protocol,
?swap_directions,
"UniswapV3 Pool loaded"
);
ret.insert(pool, swap_directions);
}
Err(err) => {
error!(%address, %err, "Error loading UniswapV3 pool");
}
},
};
}
Err(err) => {
error!(?address, %err, "Error loading UniswapV3 factory for pool")
}
}
}
Some(pool) => {
debug!(?address, protocol = ?pool.get_protocol(), "Pool already exists")
}
}
}
}
}
}
if !ret.is_empty() {
Ok(ret)
} else {
Err(eyre!("NO_POOLS_LOADED"))
}
}
/// Check if the state update code contains code for a UniswapV2 pair or UniswapV3 pool by looking for method signatures.
pub fn is_pool_code(state_update: &GethStateUpdateVec) -> bool {
for state_update_record in state_update.iter() {
for (_address, state_update_entry) in state_update_record.iter() {
if let Some(code) = &state_update_entry.code {
if UniswapV3Protocol::is_code(code) {
return true;
}
if UniswapV2Protocol::is_code(code) {
return true;
}
}
}
}
false
}