use contractless::blocks::burn::BurnTransaction; use contractless::blocks::collateral::CollateralClaimTransaction; use contractless::blocks::issue_token::IssueTokenTransaction; use contractless::blocks::loan_payment::ContractPaymentTransaction; use contractless::blocks::loans::LoanContractTransaction; use contractless::blocks::marketing::MarketingTransaction; use contractless::blocks::nft::CreateNftTransaction; use contractless::blocks::swap::SwapTransaction; use contractless::blocks::token::CreateTokenTransaction; use contractless::blocks::transfer::TransferTransaction; use contractless::blocks::vanity::VanityAddressTransaction; use contractless::common::cli_prompts::{prompt_hidden_nonempty, prompt_wallet_path}; use contractless::common::network_startup::get_connections; use contractless::common::types::{ BORROWER_TYPE, BURN_TYPE, COLLATERAL_TYPE, CREATE_NFT_TYPE, CREATE_TOKEN_TYPE, ISSUE_TOKEN_TYPE, LENDER_TYPE, MARKETING_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE, }; use contractless::env; use contractless::json; use contractless::records::memory::response_channels::generate_uid; use contractless::standalone_tools::connections::handshake; use contractless::to_string_pretty; async fn decode_mempool_transaction(response: &[u8]) -> Option { // Mempool transaction replies are the original transaction bytes, // starting with the transaction type byte and no block-height prefix. let txtype = *response.first()?; let body = &response[1..]; match txtype { TRANSFER_TYPE => { to_string_pretty(&TransferTransaction::from_bytes(txtype, body).await.ok()?).ok() } CREATE_TOKEN_TYPE => to_string_pretty( &CreateTokenTransaction::from_bytes(txtype, body) .await .ok()?, ) .ok(), CREATE_NFT_TYPE => { to_string_pretty(&CreateNftTransaction::from_bytes(txtype, body).await.ok()?).ok() } MARKETING_TYPE => { to_string_pretty(&MarketingTransaction::from_bytes(txtype, body).await.ok()?).ok() } SWAP_TYPE => to_string_pretty(&SwapTransaction::from_bytes(txtype, body).await.ok()?).ok(), LENDER_TYPE => to_string_pretty( &LoanContractTransaction::from_bytes(txtype, body) .await .ok()?, ) .ok(), BORROWER_TYPE => to_string_pretty( &ContractPaymentTransaction::from_bytes(txtype, body) .await .ok()?, ) .ok(), COLLATERAL_TYPE => to_string_pretty( &CollateralClaimTransaction::from_bytes(txtype, body) .await .ok()?, ) .ok(), BURN_TYPE => to_string_pretty(&BurnTransaction::from_bytes(txtype, body).await.ok()?).ok(), ISSUE_TOKEN_TYPE => { to_string_pretty(&IssueTokenTransaction::from_bytes(txtype, body).await.ok()?).ok() } VANITY_ADDRESS_TYPE => to_string_pretty( &VanityAddressTransaction::from_bytes(txtype, body) .await .ok()?, ) .ok(), _ => None, } } #[tokio::main] async fn main() { // Command 14 asks a peer for one unprocessed mempool transaction by signature. let rpc_command = 14; // The signature is passed as hex and converted into raw signature bytes by sending_request. let args: Vec = env::args().collect(); if args.len() != 2 { println!("Usage: ./lookup_mempool_tx_by_signature "); return; } let signature = args[1].trim().to_string(); let wallet_path = prompt_wallet_path().await; let encryption_key = prompt_hidden_nonempty( "What is your wallet decryption key? ", "Wallet key cannot be empty. Please try again.", ) .await; let connections = get_connections().await; let mut connected = false; for conn in connections { if connected { break; } let socket_address = conn.parse().expect("Failed to parse the socket address"); let result = handshake::connect_and_handshake( socket_address, signature.clone(), rpc_command, handshake::HandshakeWallet::WalletKey { encryption_key: encryption_key.clone(), wallet_path: wallet_path.clone(), }, generate_uid(), ) .await; match result { Ok(response) => { if response.is_empty() { println!("Transaction not found in mempool."); connected = true; } else if let Some(transaction_json) = decode_mempool_transaction(&response).await { println!("{transaction_json}"); connected = true; } else { // Text errors are printed directly; unknown binary is shown as hex for inspection. let response_text = String::from_utf8_lossy(&response); let trimmed = response_text.trim(); if !trimmed.is_empty() { println!("{trimmed}"); } else { println!( "{}", serde_json::to_string_pretty(&json!({ "hex": hex::encode(response) })) .unwrap() ); } connected = true; } } Err(_) => connected = false, } } if !connected { eprintln!("failed to connect"); } }