From de840f8dcc310787ebc44b5df5507ea846c74fdb Mon Sep 17 00:00:00 2001 From: Chaofan Shou Date: Mon, 20 Nov 2023 14:53:02 -0800 Subject: [PATCH 1/3] make token context a trait --- src/evm/onchain/endpoints.rs | 12 +- src/evm/onchain/flashloan.rs | 6 +- src/evm/oracles/erc20.rs | 33 +-- src/evm/uniswap/mod.rs | 505 ++++++++++++++++++----------------- src/evm/vm.rs | 113 +++++--- 5 files changed, 363 insertions(+), 306 deletions(-) diff --git a/src/evm/onchain/endpoints.rs b/src/evm/onchain/endpoints.rs index 275df75b3..584b04616 100644 --- a/src/evm/onchain/endpoints.rs +++ b/src/evm/onchain/endpoints.rs @@ -23,7 +23,7 @@ use crate::{ cache::{Cache, FileSystemCache}, evm::{ types::{EVMAddress, EVMU256}, - uniswap::{get_uniswap_info, PairContext, PathContext, TokenContext, UniswapProvider}, + uniswap::{get_uniswap_info, PairContext, PathContext, UniswapTokenContext, UniswapProvider}, }, }; @@ -248,7 +248,7 @@ pub struct OnChainConfig { price_cache: HashMap>, abi_cache: HashMap>, storage_dump_cache: HashMap>>>, - uniswap_path_cache: HashMap, + uniswap_path_cache: HashMap, rpc_cache: FileSystemCache, } @@ -708,14 +708,14 @@ impl OnChainConfig { slot_value } - pub fn fetch_uniswap_path(&mut self, network: &str, token_address: EVMAddress) -> TokenContext { + pub fn fetch_uniswap_path(&mut self, network: &str, token_address: EVMAddress) -> UniswapTokenContext { let token = format!("{:?}", token_address); let info: Info = self.find_path_subgraph(network, &token); let basic_info = info.basic_info; if basic_info.weth.is_empty() { warn!("failed to find weth address"); - return TokenContext::default(); + return UniswapTokenContext::default(); } let weth = EVMAddress::from_str(&basic_info.weth).unwrap(); let is_weth = basic_info.is_weth; @@ -781,7 +781,7 @@ impl OnChainConfig { }) .collect(); - TokenContext { + UniswapTokenContext { swaps: paths_parsed, is_weth, weth_address: weth, @@ -789,7 +789,7 @@ impl OnChainConfig { } } - pub fn fetch_uniswap_path_cached(&mut self, token: EVMAddress) -> &TokenContext { + pub fn fetch_uniswap_path_cached(&mut self, token: EVMAddress) -> &UniswapTokenContext { if self.uniswap_path_cache.contains_key(&token) { return self.uniswap_path_cache.get(&token).unwrap(); } diff --git a/src/evm/onchain/flashloan.rs b/src/evm/onchain/flashloan.rs index 2ee03e5c2..f10d4ad8d 100644 --- a/src/evm/onchain/flashloan.rs +++ b/src/evm/onchain/flashloan.rs @@ -28,7 +28,7 @@ use revm_interpreter::Interpreter; use serde::{Deserialize, Serialize}; use tracing::debug; -use crate::evm::{types::EVMFuzzState, uniswap::TokenContext}; +use crate::evm::{types::EVMFuzzState, uniswap::UniswapTokenContext}; // Some components are used when `flashloan_v2` feature is not enabled #[allow(unused_imports)] use crate::{ @@ -166,7 +166,7 @@ impl Flashloan { .map(|price| Self::calculate_usd_value(price, amount)) } - fn get_token_context(&mut self, addr: EVMAddress) -> Option { + fn get_token_context(&mut self, addr: EVMAddress) -> Option { self.endpoint .as_mut() .map(|endpoint| endpoint.fetch_uniswap_path_cached(addr).clone()) @@ -205,7 +205,7 @@ impl Flashloan { let oracle = self.flashloan_oracle.deref().try_borrow_mut(); // avoid delegate call on token -> make oracle borrow multiple times if oracle.is_ok() { - oracle.unwrap().register_token(*addr, token_ctx); + oracle.unwrap().register_token(*addr, Rc::new(RefCell::new(token_ctx))); self.erc20_address.insert(*addr); is_erc20 = true; } else { diff --git a/src/evm/oracles/erc20.rs b/src/evm/oracles/erc20.rs index ceee5643a..6741f5549 100644 --- a/src/evm/oracles/erc20.rs +++ b/src/evm/oracles/erc20.rs @@ -11,8 +11,7 @@ use crate::{ oracles::ERC20_BUG_IDX, producers::erc20::ERC20Producer, types::{EVMAddress, EVMFuzzState, EVMOracleCtx, EVMU256, EVMU512}, - uniswap::{generate_uniswap_router_sell, TokenContext}, - vm::EVMState, + vm::EVMState, uniswap::TokenContextT, }, oracle::Oracle, state::HasExecutionResult, @@ -20,7 +19,7 @@ use crate::{ pub struct IERC20OracleFlashloan { pub balance_of: Vec, - pub known_tokens: HashMap, + pub known_tokens: HashMap>>>, pub known_pair_reserve_slot: HashMap, pub erc20_producer: Rc>, } @@ -35,7 +34,7 @@ impl IERC20OracleFlashloan { } } - pub fn register_token(&mut self, token: EVMAddress, token_ctx: TokenContext) { + pub fn register_token(&mut self, token: EVMAddress, token_ctx: Rc>>) { self.known_tokens.insert(token, token_ctx); } @@ -79,27 +78,17 @@ impl let mut liquidation_txs = vec![]; for (caller, _token_info, _amount) in liquidations_earned { - // let txs = _token_info.borrow().sell( - // ctx.fuzz_state, - // _amount, - // ctx.fuzz_state.callers_pool[0], - // ctx.input.get_randomness().as_slice(), - // ); - - let txs = generate_uniswap_router_sell(_token_info, _path_idx, _amount, ctx.fuzz_state.callers_pool[0]); - if txs.is_none() { - continue; - } + let txs = _token_info.borrow().sell( + ctx.fuzz_state, + _amount, + ctx.fuzz_state.callers_pool[0], + ctx.input.get_randomness().as_slice(), + ); - // liquidation_txs.extend( - // txs.iter() - // .map(|(addr, abi, _)| (caller, *addr, Bytes::from(abi.get_bytes()))), - // ); liquidation_txs.extend( - txs.unwrap() - .iter() - .map(|(abi, _, addr)| (caller, *addr, Bytes::from(abi.get_bytes()))), + txs.iter() + .map(|(addr, abi, _)| (caller, *addr, Bytes::from(abi.get_bytes()))), ); } diff --git a/src/evm/uniswap/mod.rs b/src/evm/uniswap/mod.rs index 8a4aca773..51f3c4f3f 100644 --- a/src/evm/uniswap/mod.rs +++ b/src/evm/uniswap/mod.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, ops::Deref, rc::Rc, str::FromStr, sync::Arc}; +use std::{cell::RefCell, fmt::Debug, ops::Deref, rc::Rc, str::FromStr, sync::Arc}; use alloy_primitives::hex; @@ -7,7 +7,6 @@ use crate::evm::{ onchain::endpoints::Chain, types::{EVMAddress, EVMU256}, }; - #[derive(Clone, Debug)] pub enum UniswapProvider { PancakeSwap, @@ -16,7 +15,6 @@ pub enum UniswapProvider { UniswapV3, Biswap, } - impl FromStr for UniswapProvider { type Err = (); fn from_str(s: &str) -> Result { @@ -31,7 +29,6 @@ impl FromStr for UniswapProvider { } } } - #[derive(Clone, Debug, Default)] pub struct UniswapInfo { pub pool_fee: usize, @@ -40,7 +37,6 @@ pub struct UniswapInfo { pub init_code_hash: Vec, pub pair_bytecode: Vec, } - #[derive(Clone, Debug, Default)] pub struct PairContext { pub pair_address: EVMAddress, @@ -49,7 +45,6 @@ pub struct PairContext { pub uniswap_info: Arc, pub initial_reserves: (EVMU256, EVMU256), } - #[derive(Clone, Debug, Default)] pub struct PathContext { pub route: Vec>>, @@ -57,8 +52,26 @@ pub struct PathContext { pub final_pegged_pair: Rc>>, } +pub trait TokenContextT { + fn buy( + &self, + state: &mut S, + amount_in: EVMU256, + to: EVMAddress, + seed: &[u8], + ) -> Vec<(EVMAddress, BoxedABI, EVMU256)>; + + fn sell( + &self, + state: &mut S, + amount_in: EVMU256, + to: EVMAddress, + seed: &[u8], + ) -> Vec<(EVMAddress, BoxedABI, EVMU256)>; +} + #[derive(Clone, Debug, Default)] -pub struct TokenContext { +pub struct UniswapTokenContext { pub swaps: Vec, pub is_weth: bool, pub weth_address: EVMAddress, @@ -67,207 +80,210 @@ pub struct TokenContext { static mut WETH_MAX: EVMU256 = EVMU256::ZERO; -// swapExactETHForTokensSupportingFeeOnTransferTokens -pub fn generate_uniswap_router_buy( - token: &TokenContext, - path_idx: usize, - amount_in: EVMU256, - to: EVMAddress, -) -> Option<(BoxedABI, EVMU256, EVMAddress)> { - unsafe { - WETH_MAX = EVMU256::from(10).pow(EVMU256::from(24)); - } - // function swapExactETHForTokensSupportingFeeOnTransferTokens( - // uint amountOutMin, - // address[] calldata path, - // address to, - // uint deadline - // ) - if token.is_weth { - let mut abi = BoxedABI::new(Box::new(AEmpty {})); - abi.function = [0xd0, 0xe3, 0x0d, 0xb0]; // deposit - // EVMU256::from(perct) * unsafe {WETH_MAX} - Some((abi, amount_in, token.weth_address)) - } else { - if token.swaps.is_empty() { - return None; - } - let path_ctx = &token.swaps[path_idx % token.swaps.len()]; - // let amount_in = path_ctx.get_amount_in(perct, reserve); - let mut path: Vec = path_ctx - .route - .iter() - .rev() - .map(|pair| pair.deref().borrow().next_hop) - .collect(); - // when it is pegged token or weth - if path.is_empty() || path[0] != token.weth_address { - path.insert(0, token.weth_address); +impl TokenContextT for UniswapTokenContext { + fn buy( + &self, + _state: &mut S, + amount_in: EVMU256, + to: EVMAddress, + seed: &[u8], + ) -> Vec<(EVMAddress, BoxedABI, EVMU256)> { + unsafe { + WETH_MAX = EVMU256::from(10).pow(EVMU256::from(24)); } - path.insert(path.len(), token.address); - let mut abi = BoxedABI::new(Box::new(AArray { - data: vec![ - BoxedABI::new(Box::new(A256 { - data: vec![0; 32], - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })), - BoxedABI::new(Box::new(AArray { - data: path - .iter() - .map(|addr| { - BoxedABI::new(Box::new(A256 { - data: addr.as_bytes().to_vec(), - is_address: true, - dont_mutate: false, - inner_type: A256InnerType::Address, - })) - }) - .collect(), - dynamic_size: true, - })), - BoxedABI::new(Box::new(A256 { - data: to.0.to_vec(), - is_address: true, - dont_mutate: false, - inner_type: A256InnerType::Address, - })), - BoxedABI::new(Box::new(A256 { - data: vec![0xff; 32], - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })), - ], - dynamic_size: false, - })); - abi.function = [0xb6, 0xf9, 0xde, 0x95]; // swapExactETHForTokensSupportingFeeOnTransferTokens + // function swapExactETHForTokensSupportingFeeOnTransferTokens( + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) + if self.is_weth { + let mut abi = BoxedABI::new(Box::new(AEmpty {})); + abi.function = [0xd0, 0xe3, 0x0d, 0xb0]; // deposit + // EVMU256::from(perct) * unsafe {WETH_MAX} + vec![(self.weth_address, abi, amount_in)] + } else { + if self.swaps.is_empty() { + return vec![]; + } + let path_ctx = &self.swaps[seed[0] as usize % self.swaps.len()]; + // let amount_in = path_ctx.get_amount_in(perct, reserve); + let mut path: Vec = path_ctx + .route + .iter() + .rev() + .map(|pair| pair.deref().borrow().next_hop) + .collect(); + // when it is pegged token or weth + if path.is_empty() || path[0] != self.weth_address { + path.insert(0, self.weth_address); + } + path.insert(path.len(), self.address); + let mut abi = BoxedABI::new(Box::new(AArray { + data: vec![ + BoxedABI::new(Box::new(A256 { + data: vec![0; 32], + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, + })), + BoxedABI::new(Box::new(AArray { + data: path + .iter() + .map(|addr| { + BoxedABI::new(Box::new(A256 { + data: addr.as_bytes().to_vec(), + is_address: true, + dont_mutate: false, + inner_type: A256InnerType::Address, + })) + }) + .collect(), + dynamic_size: true, + })), + BoxedABI::new(Box::new(A256 { + data: to.0.to_vec(), + is_address: true, + dont_mutate: false, + inner_type: A256InnerType::Address, + })), + BoxedABI::new(Box::new(A256 { + data: vec![0xff; 32], + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, + })), + ], + dynamic_size: false, + })); + abi.function = [0xb6, 0xf9, 0xde, 0x95]; // swapExactETHForTokensSupportingFeeOnTransferTokens - match path_ctx.final_pegged_pair.deref().borrow().as_ref() { - None => Some(( - abi, - amount_in, - path_ctx.route.last().unwrap().deref().borrow().uniswap_info.router, - )), - Some(info) => Some((abi, amount_in, info.uniswap_info.router)), + match path_ctx.final_pegged_pair.deref().borrow().as_ref() { + None => vec![( + path_ctx.route.last().unwrap().deref().borrow().uniswap_info.router, + abi, + amount_in, + )], + Some(info) => vec![(info.uniswap_info.router, abi, amount_in)], + } } } -} -// swapExactTokensForETHSupportingFeeOnTransferTokens -pub fn generate_uniswap_router_sell( - token: &TokenContext, - path_idx: usize, - amount_in: EVMU256, - to: EVMAddress, -) -> Option> { - unsafe { - WETH_MAX = EVMU256::from(10).pow(EVMU256::from(24)); - } - // function swapExactTokensForETHSupportingFeeOnTransferTokens( - // uint amountIn, - // uint amountOutMin, - // address[] calldata path, - // address to, - // uint deadline - // ) - let amount: [u8; 32] = amount_in.to_be_bytes(); - let mut abi_amount = BoxedABI::new(Box::new(A256 { - data: amount.to_vec(), - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })); - - if token.is_weth { - abi_amount.function = [0x2e, 0x1a, 0x7d, 0x4d]; // withdraw - Some(vec![(abi_amount, EVMU256::ZERO, token.weth_address)]) - } else { - if token.swaps.is_empty() { - return None; - } - let path_ctx = &token.swaps[path_idx % token.swaps.len()]; - // let amount_in = path_ctx.get_amount_in(perct, reserve); - let mut path: Vec = path_ctx - .route - .iter() - .map(|pair| pair.deref().borrow().next_hop) - .collect(); - // when it is pegged token or weth - if path.is_empty() || *path.last().unwrap() != token.weth_address { - path.push(token.weth_address); + // swapExactTokensForETHSupportingFeeOnTransferTokens + fn sell( + &self, + _state: &mut S, + amount_in: EVMU256, + to: EVMAddress, + seed: &[u8], + ) -> Vec<(EVMAddress, BoxedABI, EVMU256)> { + unsafe { + WETH_MAX = EVMU256::from(10).pow(EVMU256::from(24)); } - path.insert(0, token.address); - let mut sell_abi = BoxedABI::new(Box::new(AArray { - data: vec![ - abi_amount, - BoxedABI::new(Box::new(A256 { - data: vec![0; 32], - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })), - BoxedABI::new(Box::new(AArray { - data: path - .iter() - .map(|addr| { - BoxedABI::new(Box::new(A256 { - data: addr.as_bytes().to_vec(), - is_address: true, - dont_mutate: false, - inner_type: A256InnerType::Address, - })) - }) - .collect(), - dynamic_size: true, - })), - BoxedABI::new(Box::new(A256 { - data: to.0.to_vec(), - is_address: true, - dont_mutate: false, - inner_type: A256InnerType::Address, - })), - BoxedABI::new(Box::new(A256 { - data: vec![0xff; 32], - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })), - ], - dynamic_size: false, + // function swapExactTokensForETHSupportingFeeOnTransferTokens( + // uint amountIn, + // uint amountOutMin, + // address[] calldata path, + // address to, + // uint deadline + // ) + let amount: [u8; 32] = amount_in.to_be_bytes(); + let mut abi_amount = BoxedABI::new(Box::new(A256 { + data: amount.to_vec(), + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, })); - sell_abi.function = [0x79, 0x1a, 0xc9, 0x47]; // swapExactTokensForETHSupportingFeeOnTransferTokens - let router = match path_ctx.final_pegged_pair.deref().borrow().as_ref() { - None => path_ctx.route.last().unwrap().deref().borrow().uniswap_info.router, - Some(info) => info.uniswap_info.router, - }; + if self.is_weth { + abi_amount.function = [0x2e, 0x1a, 0x7d, 0x4d]; // withdraw + vec![(self.weth_address, abi_amount, EVMU256::ZERO)] + } else { + if self.swaps.is_empty() { + return vec![]; + } + let path_ctx = &self.swaps[seed[0] as usize % self.swaps.len()]; + // let amount_in = path_ctx.get_amount_in(perct, reserve); + let mut path: Vec = path_ctx + .route + .iter() + .map(|pair| pair.deref().borrow().next_hop) + .collect(); + // when it is pegged token or weth + if path.is_empty() || *path.last().unwrap() != self.weth_address { + path.push(self.weth_address); + } + path.insert(0, self.address); + let mut sell_abi = BoxedABI::new(Box::new(AArray { + data: vec![ + abi_amount, + BoxedABI::new(Box::new(A256 { + data: vec![0; 32], + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, + })), + BoxedABI::new(Box::new(AArray { + data: path + .iter() + .map(|addr| { + BoxedABI::new(Box::new(A256 { + data: addr.as_bytes().to_vec(), + is_address: true, + dont_mutate: false, + inner_type: A256InnerType::Address, + })) + }) + .collect(), + dynamic_size: true, + })), + BoxedABI::new(Box::new(A256 { + data: to.0.to_vec(), + is_address: true, + dont_mutate: false, + inner_type: A256InnerType::Address, + })), + BoxedABI::new(Box::new(A256 { + data: vec![0xff; 32], + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, + })), + ], + dynamic_size: false, + })); + sell_abi.function = [0x79, 0x1a, 0xc9, 0x47]; // swapExactTokensForETHSupportingFeeOnTransferTokens - let mut approve_abi = BoxedABI::new(Box::new(AArray { - data: vec![ - BoxedABI::new(Box::new(A256 { - data: router.0.to_vec(), - is_address: true, - dont_mutate: false, - inner_type: A256InnerType::Address, - })), - BoxedABI::new(Box::new(A256 { - data: vec![0xff; 32], - is_address: false, - dont_mutate: false, - inner_type: A256InnerType::Uint, - })), - ], - dynamic_size: false, - })); + let router = match path_ctx.final_pegged_pair.deref().borrow().as_ref() { + None => path_ctx.route.last().unwrap().deref().borrow().uniswap_info.router, + Some(info) => info.uniswap_info.router, + }; + + let mut approve_abi = BoxedABI::new(Box::new(AArray { + data: vec![ + BoxedABI::new(Box::new(A256 { + data: router.0.to_vec(), + is_address: true, + dont_mutate: false, + inner_type: A256InnerType::Address, + })), + BoxedABI::new(Box::new(A256 { + data: vec![0xff; 32], + is_address: false, + dont_mutate: false, + inner_type: A256InnerType::Uint, + })), + ], + dynamic_size: false, + })); - approve_abi.function = [0x09, 0x5e, 0xa7, 0xb3]; // approve + approve_abi.function = [0x09, 0x5e, 0xa7, 0xb3]; // approve - Some(vec![ - (approve_abi, EVMU256::ZERO, token.address), - (sell_abi, EVMU256::ZERO, router), - ]) + vec![ + (self.address, approve_abi, EVMU256::ZERO), + (router, sell_abi, EVMU256::ZERO), + ] + } } } @@ -297,56 +313,61 @@ pub fn get_uniswap_info(provider: &UniswapProvider, chain: &Chain) -> UniswapInf _ => panic!("Uniswap provider {:?} @ chain {:?} not supported", provider, chain), } } - pub const BSC_PANCAKEV2_PAIR_BYTECODE: &str = include_str!("bsc_pancakeV2_pair.bin"); pub const ETH_UNISWAPV2_PAIR_BYTECODE: &str = include_str!("eth_uniswapV2_pair.bin"); -#[cfg(test)] -mod tests { - use std::str::FromStr; +// #[cfg(test)] +// mod tests { +// use std::str::FromStr; - use tracing::debug; +// use tracing::debug; - use super::*; - use crate::evm::onchain::endpoints::Chain; +// use super::*; +// use crate::evm::onchain::endpoints::Chain; - macro_rules! wrap { - ($x: expr) => { - Rc::new(RefCell::new($x)) - }; - } +// macro_rules! wrap { +// ($x: expr) => { +// Rc::new(RefCell::new($x)) +// }; +// } - #[test] - fn test_uniswap_sell() { - let t1 = TokenContext { - swaps: vec![PathContext { - route: vec![wrap!(PairContext { - pair_address: EVMAddress::from_str("0x0000000000000000000000000000000000000000").unwrap(), - side: 0, - uniswap_info: Arc::new(get_uniswap_info(&UniswapProvider::PancakeSwap, &Chain::BSC)), - initial_reserves: (Default::default(), Default::default()), - next_hop: EVMAddress::from_str("0x1100000000000000000000000000000000000000").unwrap(), - })], - final_pegged_ratio: EVMU256::from(1), - final_pegged_pair: Rc::new(RefCell::new(None)), - }], - is_weth: false, - weth_address: EVMAddress::from_str("0xee00000000000000000000000000000000000000").unwrap(), - address: EVMAddress::from_str("0xff00000000000000000000000000000000000000").unwrap(), - }; +// #[test] +// fn test_uniswap_sell() { +// let t1 = TokenContext { +// swaps: vec![PathContext { +// route: vec![wrap!(PairContext { +// pair_address: +// EVMAddress::from_str("0x0000000000000000000000000000000000000000").unwrap(), +// side: 0, +// uniswap_info: +// Arc::new(get_uniswap_info(&UniswapProvider::PancakeSwap, &Chain::BSC)), +// initial_reserves: (Default::default(), +// Default::default()), next_hop: +// EVMAddress::from_str("0x1100000000000000000000000000000000000000").unwrap(), +// })], +// final_pegged_ratio: EVMU256::from(1), +// final_pegged_pair: Rc::new(RefCell::new(None)), +// }], +// is_weth: false, +// weth_address: +// EVMAddress::from_str("0xee00000000000000000000000000000000000000").unwrap(), +// address: +// EVMAddress::from_str("0xff00000000000000000000000000000000000000").unwrap(), +// }; - let plan = generate_uniswap_router_sell( - &t1, - 0, - EVMU256::from(10000), - EVMAddress::from_str("0x2300000000000000000000000000000000000000").unwrap(), - ); - debug!( - "plan: {:?}", - plan.unwrap() - .iter() - .map(|x| hex::encode(x.0.get_bytes())) - .collect::>() - ); - } -} +// let plan = generate_uniswap_router_sell( +// &t1, +// 0, +// EVMU256::from(10000), +// +// EVMAddress::from_str("0x2300000000000000000000000000000000000000").unwrap(), +// ); +// debug!( +// "plan: {:?}", +// plan.unwrap() +// .iter() +// .map(|x| hex::encode(x.0.get_bytes())) +// .collect::>() +// ); +// } +// } \ No newline at end of file diff --git a/src/evm/vm.rs b/src/evm/vm.rs index e32719dcf..bdfdcb9ed 100644 --- a/src/evm/vm.rs +++ b/src/evm/vm.rs @@ -33,7 +33,6 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tracing::{debug, error}; use super::{input::EVMInput, middlewares::reentrancy::ReentrancyData, types::EVMFuzzState}; -use crate::evm::uniswap::generate_uniswap_router_buy; // Some components are used when `flashloan_v2` feature is disabled #[allow(unused_imports)] use crate::{ @@ -992,43 +991,52 @@ where // buy (borrow because we have infinite ETH) tokens with ETH using uniswap EVMInputTy::Borrow => { let token = input.get_contract(); + let token_ctx = { + let flashloan_mid = self.host.flashloan_middleware.as_ref().unwrap().deref().borrow(); + let flashloan_oracle = flashloan_mid.flashloan_oracle.deref().borrow(); + flashloan_oracle + .known_tokens + .get(&token) + .unwrap_or_else(|| panic!("unknown token : {:?}", token)) + .clone() + }; - let path_idx = input.get_randomness()[0] as usize; - // generate the call to uniswap router for buying tokens using ETH - let call_info = generate_uniswap_router_buy( - get_token_ctx!(self.host.flashloan_middleware.as_ref().unwrap().deref().borrow(), token), - path_idx, + let calldata = token_ctx.borrow().buy( + state, input.get_txn_value().unwrap(), input.get_caller(), + input.get_randomness().as_slice(), ); - match call_info { - Some((abi, value, target)) => { - let bys = abi.get_bytes(); - let mut res = self.fast_call( - target, - Bytes::from(bys), - input.get_state(), - state, - value, - input.get_caller(), - ); - if let Some(ref m) = self.host.flashloan_middleware { - m.deref() - .borrow_mut() - .analyze_call(input, &mut res.new_state.flashloan_data) - } - unsafe { - ExecutionResult { - output: res.output.to_vec(), - reverted: !is_call_success!(res.ret), - new_state: StagedVMState::new_with_state( - VMStateT::as_any(&res.new_state).downcast_ref_unchecked::().clone(), - ), - additional_info: None, - } + if !calldata.is_empty() { + assert_eq!(calldata.len(), 1); + let (target, abi, value) = &calldata[0]; + let bys = abi.get_bytes(); + let mut res = self.fast_call( + *target, + Bytes::from(bys), + input.get_state(), + state, + *value, + input.get_caller(), + ); + if let Some(ref m) = self.host.flashloan_middleware { + m.deref() + .borrow_mut() + .analyze_call(input, &mut res.new_state.flashloan_data) + } + unsafe { + ExecutionResult { + output: res.output.to_vec(), + reverted: !is_call_success!(res.ret), + new_state: StagedVMState::new_with_state( + VMStateT::as_any(&res.new_state).downcast_ref_unchecked::().clone(), + ), + additional_info: None, } } - None => ExecutionResult { + + } else { + ExecutionResult { // we don't have enough liquidity to buy the token output: vec![], reverted: false, @@ -1038,8 +1046,47 @@ where .clone() }), additional_info: None, - }, + } } + // match call_info { + // Some((abi, value, target)) => { + // let bys = abi.get_bytes(); + // let mut res = self.fast_call( + // target, + // Bytes::from(bys), + // input.get_state(), + // state, + // value, + // input.get_caller(), + // ); + // if let Some(ref m) = self.host.flashloan_middleware { + // m.deref() + // .borrow_mut() + // .analyze_call(input, &mut res.new_state.flashloan_data) + // } + // unsafe { + // ExecutionResult { + // output: res.output.to_vec(), + // reverted: !is_call_success!(res.ret), + // new_state: StagedVMState::new_with_state( + // VMStateT::as_any(&res.new_state).downcast_ref_unchecked::().clone(), + // ), + // additional_info: None, + // } + // } + // } + // None => ExecutionResult { + // // we don't have enough liquidity to buy the token + // output: vec![], + // reverted: false, + // new_state: StagedVMState::new_with_state(unsafe { + // VMStateT::as_any(input.get_state()) + // .downcast_ref_unchecked::() + // .clone() + // }), + // additional_info: None, + // }, + // } } EVMInputTy::Liquidate => { unreachable!("liquidate should be handled by middleware"); From 3ee339d49d823079343a3223a158a3c62474cd01 Mon Sep 17 00:00:00 2001 From: Chaofan Shou Date: Mon, 20 Nov 2023 14:53:12 -0800 Subject: [PATCH 2/3] fmt --- src/evm/onchain/endpoints.rs | 2 +- src/evm/oracles/erc20.rs | 4 ++-- src/evm/uniswap/mod.rs | 2 +- src/evm/vm.rs | 9 +++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/evm/onchain/endpoints.rs b/src/evm/onchain/endpoints.rs index 584b04616..baef66a22 100644 --- a/src/evm/onchain/endpoints.rs +++ b/src/evm/onchain/endpoints.rs @@ -23,7 +23,7 @@ use crate::{ cache::{Cache, FileSystemCache}, evm::{ types::{EVMAddress, EVMU256}, - uniswap::{get_uniswap_info, PairContext, PathContext, UniswapTokenContext, UniswapProvider}, + uniswap::{get_uniswap_info, PairContext, PathContext, UniswapProvider, UniswapTokenContext}, }, }; diff --git a/src/evm/oracles/erc20.rs b/src/evm/oracles/erc20.rs index 6741f5549..a851410a6 100644 --- a/src/evm/oracles/erc20.rs +++ b/src/evm/oracles/erc20.rs @@ -11,7 +11,8 @@ use crate::{ oracles::ERC20_BUG_IDX, producers::erc20::ERC20Producer, types::{EVMAddress, EVMFuzzState, EVMOracleCtx, EVMU256, EVMU512}, - vm::EVMState, uniswap::TokenContextT, + uniswap::TokenContextT, + vm::EVMState, }, oracle::Oracle, state::HasExecutionResult, @@ -85,7 +86,6 @@ impl ctx.input.get_randomness().as_slice(), ); - liquidation_txs.extend( txs.iter() .map(|(addr, abi, _)| (caller, *addr, Bytes::from(abi.get_bytes()))), diff --git a/src/evm/uniswap/mod.rs b/src/evm/uniswap/mod.rs index 51f3c4f3f..ede40ada4 100644 --- a/src/evm/uniswap/mod.rs +++ b/src/evm/uniswap/mod.rs @@ -370,4 +370,4 @@ pub const ETH_UNISWAPV2_PAIR_BYTECODE: &str = include_str!("eth_uniswapV2_pair.b // .collect::>() // ); // } -// } \ No newline at end of file +// } diff --git a/src/evm/vm.rs b/src/evm/vm.rs index bdfdcb9ed..045db02cc 100644 --- a/src/evm/vm.rs +++ b/src/evm/vm.rs @@ -1034,7 +1034,6 @@ where additional_info: None, } } - } else { ExecutionResult { // we don't have enough liquidity to buy the token @@ -1062,14 +1061,16 @@ where // if let Some(ref m) = self.host.flashloan_middleware { // m.deref() // .borrow_mut() - // .analyze_call(input, &mut res.new_state.flashloan_data) - // } + // .analyze_call(input, &mut + // res.new_state.flashloan_data) } // unsafe { // ExecutionResult { // output: res.output.to_vec(), // reverted: !is_call_success!(res.ret), // new_state: StagedVMState::new_with_state( - // VMStateT::as_any(&res.new_state).downcast_ref_unchecked::().clone(), + // + // VMStateT::as_any(&res.new_state). + // downcast_ref_unchecked::().clone(), // ), // additional_info: None, // } From 554e1713cb655176eb9ebac44608ca7a3022281e Mon Sep 17 00:00:00 2001 From: Chaofan Shou Date: Mon, 20 Nov 2023 14:59:41 -0800 Subject: [PATCH 3/3] fmt --- src/evm/vm.rs | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/src/evm/vm.rs b/src/evm/vm.rs index 045db02cc..0d93aa0ed 100644 --- a/src/evm/vm.rs +++ b/src/evm/vm.rs @@ -1047,47 +1047,6 @@ where additional_info: None, } } - // match call_info { - // Some((abi, value, target)) => { - // let bys = abi.get_bytes(); - // let mut res = self.fast_call( - // target, - // Bytes::from(bys), - // input.get_state(), - // state, - // value, - // input.get_caller(), - // ); - // if let Some(ref m) = self.host.flashloan_middleware { - // m.deref() - // .borrow_mut() - // .analyze_call(input, &mut - // res.new_state.flashloan_data) } - // unsafe { - // ExecutionResult { - // output: res.output.to_vec(), - // reverted: !is_call_success!(res.ret), - // new_state: StagedVMState::new_with_state( - // - // VMStateT::as_any(&res.new_state). - // downcast_ref_unchecked::().clone(), - // ), - // additional_info: None, - // } - // } - // } - // None => ExecutionResult { - // // we don't have enough liquidity to buy the token - // output: vec![], - // reverted: false, - // new_state: StagedVMState::new_with_state(unsafe { - // VMStateT::as_any(input.get_state()) - // .downcast_ref_unchecked::() - // .clone() - // }), - // additional_info: None, - // }, - // } } EVMInputTy::Liquidate => { unreachable!("liquidate should be handled by middleware");