use anyhow::Result; use alloy::{ network::TransactionBuilder, primitives::U256, providers::{Provider, ProviderBuilder}, signers::local::PrivateKeySigner, rpc::types::TransactionRequest, }; use std::str::FromStr; pub async fn commit_cid(cid: &str) -> Result { let rpc_url = "https://sepolia.base.org".parse()?; let priv_key = std::env::var("PRIVATE_KEY") .unwrap_or_else(|_| "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string()); let signer = PrivateKeySigner::from_str(&priv_key)?; let from = signer.address(); let wallet = alloy::network::EthereumWallet::from(signer); let provider = ProviderBuilder::new() .wallet(wallet) .on_http(rpc_url); let data = cid.as_bytes().to_vec(); let mut tx = TransactionRequest::default() .with_from(from) .with_to(from) // self‑transfer .with_value(U256::ZERO) .with_input(data) .with_chain_id(84532); // <-- Base Sepolia chain ID let nonce = provider.get_transaction_count(from).await?; let gas_limit = provider.estimate_gas(&tx).await?; let fee = provider.estimate_eip1559_fees(None).await?; tx = tx .with_nonce(nonce) .with_gas_limit(gas_limit) .with_max_fee_per_gas(fee.max_fee_per_gas) .with_max_priority_fee_per_gas(fee.max_priority_fee_per_gas); // Retry loop (handles 502 errors) let mut attempts = 0; loop { match provider.send_transaction(tx.clone()).await { Ok(pending) => { let receipt = pending.get_receipt().await?; let tx_hash = receipt.transaction_hash; tracing::info!( "Committed CID {} to Base Sepolia, tx: {:?}", cid, tx_hash ); return Ok(format!("{:?}", tx_hash)); } Err(e) if attempts < 3 && e.to_string().contains("502") => { attempts += 1; tokio::time::sleep(std::time::Duration::from_secs(2)).await; continue; } Err(e) => return Err(anyhow::Error::new(e).context("send_transaction failed")), } } }