Files
lapa_v3/src/main.rs

148 lines
4.0 KiB
Rust

use anyhow::{Context, Result};
use tokio::sync::mpsc;
use yellowstone_grpc_proto::geyser::SubscribeUpdateTransaction;
use yellowstone_grpc_proto::prost::Message;
use bs58;
use dotenvy::dotenv;
use std::fs;
use sniper_bot::listener;
use sniper_bot::listener::YellowstoneSource;
use sniper_bot::utils::{
save_tx_update,
load_keypair_and_pubkey_from_json,
init_tracing,
};
use sniper_bot::engine::prepare_and_build;
use sniper_bot::protocols::default_adapters;
use sniper_bot::rpc::{HttpRpc, Rpc, sign_versioned_tx};
use solana_sdk::{hash::Hash, message::VersionedMessage};
#[tokio::main]
async fn main() -> Result<()> {
init_tracing();
// Load environment variables from .env file
dotenv().ok();
let bundler = std::env::var("BUNDLER")?;
// Testing conditions
//
let simulate_first = std::env::var("SIMULATE_FIRST").unwrap_or_else(|_| "true".to_string()) == "true";
let bin_path = std::env::var("BIN_PATH").context("Falta BIN_PATH en .env (o variable de entorno)")?;
//
// Testing conditions
// Load wallet
let (kp, kp_pub) = load_keypair_and_pubkey_from_json()?;
eprintln!("Keypair pubkey: {}", kp_pub);
tracing::info!("[INFO] Bot initialited");
// RPC client
let rpc = HttpRpc::new()?;
// Testing conditions
//
// Cargar y decodificar el BIN a txu (protobuf)
let bytes = fs::read(&bin_path).with_context(|| format!("Leyendo binario: {bin_path}"))?;
let txu = SubscribeUpdateTransaction::decode(bytes.as_slice()).context("Decodificando prost: SubscribeUpdateTransaction")?;
//
// Testing conditions
let adapters = default_adapters();
// === A partir de aquí: orquestar compra ===
// 1) Plan + mensaje preparado (por ahora: replay 1:1)
let (_plan, prepared) = prepare_and_build(txu, &adapters, &kp_pub)?;
// 2) Blockhash fresco + slot
let (new_bh, ctx_slot) = rpc.get_latest_blockhash().await?;
println!("Latest slot solana: {ctx_slot}");
// 3) Actualiza blockhash del mensaje
let vm = set_recent_blockhash(prepared.message, new_bh);
// 4) Firma con tu keypair
let vtx = sign_versioned_tx(vm, &[&kp])?;
// 5) Simula (opcional)
if simulate_first {
rpc.simulate(&vtx, Some(ctx_slot)).await?;
println!("🧪 simulateTransaction OK");
}
// 6) Enviar
let sig = rpc.send_transaction(&vtx, Some(ctx_slot)).await?;
println!("🚀 Enviada: {}", sig);
// Testing conditions
//
return Ok(());
//
// Testing conditions
// Create a channel for transaction updates
let (tx, mut rx) = mpsc::channel::<SubscribeUpdateTransaction>(1024);
// Connect to Yellowstone source
let yellowstone_source = YellowstoneSource::connect(
bundler
).await?;
// Launch listener
let _run = tokio::spawn({
let tx = tx.clone();
async move {
if let Err(e) = listener::yellowstone_forward_source_to_channel(yellowstone_source, tx).await {
tracing::error!("[ERR] listener error: {}", e);
}
}
});
while let Some(txu) = rx.recv().await {
// Guarda en disco
if let Err(e) = save_tx_update(&txu).await {
tracing::warn!("No se pudo guardar el frame: {e:?}");
}
//tracing::info!("[INFO] received transaction update: \n{:#?}", txu);
let sig = txu
.transaction
.as_ref()
.map(|t| bs58::encode(&t.signature).into_string())
.unwrap_or("<no-signature>".to_string());
tracing::info!("OK: slot={} sig={}", txu.slot, sig);
}
Ok(())
}
fn set_recent_blockhash(mut vm: VersionedMessage, new_bh: Hash) -> VersionedMessage {
match &mut vm {
VersionedMessage::V0(m) => { m.recent_blockhash = new_bh; }
VersionedMessage::Legacy(m) => { m.recent_blockhash = new_bh; }
}
vm
}