Skip to content
Merged

Ipc #49

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ BOT_PRIVATE_KEY=

# rpc
BLOXROUTE_AUTH_HEADER=
WSS_RPC_URL_FOURMEME=
WSS_RPC_URL_PANCAKE=
HTTP_RPC_URL=
HTTP_SEND_TX_URL=
IPC_URL=

# tg bot
TELEGRAM_BOT_TOKEN=
Expand Down
33 changes: 5 additions & 28 deletions src/pvp/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,8 @@ pub struct EnvConfig {
pub log_level: LogLevel,

// -------- rpc config
/// The WebSocket RPC URL
pub wss_rpc_url_fourmeme: String,
pub wss_rpc_url_pancake: String,
/// The HTTP RPC URL
pub http_rpc_url: String,
/// The HTTP send tx URL: used to prevent rate limiting
pub http_send_tx_url: String,
/// The IPC URL
pub ipc_url: String,
/// The bloXroute auth header
pub bloxroute_auth_header: String,

Expand Down Expand Up @@ -131,10 +126,7 @@ impl Default for EnvConfig {
tx_simulation: true,

// -------- rpc config
wss_rpc_url_fourmeme: env::var("WSS_RPC_URL_FOURMEME").expect("WSS_RPC_URL_FOURMEME not set"),
wss_rpc_url_pancake: env::var("WSS_RPC_URL_PANCAKE").expect("WSS_RPC_URL_PANCAKE not set"),
http_rpc_url: env::var("HTTP_RPC_URL").expect("HTTP_RPC_URL not set"),
http_send_tx_url: env::var("HTTP_SEND_TX_URL").expect("HTTP_SEND_TX_URL not set"),
ipc_url: env::var("IPC_URL").expect("IPC_URL not set"),
bloxroute_auth_header: env::var("BLOXROUTE_AUTH_HEADER").expect("BLOXROUTE_AUTH_HEADER not set"),

// -------- database config
Expand Down Expand Up @@ -265,23 +257,8 @@ impl EnvConfig {
self
}

pub fn with_wss_rpc_url_fourmeme(mut self, url: String) -> Self {
self.wss_rpc_url_fourmeme = url;
self
}

pub fn with_wss_rpc_url_pancake(mut self, url: String) -> Self {
self.wss_rpc_url_pancake = url;
self
}

pub fn with_http_rpc_url(mut self, url: String) -> Self {
self.http_rpc_url = url;
self
}

pub fn with_http_send_tx_url(mut self, url: String) -> Self {
self.http_send_tx_url = url;
pub fn with_ipc_url(mut self, url: String) -> Self {
self.ipc_url = url;
self
}

Expand Down
1 change: 0 additions & 1 deletion src/pvp/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ pub mod db;
pub mod inner_pool_trader;
pub mod oracle;
pub mod outer_pool_trader;
pub mod sheet;

pub use inner_pool_trader::IInnerPoolTrader;
pub use oracle::IOracle;
Expand Down
9 changes: 0 additions & 9 deletions src/pvp/interface/sheet.rs

This file was deleted.

6 changes: 4 additions & 2 deletions src/pvp/service/auto_sell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//!
//! Known issues: When checking latest_trade_info, there is a competitive relationship between auto_sell and strategy_pancake
//! modules, so the same token may be sold continuously in one minute.
//!
//! This is optional. If you have an own node, you can remove this service.

use std::{marker::PhantomData, str::FromStr, sync::Arc, time::Duration};

Expand All @@ -30,7 +32,7 @@ use crate::pvp::{
},
strategy::helper::{
StrategyType, get_diff_time_since_migration, get_initial_fourmeme_buy_amount, get_pair_wbnb_balance,
get_wbnb_amount_when_bought_token,
get_pair_wbnb_balance_when_bought_token,
},
trade::outer_pool_trader::OuterPoolTrader,
};
Expand Down Expand Up @@ -144,7 +146,7 @@ where
current_pair_wbnb_balance: U256,
strategy: &str,
) -> Result<(), CustomError> {
let wbnb_amount_when_bought = get_wbnb_amount_when_bought_token(&*self.db, meme_token)
let wbnb_amount_when_bought = get_pair_wbnb_balance_when_bought_token(&*self.db, meme_token)
.await
.unwrap_or_default();

Expand Down
86 changes: 22 additions & 64 deletions src/pvp/start.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloy::{
eips::BlockNumberOrTag,
primitives::{Address, U256},
providers::{Provider, ProviderBuilder, WsConnect},
providers::{IpcConnect, Provider, ProviderBuilder},
rpc::types::Filter,
signers::local::PrivateKeySigner,
sol_types::SolEvent,
Expand Down Expand Up @@ -30,7 +30,7 @@ use crate::pvp::{
logger::Logger,
nonce::NonceManager,
},
service::{auto_sell::AutoSeller, db_cleaner::start_db_cleaner},
service::db_cleaner::start_db_cleaner,
strategy::strategy::{Event, Strategy},
trade::{TxSubmitType, inner_pool_trader::InnerPoolTrader, outer_pool_trader::OuterPoolTrader},
};
Expand Down Expand Up @@ -114,16 +114,7 @@ fn print_config(env_config: &EnvConfig) {
("TX Simulation".to_string(), env_config.tx_simulation.to_string()),
("Log Level".to_string(), format!("{:?}", env_config.log_level)),
// -------- rpc config
(
"WSS RPC URL Fourmeme".to_string(),
env_config.wss_rpc_url_fourmeme.clone(),
),
(
"WSS RPC URL PancakeSwap".to_string(),
env_config.wss_rpc_url_pancake.clone(),
),
("HTTP RPC URL".to_string(), env_config.http_rpc_url.clone()),
("HTTP Send TX URL".to_string(), env_config.http_send_tx_url.clone()),
("IPC URL".to_string(), env_config.ipc_url.clone()),
// -------- database config
("DB Path".to_string(), env_config.db_path.clone()),
]),
Expand Down Expand Up @@ -213,50 +204,33 @@ pub async fn run() -> eyre::Result<()> {

// 3. Setup signer
let signer: PrivateKeySigner = env_config.bot_private_key.parse()?;

// 4. Setup providers
let wallet = alloy::network::EthereumWallet::from(signer.clone());
let wss_provider_fourmeme = ProviderBuilder::new()
.wallet(wallet.clone())
.connect_ws(WsConnect::new(&env_config.wss_rpc_url_fourmeme))
.await?;
let wss_provider_pancake = ProviderBuilder::new()
.wallet(wallet.clone())
.connect_ws(WsConnect::new(&env_config.wss_rpc_url_pancake))
.await?;

let http_provider = ProviderBuilder::new()
.wallet(wallet.clone())
.connect_http(env_config.http_rpc_url.parse()?);
let http_send_tx_provider = ProviderBuilder::new()
.wallet(wallet)
.connect_http(env_config.http_send_tx_url.parse()?);
// 4. Setup provider
let ipc = IpcConnect::new(env_config.ipc_url.clone());
let ipc_provider = ProviderBuilder::new().wallet(wallet.clone()).connect_ipc(ipc).await?;

// 5. Setup bloXroute service
let bloxroute_service = Arc::new(BloXrouteService::new(
env_config.bloxroute_auth_header.clone(),
vec![signer.clone()],
http_send_tx_provider.clone(),
ipc_provider.clone(),
));

// 6. Create contract instances
let fourmeme_contract = Arc::new(FourmemeInstance::new(FOURMEME_CONTRACT, wss_provider_fourmeme.clone()));
let pancake_router_contract = Arc::new(PancakeSwapRouterInstance::new(
PANCAKESWAP_ROUTER,
wss_provider_pancake.clone(),
));
let fourmeme_contract = Arc::new(FourmemeInstance::new(FOURMEME_CONTRACT, ipc_provider.clone()));
let pancake_router_contract = Arc::new(PancakeSwapRouterInstance::new(PANCAKESWAP_ROUTER, ipc_provider.clone()));

// 7. Create nonce manager for Private transaction mode
let nonce_manager: Option<Arc<NonceManager<_, _>>> = if env_config.tx_submit_type == TxSubmitType::Private {
let provider_for_nonce = http_send_tx_provider.clone();
let nm = Arc::new(
NonceManager::new(provider_for_nonce, env_config.bot_address)
NonceManager::new(ipc_provider.clone(), env_config.bot_address)
.await
.map_err(|e| eyre::eyre!("Failed to create nonce manager: {}", e))?,
);

// Start background task to update nonce periodically (every 10 seconds)
let _handle = nm
let _ = nm
.update_nonce(std::time::Duration::from_secs(10))
.await
.map_err(|e| eyre::eyre!("Failed to start nonce update task: {}", e))?;
Expand All @@ -279,19 +253,16 @@ pub async fn run() -> eyre::Result<()> {
.map_err(|e| eyre::eyre!("Failed to create outer pool trader: {}", e))?;

// 9. Start BNB balance monitor task
let monitor_provider = Arc::new(http_send_tx_provider.clone());
let monitor_bot_address = env_config.bot_address;
let monitor_required_balance =
env_config.fourmeme_progress_buy_amount * U256::from(2) + ONE_ETHER / U256::from(1000u64); // buy_amount * 2 + 0.001 BNB
let monitor_telegram_bot_token = env_config.telegram_bot_token.clone();
let monitor_telegram_bot_chat_id = env_config.telegram_bot_chat_id.clone();
let monitor_required_balance = ONE_ETHER / U256::from(200u64); // 0.005 BNB
let ipc_provider_clone = ipc_provider.clone();
let env_config_clone = env_config.clone();
tokio::spawn(async move {
monitor_bnb_balance(
monitor_provider,
monitor_bot_address,
Arc::new(ipc_provider_clone),
env_config_clone.bot_address,
monitor_required_balance,
monitor_telegram_bot_token,
monitor_telegram_bot_chat_id,
env_config_clone.telegram_bot_token.clone(),
env_config_clone.telegram_bot_chat_id.clone(),
)
.await;
});
Expand All @@ -318,18 +289,18 @@ pub async fn run() -> eyre::Result<()> {
.from_block(BlockNumberOrTag::Latest);

engine.add_collector(map_collector!(
LogCollector::new(Arc::new(wss_provider_fourmeme.clone()), fourmeme_filter),
LogCollector::new(Arc::new(ipc_provider.clone()), fourmeme_filter),
Event::FourmemeLog
));
engine.add_collector(map_collector!(
LogCollector::new(Arc::new(wss_provider_pancake.clone()), pancake_filter),
LogCollector::new(Arc::new(ipc_provider.clone()), pancake_filter),
Event::PancakeSwapLog
));

// 12. Add strategy
let strategy = Strategy::new(
Arc::new(env_config.clone()),
Arc::new(http_provider),
Arc::new(ipc_provider.clone()),
db.clone(),
execution_lock.clone(),
);
Expand All @@ -352,20 +323,7 @@ pub async fn run() -> eyre::Result<()> {
start_db_cleaner(db_for_cleaner, Arc::new(env_config_for_cleaner)).await;
});

// 15. Start auto sell service
let auto_sell_service = AutoSeller::new(
db.clone(),
http_send_tx_provider.clone(),
Arc::new(Mutex::new(outer_pool_trader)),
bloxroute_service,
Arc::new(env_config.clone()),
60,
);
tokio::spawn(async move {
auto_sell_service.start().await;
});

// 16. Run engine
// 15. Run engine
Logger.success("Starting PVP bot engine...");
engine
.run_and_join()
Expand Down
2 changes: 1 addition & 1 deletion src/pvp/strategy/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub async fn parse_token_from_migrated_info<D: IDatabase>(
))
}

pub async fn get_wbnb_amount_when_bought_token<D: IDatabase>(
pub async fn get_pair_wbnb_balance_when_bought_token<D: IDatabase>(
db: &D,
meme_address: Address,
) -> Result<U256, CustomError> {
Expand Down
26 changes: 23 additions & 3 deletions src/pvp/strategy/strategy_fourmeme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub async fn on_fourmeme_token_migrated_event<

// [STRATEGY TOKEN MIGRATED]
// if:
// - 2 minutes after the token is migrated
// - 2.5 minutes after the token is migrated
// - the pair's wbnb balance is greater than `meme_migrated_model_b_threshold`
// then buy the token
let http_provider_clone = http_provider.clone();
Expand Down Expand Up @@ -115,6 +115,11 @@ pub async fn consider_selling<D: IDatabase, P: Provider<N> + Clone + Send + Sync
return Err(CustomError::StrategyDoNothing());
}

// [STRATEGY SELL]
// if:
// - curve progress is less than `fourmeme_bundle_sl_curve_progress`
// - we are in the fourmeme stage
// then sell all the tokens
let more_info = format!("curve progress: {}", curve_progress);
Logger.process(&format!(
"Strategy {} considering selling: meme address: {}, bot meme balance: {}, curve progress: {} - sell all",
Expand All @@ -123,7 +128,11 @@ pub async fn consider_selling<D: IDatabase, P: Provider<N> + Clone + Send + Sync
bot_meme_balance,
curve_progress
));
return Ok(build_sell_pending_action(meme_address, bot_meme_balance, more_info));
return Ok(build_bundle_sell_pending_action(
meme_address,
bot_meme_balance,
more_info,
));
}
}

Expand Down Expand Up @@ -162,6 +171,11 @@ pub async fn consider_buying<D: IDatabase, P: Provider<N> + Clone + Send + Sync
if curve_progress > env_config.fourmeme_progress_buy_curve_threshold {
let pair_wbnb_balance = get_pair_wbnb_balance(&http_provider, meme_address).await?;
let more_info = format!("curve progress: {}", curve_progress);

// [STRATEGY BUY]
// if:
// - curve progress is greater than `fourmeme_progress_buy_curve_threshold`
// then buy the token
return Ok(build_progress_buy_pending_action(
meme_address,
pair_wbnb_balance,
Expand All @@ -178,6 +192,12 @@ pub async fn consider_buying<D: IDatabase, P: Provider<N> + Clone + Send + Sync
"bundle tx block: {}, bundle sender: {}",
bundle_block_number, bundle_sender
);

// [STRATEGY BUY]
// if:
// - curve progress is greater than `fourmeme_bundle_threshold`
// - there is a bundle transaction
// then buy the token
return Ok(build_bundle_buy_pending_action(
meme_address,
pair_wbnb_balance,
Expand Down Expand Up @@ -223,7 +243,7 @@ async fn ensure_pair_info_in_db<D: IDatabase>(
}

/// Helper function: build the sell pending action
fn build_sell_pending_action(meme_address: Address, meme_amount: U256, more_info: String) -> PendingAction {
fn build_bundle_sell_pending_action(meme_address: Address, meme_amount: U256, more_info: String) -> PendingAction {
PendingAction {
strategy: StrategyType::Bundle.to_string(),
pool_type: PoolType::Fourmeme,
Expand Down
Loading
Loading