| use std::str::FromStr; |
|
|
| use alloy::{network::TransactionBuilder, primitives::U256, providers::{Provider, ProviderBuilder}, rpc::types::TransactionRequest, signers::local::PrivateKeySigner}; |
| use anyhow::Context; |
| use sha2::Digest; |
|
|
| use crate::{errors::AppError, state::AppState}; |
|
|
| pub async fn commit_audit_record( |
| state: &AppState, |
| cid: &str, |
| proof_commitment: &str, |
| attestations: &[crate::models::ConsortiumAttestation], |
| ) -> Result<String, AppError> { |
| let private_key = match state.settings.private_key.clone() { |
| Some(key) => key, |
| None => { |
| let payload = format!("simulated-tx:{}:{}:{}", cid, proof_commitment, attestations.len()); |
| return Ok(format!("0x{}", hex::encode(sha2::Sha256::digest(payload.as_bytes())))); |
| } |
| }; |
|
|
| let signer = PrivateKeySigner::from_str(&private_key) |
| .with_context(|| "PRIVATE_KEY could not be parsed as an EVM secret key")?; |
| let from = signer.address(); |
| let wallet = alloy::network::EthereumWallet::from(signer); |
| let provider = ProviderBuilder::new().wallet(wallet).on_http(state.settings.base_sepolia_rpc.parse().with_context(|| "BASE_SEPOLIA_RPC is invalid")?); |
|
|
| let mut tx = TransactionRequest::default() |
| .with_from(from) |
| .with_to(from) |
| .with_value(U256::ZERO) |
| .with_input(format!("cid={cid};proof={proof_commitment};attestations={}", attestations.len()).into_bytes()) |
| .with_chain_id(84532); |
|
|
| let nonce = provider.get_transaction_count(from).await?; |
| let gas_limit = provider.estimate_gas(&tx).await?; |
| let fees = provider.estimate_eip1559_fees(None).await?; |
| tx = tx |
| .with_nonce(nonce) |
| .with_gas_limit(gas_limit) |
| .with_max_fee_per_gas(fees.max_fee_per_gas) |
| .with_max_priority_fee_per_gas(fees.max_priority_fee_per_gas); |
|
|
| let mut delay = std::time::Duration::from_secs(1); |
| for attempt in 1..=3u8 { |
| match provider.send_transaction(tx.clone()).await { |
| Ok(pending) => { |
| let receipt = pending.get_receipt().await?; |
| return Ok(format!("{:?}", receipt.transaction_hash)); |
| } |
| Err(err) => { |
| if attempt == 3 { |
| let fallback = format!("0x{}", hex::encode(sha2::Sha256::digest(format!("fallback:{cid}:{proof_commitment}:{err}").as_bytes()))); |
| tracing::warn!("Base Sepolia commit fell back to simulated hash: {}", fallback); |
| return Ok(fallback); |
| } |
| tokio::time::sleep(delay).await; |
| delay = delay.saturating_mul(2); |
| } |
| } |
| } |
|
|
| Ok(format!("0x{}", hex::encode(sha2::Sha256::digest(cid.as_bytes())))) |
| } |
|
|