load_keypair_and_pubkey_from_json function added to load wallet key

This commit is contained in:
2025-11-06 17:17:50 +01:00
parent 6aab91ed1c
commit 5e05955308
57 changed files with 2429 additions and 46223 deletions

4
.env
View File

@@ -4,3 +4,7 @@ YELLOWSTONE_COMMITMENT=processed
BUNDLER=5jYaYv7HoiFVrY9bAcruj6dH8fCBseky4sBmnTFGSaeW
RUST_LOG=info
BIN_PATH=logs/frames/bin/1762440223791_slot378317940_4t6rKnrWTjmM_tx.bin
# Wallet
WALLET_PATH=keys/wallet_01.json

2921
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,18 +4,34 @@ version = "0.1.0"
edition = "2024"
[dependencies]
# utilidades
anyhow = "1"
futures = "0.3"
tokio = { version = "1.39", features = ["rt-multi-thread", "macros", "signal", "fs"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# TLS / HTTP libs si las necesitas luego (reqwest usa rustls)
reqwest = { version = "0.12", features = ["rustls-tls", "json"] }
# openssl si lo necesitas para otras cosas (dejamos vendored)
openssl = { version = "0.10", features = ["vendored"] }
yellowstone-grpc-client = "4"
yellowstone-grpc-proto = "4"
tonic = "0.11"
# Yellowstone gRPC (stack moderno)
yellowstone-grpc-client = "9"
yellowstone-grpc-proto = "9"
# gRPC core
tonic = "0.14"
# Solana SDK (rama 2.x compatible con la unidad moderna de crates)
solana-sdk = "2.3"
# utilidades
bs58 = "0.5"
dotenvy = "0.15"
# serialización
serde = { version = "1", features = ["derive"] }
serde_json = "1"

73
README.md Normal file
View File

@@ -0,0 +1,73 @@
┌───────────────────────────────────────────┐
│ ENTRADAS │
│ │
LIVE │ (A) Yellowstone Geyser -> txu │
(suscripción) ───▶│ (SubscribeUpdateTransaction) │
│ │
REPLAY │ (B) Archivo tx.bin (VersionedTx bincode) │
(logs/frames/bin) └───────────────┬───────────────────────────┘
┌───────────────────────────────────────────┐
│ main.rs │
│ - configura adapters[] │
│ - configura RPC │
│ - selecciona fuente: (A) o (B) │
└───────────────┬───────────────────────────┘
(A) txu │ (B) tx.bin
directo │ load_versioned_tx
┌───────────────────────────────────────────┐
│ engine.rs │
│ to_snapshot() -> TxuSnapshot │
│ - version (legacy/v0) │
│ - account_keys + (ALT lookups opc.) │
│ - instrucciones (orden + data) │
│ - compute budget ixs │
└───────────────┬───────────────────────────┘
│ TxuSnapshot
┌─────────────────────────────────────────────────────────┐
│ protocols.rs │
│ adapters[] = [ Meteora, PumpFun, Bonk, ... ] │
│ │
│ ┌──────────────┐ probe() ┌─────────────────────┐ │
│ │ Meteora │◀───────────▶│ TxuSnapshot │ │
│ └─────┬────────┘ └─────────────────────┘ │
│ │ (si reconoce) │
│ ▼ │
│ extract_plan() -> SwapPlan │
│ - PDAs/vaults del pool (NO cambiar) │
│ - mints/cantidades (si las decodificas) │
│ - ixs crudas (incl. ComputeBudget) │
│ │
│ build_message(SwapPlan, my_owner) -> PreparedMessage │
│ - sustituye: payer + ATAs del bundler → TUS ATAs │
│ - conserva: PDAs/vaults/Program IDs │
│ - WSOL/ATA lifecycle (si faltan, marca crear) │
│ - v0+ALT: reutiliza ALT o expande claves │
└─────────┬───────────────────────────────────────────────┘
│ PreparedMessage (mensaje SIN firmar)
┌───────────────────────────────────────┐
│ main.rs │
│ - inyecta recent_blockhash (RPC) │
│ - agrega ixs extra (create ATA/WSOL)│
│ - firma con tu Keypair │
└───────────────┬──────────────────────┘
│ VersionedTransaction firmado
┌──────────────────────────────────────────────────┐
│ rpc.rs │
│ getLatestBlockhash() │
│ simulateTransaction() ──▶ (CUs, logs, errores) │
│ sendTransaction() ──▶ signature (base58) │
└───────────────────┬──────────────────────────────┘
┌────────────────────────────┐
│ Resultado │
│ - ok: firma/slot │
│ - fail: motivo/log │
└────────────────────────────┘

1
keys/wallet_01.json Normal file
View File

@@ -0,0 +1 @@
[250,118,51,30,164,231,4,233,107,88,82,182,111,68,193,6,75,94,233,74,200,39,61,212,169,83,85,44,13,115,143,28,28,74,241,97,180,111,148,237,203,166,51,118,205,220,37,62,156,192,29,119,181,64,141,133,29,54,139,114,3,149,115,0]

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,10 @@ use tracing_subscriber::EnvFilter;
use sniper_bot::listener;
use sniper_bot::listener::YellowstoneSource;
use sniper_bot::utils::save_tx_update;
use sniper_bot::utils::{
save_tx_update,
load_keypair_and_pubkey_from_json,
};
@@ -20,6 +22,12 @@ async fn main() -> Result<()> {
// Load environment variables from .env file
dotenv().ok();
let bundler = std::env::var("BUNDLER")?;
let wallet_path = std::env::var("WALLET_PATH")?;
// Wallet
let (kp, my_owner) = load_keypair_and_pubkey_from_json(&wallet_path)?;
println!("🔑 Owner: {my_owner}");

View File

@@ -1,12 +1,53 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::fs as std_fs;
use std::time::{SystemTime, UNIX_EPOCH};
use std::convert::TryFrom;
use anyhow::Result;
use anyhow::{anyhow, Context, Result};
use bs58;
use tokio::fs;
use yellowstone_grpc_proto::geyser::SubscribeUpdateTransaction;
use yellowstone_grpc_proto::prost::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signer};
/// Carga un keypair desde un JSON (array de 64 u 32 enteros) y devuelve (Keypair, Pubkey).
/// - 64 bytes: clave secreta completa (secret + public) -> `Keypair::from_bytes`.
/// - 32 bytes: semilla ed25519 -> `Keypair::from_seed`.
pub fn load_keypair_and_pubkey_from_json<P: AsRef<Path>>(path: P) -> Result<(Keypair, Pubkey)> {
let path_ref = path.as_ref();
let data = std_fs::read_to_string(path_ref)
.with_context(|| format!("Leyendo wallet JSON: {}", path_ref.display()))?;
// Parse JSON array of integers into Vec<u8>
let vec_bytes: Vec<u8> = serde_json::from_str(&data)
.with_context(|| "Parseando JSON de la wallet (se espera array de enteros)")?;
let kp = match vec_bytes.len() {
64 => {
// from_bytes returns Result<Keypair, _>
Keypair::try_from(&vec_bytes[..])
.map_err(|e| anyhow!("Keypair::try_from falló (¿array de 64 bytes válido?): {e}"))?
}
32 => {
let mut seed = [0u8; 32];
seed.copy_from_slice(&vec_bytes);
// new_from_array exists in solana-keypair and constructs from a 32-byte secret
Keypair::new_from_array(seed)
}
n => {
return Err(anyhow!(
"Formato de wallet no soportado: se esperaban 64 o 32 bytes, recibidos {n}"
))
}
};
let pubkey = kp.pubkey();
Ok((kp, pubkey))
}
// Save file from tx received
pub async fn save_tx_update(txu: &SubscribeUpdateTransaction) -> Result<(PathBuf, PathBuf)> {