From 22eaae6b0d131be8620f56e43924fb6bfdd5ade4 Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Thu, 23 Oct 2025 13:21:04 +0200 Subject: [PATCH 1/7] Remove non v1 api endpoints. --- src/main.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7ea6c14..e9be986 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1265,22 +1265,17 @@ async fn main() { let app = Router::new() .route("/", get(alive)) .route("/versions", get(versions)) - .route("/v1/info", get(info)) .route("/info", get(info)) + .route("/v1/info", get(info)) .route("/v1/eth/proof/{block_hash}", get(get_eth_proof)) - .route("/eth/proof/{block_hash}", get(get_eth_proof)) .route("/v1/eth/head", get(get_eth_head)) - .route("/eth/head", get(get_eth_head_legacy)) .route("/v1/avl/head", get(get_avl_head)) - .route("/avl/head", get(get_avl_head)) .route( "/v1/avl/proof/{block_hash}/{message_id}", get(get_avl_proof), ) .route("/v1/transactions", get(transactions)) .route("/transactions", get(transactions)) - .route("/avl/proof/{block_hash}/{message_id}", get(get_avl_proof)) - .route("/beacon/slot/{slot_number}", get(get_beacon_slot)) .route("/v1/head/{chain_id}", get(get_head)) .route("/v1/proof/{chain_id}", get(get_proof)) .layer(TraceLayer::new_for_http()) From d66cc211aa66729a0bec59cb5269979af0bb0089 Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Thu, 23 Oct 2025 14:14:32 +0200 Subject: [PATCH 2/7] Remove succinct api and move models. --- .env.example | 2 +- README.md | 2 +- src/main.rs | 489 +++++++------------------------------------------- src/models.rs | 282 ++++++++++++++++++++++++++++- 4 files changed, 344 insertions(+), 431 deletions(-) diff --git a/.env.example b/.env.example index 866019c..2fc964d 100755 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ AVAIL_CLIENT_URL= -SUCCINCT_URL= +MERKLE_PROOF_SERVICE_URL= AVAIL_CHAIN_NAME= CONTRACT_CHAIN_ID= VECTORX_CONTRACT_ADDRESS= diff --git a/README.md b/README.md index 8ab723b..990ae63 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Bridge API -The bridge API is a REST API for fetching proofs from Avail's Kate RPC and Succinct API to submit on Ethereum or +The bridge API is a REST API for fetching proofs from Avail's Kate RPC and Merkle proof service API to submit on Ethereum or any off-chain proof verification. ## Deploying the bridge API diff --git a/src/main.rs b/src/main.rs index e9be986..886c4aa 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,13 @@ mod models; mod schema; -use crate::models::{AvailSend, EthereumSend, StatusEnum}; +use crate::models::*; + use crate::schema::avail_sends::dsl::avail_sends; use crate::schema::ethereum_sends::dsl::ethereum_sends; use alloy::primitives::{Address, B256, U256, hex}; use alloy::providers::ProviderBuilder; -use alloy::sol; use anyhow::{Context, Result, anyhow}; -use avail_core::data_proof::AddressedMessage; use axum::body::{Body, to_bytes}; use axum::response::Response; use axum::{ @@ -25,7 +24,7 @@ use diesel::{ ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl, SelectableHelper, r2d2, r2d2::ConnectionManager, }; -use http::{HeaderMap, HeaderName, HeaderValue, Method}; +use http::Method; use jsonrpsee::{ core::ClientError, core::client::ClientT, @@ -34,7 +33,7 @@ use jsonrpsee::{ }; use lazy_static::lazy_static; use reqwest::Client; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use serde_with::serde_as; use sha3::{Digest, Keccak256}; @@ -58,309 +57,28 @@ use tracing_subscriber::prelude::*; #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; -sol!( - #[allow(missing_docs)] - #[sol(rpc)] - SP1Vector, - "src/abi/SP1Vector.json" -); - -#[derive(Debug, Deserialize)] -struct Root { - data: Data, -} - -#[derive(Debug, Deserialize)] -struct Data { - message: Message, -} - -#[derive(Debug, Deserialize)] -struct Message { - slot: String, - body: MessageBody, -} - -#[derive(Debug, Deserialize)] -struct MessageBody { - execution_payload: ExecutionPayload, -} - -#[derive(Debug, Deserialize)] -struct ExecutionPayload { - block_number: String, - block_hash: String, -} - -struct ErrorResponse { - pub error: anyhow::Error, - pub headers_keypairs: Vec<(String, String)>, - pub status_code: Option, -} - -impl ErrorResponse { - pub fn new(error: anyhow::Error) -> Self { - Self { - error, - headers_keypairs: vec![], - status_code: None, - } - } - pub fn with_status(error: anyhow::Error, status_code: StatusCode) -> Self { - Self { - error, - headers_keypairs: vec![], - status_code: Some(status_code), - } - } - - pub fn with_status_and_headers( - error: anyhow::Error, - status_code: StatusCode, - headers: &[(&str, &str)], - ) -> Self { - let h = headers - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect::>(); - Self { - error, - headers_keypairs: h, - status_code: Some(status_code), - } - } -} - -// Tell axum how to convert `AppError` into a response. -impl IntoResponse for ErrorResponse { - fn into_response(self) -> Response { - let status = self - .status_code - .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR); - let mut headermap = HeaderMap::new(); - for (k, v) in self.headers_keypairs { - headermap.insert( - HeaderName::try_from(k).unwrap(), - HeaderValue::try_from(v).unwrap(), - ); - } - let json_resp = Json(json!({"error" : format!("{:#}", self.error)})); - - (status, headermap, json_resp).into_response() - } -} - -// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into -// `Result<_, AppError>`. That way you don't need to do that manually. -impl From for ErrorResponse -where - E: Into, -{ - fn from(err: E) -> Self { - Self { - error: err.into(), - headers_keypairs: vec![], - status_code: None, - } - } -} - #[derive(Debug)] -struct AppState { - avail_client: HttpClient, - ethereum_client: HttpClient, - request_client: Client, - succinct_base_url: String, - beaconchain_base_url: String, - avail_chain_name: String, - contract_chain_id: String, - contract_address: String, - bridge_contract_address: String, - eth_head_cache_maxage: u16, - avl_head_cache_maxage: u16, - head_cache_maxage: u16, - avl_proof_cache_maxage: u32, - eth_proof_cache_maxage: u32, - proof_cache_maxage: u32, - eth_proof_failure_cache_maxage: u32, - slot_mapping_cache_maxage: u32, - transactions_cache_maxage: u32, - connection_pool: r2d2::Pool>, - chains: HashMap, -} - -#[derive(Debug)] -struct Chain { - rpc_url: String, - contract_address: Address, -} - -#[derive(Deserialize)] -struct IndexStruct { - index: u32, -} - -#[derive(Deserialize)] -struct ProofQueryStruct { - index: u32, - block_hash: B256, -} - -#[derive(Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -struct KateQueryDataProofResponse { - data_proof: DataProof, - #[serde(skip_serializing_if = "Option::is_none")] - message: Option, -} - -#[derive(Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -struct DataProof { - roots: Roots, - proof: Vec, - leaf_index: u32, - leaf: B256, -} - -#[derive(Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -struct Roots { - data_root: B256, - blob_root: B256, - bridge_root: B256, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct AccountStorageProofResponse { - account_proof: Vec, - storage_proof: Vec, -} - -#[derive(Deserialize)] -struct StorageProof { - proof: Vec, -} - -#[derive(Deserialize)] -struct SuccinctAPIResponse { - data: Option, - error: Option, - success: Option, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct SlotMappingResponse { - block_hash: String, - block_number: String, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct SuccinctAPIData { - range_hash: B256, - data_commitment: B256, - merkle_branch: Vec, - index: u16, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct AggregatedResponse { - data_root_proof: Vec, - leaf_proof: Vec, - range_hash: B256, - data_root_index: u16, - leaf: B256, - leaf_index: u32, - data_root: B256, - blob_root: B256, - bridge_root: B256, - data_root_commitment: B256, - block_hash: B256, - message: Option, -} - -impl AggregatedResponse { - pub fn new( - range_data: SuccinctAPIData, - data_proof_res: KateQueryDataProofResponse, - hash: B256, - ) -> Self { - AggregatedResponse { - data_root_proof: range_data.merkle_branch, - leaf_proof: data_proof_res.data_proof.proof, - range_hash: range_data.range_hash, - data_root_index: range_data.index, - leaf: data_proof_res.data_proof.leaf, - leaf_index: data_proof_res.data_proof.leaf_index, - data_root: data_proof_res.data_proof.roots.data_root, - blob_root: data_proof_res.data_proof.roots.blob_root, - bridge_root: data_proof_res.data_proof.roots.bridge_root, - data_root_commitment: range_data.data_commitment, - block_hash: hash, - message: data_proof_res.message, - } - } -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct EthProofResponse { - account_proof: Vec, - storage_proof: Vec, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct HeadResponseV2 { - pub slot: u64, - pub block_number: u64, - pub block_hash: B256, - pub timestamp: u64, - pub timestamp_diff: u64, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct HeadResponseLegacy { - pub slot: u64, - pub timestamp: u64, - pub timestamp_diff: u64, -} - -#[derive(Serialize, Deserialize)] -struct ChainHeadResponse { - pub head: u32, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct RangeBlocks { - start: u32, - end: u32, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -struct RangeBlocksAPIResponse { - data: RangeBlocks, -} - -#[derive(Debug, Deserialize)] -pub struct HeaderBlockNumber { - #[serde(deserialize_with = "hex_to_u32")] - pub number: u32, -} - -fn hex_to_u32<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - u32::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom) +pub struct AppState { + pub avail_client: HttpClient, + pub ethereum_client: HttpClient, + pub request_client: Client, + pub merkle_proof_service_base_url: String, + pub beaconchain_base_url: String, + pub avail_chain_name: String, + pub contract_chain_id: String, + pub contract_address: String, + pub bridge_contract_address: String, + pub eth_head_cache_maxage: u16, + pub avl_head_cache_maxage: u16, + pub head_cache_maxage: u16, + pub avl_proof_cache_maxage: u32, + pub eth_proof_cache_maxage: u32, + pub proof_cache_maxage: u32, + pub eth_proof_failure_cache_maxage: u32, + pub slot_mapping_cache_maxage: u32, + pub transactions_cache_maxage: u32, + pub connection_pool: r2d2::Pool>, + pub chains: HashMap, } async fn alive() -> Result, StatusCode> { @@ -565,21 +283,22 @@ async fn get_eth_proof( let eth_proof_failure_cache_maxage = state.eth_proof_failure_cache_maxage; let url = format!( "{}?chainName={}&contractChainId={}&contractAddress={}&blockHash={}", - state.succinct_base_url, + state.merkle_proof_service_base_url, state.avail_chain_name, state.contract_chain_id, state.contract_address, block_hash ); - let succinct_response_fut = tokio::spawn(async move { - let succinct_response = state.request_client.get(url).send().await; - match succinct_response { - Ok(resp) => resp.json::().await, + let mekrle_proof_response_fut = tokio::spawn(async move { + let merkle_proof_response = state.request_client.get(url).send().await; + match merkle_proof_response { + Ok(resp) => resp.json::().await, Err(err) => Err(err), } }); - let (data_proof, succinct_response) = join!(data_proof_response_fut, succinct_response_fut); + let (data_proof, merkle_proof_response) = + join!(data_proof_response_fut, mekrle_proof_response_fut); let data_proof_res: KateQueryDataProofResponse = data_proof .map_err(|e| { tracing::error!("❌ Failed to fetch the kate query data. Error: {e:#}"); @@ -598,7 +317,7 @@ async fn get_eth_proof( ) })?; - let succinct_data = succinct_response + let merkle_proof_data = merkle_proof_response .map_err(|e| { tracing::error!("❌ Failed to get the merkle proof data. Error: {e:#}"); ErrorResponse::with_status_and_headers( @@ -615,25 +334,22 @@ async fn get_eth_proof( &[("Cache-Control", "public, max-age=60, must-revalidate")], ) })?; - let succinct_data = match succinct_data { - SuccinctAPIResponse { + let merkle_data = match merkle_proof_data { + MekrleProofAPIResponse { data: Some(data), .. } => data, - SuccinctAPIResponse { + MekrleProofAPIResponse { success: Some(false), error: Some(data), .. } => { if data.contains("not in the range of blocks") { tracing::warn!( - "⏳ Succinct VectorX contract not updated yet! Response: {}", + "⏳ Merkle proof VectorX contract not updated yet! Response: {}", data ); } else { - tracing::error!( - "❌ Succinct API returned unsuccessfully. Response: {}", - data - ); + tracing::error!("❌ Merkle API returned unsuccessfully. Response: {}", data); } return Err(ErrorResponse::with_status_and_headers( @@ -647,9 +363,9 @@ async fn get_eth_proof( } _ => { - tracing::error!("❌ Succinct API returned no data"); + tracing::error!("❌ Merkle proof API returned no data"); return Err(ErrorResponse::with_status_and_headers( - anyhow!("Succinct API returned no data"), + anyhow!("Merkle proof API returned no data"), StatusCode::NOT_FOUND, &[("Cache-Control", "public, max-age=60, must-revalidate")], )); @@ -663,16 +379,16 @@ async fn get_eth_proof( format!("public, max-age={}, immutable", eth_proof_cache_maxage), )], Json(json!(AggregatedResponse { - data_root_proof: succinct_data.merkle_branch, + data_root_proof: merkle_data.merkle_branch, leaf_proof: data_proof_res.data_proof.proof, - range_hash: succinct_data.range_hash, - data_root_index: succinct_data.index, + range_hash: merkle_data.range_hash, + data_root_index: merkle_data.index, leaf: data_proof_res.data_proof.leaf, leaf_index: data_proof_res.data_proof.leaf_index, data_root: data_proof_res.data_proof.roots.data_root, blob_root: data_proof_res.data_proof.roots.blob_root, bridge_root: data_proof_res.data_proof.roots.bridge_root, - data_root_commitment: succinct_data.data_commitment, + data_root_commitment: merkle_data.data_commitment, block_hash, message: data_proof_res.message })), @@ -739,59 +455,6 @@ async fn get_avl_proof( .into_response()) } -/// Creates a request to the beaconcha service for mapping slot to the block number. -#[inline(always)] -async fn get_beacon_slot( - Path(slot): Path, - State(state): State>, -) -> Result { - let resp = state - .request_client - .get(format!( - "{}/eth/v2/beacon/blocks/{}", - state.beaconchain_base_url, slot - )) - .send() - .await - .map_err(|e| { - tracing::error!("❌ Cannot get beacon API data: {e:#}"); - ErrorResponse::with_status_and_headers( - e.into(), - StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], - ) - })?; - - let response_data = resp.json::().await.map_err(|e| { - tracing::error!("❌ Cannot get beacon API response data: {e:#}"); - ErrorResponse::with_status_and_headers( - e.into(), - StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], - ) - })?; - Ok(( - StatusCode::OK, - [( - "Cache-Control", - format!( - "public, max-age={}, immutable", - state.slot_mapping_cache_maxage - ), - )], - Json(json!(SlotMappingResponse { - block_number: response_data - .data - .message - .body - .execution_payload - .block_number, - block_hash: response_data.data.message.body.execution_payload.block_hash - })), - ) - .into_response()) -} - /// get_eth_head returns Ethereum head with the latest slot/block that is stored and a time. #[inline(always)] async fn get_eth_head( @@ -827,39 +490,6 @@ async fn get_eth_head( .into_response()) } -/// get_eth_head returns Ethereum head with the latest slot/block that is stored and a time. -#[inline(always)] -async fn get_eth_head_legacy( - State(state): State>, -) -> Result { - let slot_block_head = SLOT_BLOCK_HEAD.read().await; - let (slot, _block, _hash, timestamp) = slot_block_head.as_ref().ok_or_else(|| { - ErrorResponse::with_status_and_headers( - anyhow!("Not found"), - StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], - ) - })?; - - let now = Utc::now().timestamp() as u64; - Ok(( - StatusCode::OK, - [( - "Cache-Control", - format!( - "public, max-age={}, must-revalidate", - state.eth_head_cache_maxage - ), - )], - Json(json!(HeadResponseLegacy { - slot: *slot, - timestamp: *timestamp, - timestamp_diff: now - *timestamp - })), - ) - .into_response()) -} - /// get_avl_head returns start and end blocks which the contract has commitments #[inline(always)] async fn get_avl_head( @@ -867,7 +497,10 @@ async fn get_avl_head( ) -> Result { let url = format!( "{}/{}/?contractChainId={}&contractAddress={}", - state.succinct_base_url, "range", state.contract_chain_id, state.contract_address + state.merkle_proof_service_base_url, + "range", + state.contract_chain_id, + state.contract_address ); let response = state.request_client.get(url).send().await.map_err(|e| { tracing::error!("❌ Cannot parse range blocks: {e:#}"); @@ -1040,21 +673,21 @@ async fn get_proof( &[("Cache-Control", "max-age=60, must-revalidate")], ) })? { - Ok(SuccinctAPIResponse { + Ok(MekrleProofAPIResponse { data: Some(data), .. }) => data, - Ok(SuccinctAPIResponse { + Ok(MekrleProofAPIResponse { success: Some(false), error: Some(data), .. }) => { if data.contains("not in the range of blocks") { - tracing::warn!( - "Succinct VectorX contract not updated yet! Response: {}", + tracing::warn!("VectorX contract not updated yet! Response: {}", data); + } else { + tracing::error!( + "Merkle proof API returned unsuccessfully. Response: {}", data ); - } else { - tracing::error!("Succinct API returned unsuccessfully. Response: {}", data); } return Err(ErrorResponse::with_status_and_headers( anyhow!("error: {data}"), @@ -1063,7 +696,7 @@ async fn get_proof( )); } Err(err) => { - tracing::error!("Cannot get succinct api response {:?}", err); + tracing::error!("Cannot get merkle proof api response {:?}", err); return Err(ErrorResponse::with_status_and_headers( anyhow!("error: {err}"), StatusCode::INTERNAL_SERVER_ERROR, @@ -1071,9 +704,9 @@ async fn get_proof( )); } _ => { - tracing::error!("Succinct API returned no data"); + tracing::error!("Merkle proof API returned no data"); return Err(ErrorResponse::with_status_and_headers( - anyhow!("Succinct API returned no data"), + anyhow!("Merkle proof API returned no data"), StatusCode::INTERNAL_SERVER_ERROR, &[("Cache-Control", "max-age=60, must-revalidate")], )); @@ -1113,10 +746,10 @@ fn spawn_kate_proof( fn spawn_merkle_proof_range_fetch( state: Arc, block_hash: B256, -) -> JoinHandle> { +) -> JoinHandle> { let url = format!( "{}?chainName={}&contractChainId={}&contractAddress={}&blockHash={}", - state.succinct_base_url, + state.merkle_proof_service_base_url, state.avail_chain_name, state.contract_chain_id, state.contract_address, @@ -1125,7 +758,7 @@ fn spawn_merkle_proof_range_fetch( tokio::spawn(async move { let res = state.request_client.get(url).send().await; match res { - Ok(resp) => resp.json::().await, + Ok(resp) => resp.json::().await, Err(e) => Err(e), } }) @@ -1210,7 +843,7 @@ async fn main() { ) .unwrap(), request_client: Client::builder().brotli(true).build().unwrap(), - succinct_base_url: env::var("SUCCINCT_URL") + merkle_proof_service_base_url: env::var("MERKLE_PROOF_SERVICE_URL") .unwrap_or("https://beaconapi.succinct.xyz/api/integrations/vectorx".to_owned()), beaconchain_base_url: env::var("BEACONCHAIN_URL") .unwrap_or("https://sepolia.beaconcha.in/api/v1/slot".to_owned()), diff --git a/src/models.rs b/src/models.rs index 67ebf4d..b71b491 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,4 +1,9 @@ use crate::schema::sql_types::Status; +use alloy::primitives::{Address, B256}; +use alloy::sol; +use avail_core::data_proof::AddressedMessage; +use axum::Json; +use axum::response::{IntoResponse, Response}; use chrono::NaiveDateTime; use diesel::pg::{Pg, PgValue}; use diesel::serialize::{IsNull, Output}; @@ -8,11 +13,286 @@ use diesel::{ serialize::ToSql, *, }; +use http::{HeaderMap, HeaderName, HeaderValue, StatusCode}; use jsonrpsee::core::Serialize; -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; +use serde_json::json; use serde_with::serde_as; use std::io::Write; +sol!( + #[allow(missing_docs)] + #[sol(rpc)] + SP1Vector, + "src/abi/SP1Vector.json" +); + +#[derive(Debug, Deserialize)] +pub struct Root { + pub data: Data, +} + +#[derive(Debug, Deserialize)] +pub struct Data { + pub message: Message, +} + +#[derive(Debug, Deserialize)] +pub struct Message { + pub slot: String, + pub body: MessageBody, +} + +#[derive(Debug, Deserialize)] +pub struct MessageBody { + pub execution_payload: ExecutionPayload, +} + +#[derive(Debug, Deserialize)] +pub struct ExecutionPayload { + pub block_number: String, + pub block_hash: String, +} + +pub struct ErrorResponse { + pub error: anyhow::Error, + pub headers_keypairs: Vec<(String, String)>, + pub status_code: Option, +} + +impl ErrorResponse { + pub fn new(error: anyhow::Error) -> Self { + Self { + error, + headers_keypairs: vec![], + status_code: None, + } + } + pub fn with_status(error: anyhow::Error, status_code: StatusCode) -> Self { + Self { + error, + headers_keypairs: vec![], + status_code: Some(status_code), + } + } + + pub fn with_status_and_headers( + error: anyhow::Error, + status_code: StatusCode, + headers: &[(&str, &str)], + ) -> Self { + let h = headers + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect::>(); + Self { + error, + headers_keypairs: h, + status_code: Some(status_code), + } + } +} + +// Tell axum how to convert `AppError` into a response. +impl IntoResponse for ErrorResponse { + fn into_response(self) -> Response { + let status = self + .status_code + .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR); + let mut headermap = HeaderMap::new(); + for (k, v) in self.headers_keypairs { + headermap.insert( + HeaderName::try_from(k).unwrap(), + HeaderValue::try_from(v).unwrap(), + ); + } + let json_resp = Json(json!({"error" : format!("{:#}", self.error)})); + + (status, headermap, json_resp).into_response() + } +} + +// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into +// `Result<_, AppError>`. That way you don't need to do that manually. +impl From for ErrorResponse +where + E: Into, +{ + fn from(err: E) -> Self { + Self { + error: err.into(), + headers_keypairs: vec![], + status_code: None, + } + } +} + +#[derive(Debug)] +pub struct Chain { + pub rpc_url: String, + pub contract_address: Address, +} + +#[derive(Deserialize)] +pub struct IndexStruct { + pub index: u32, +} + +#[derive(Deserialize)] +pub struct ProofQueryStruct { + pub index: u32, + pub block_hash: B256, +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct KateQueryDataProofResponse { + pub data_proof: DataProof, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DataProof { + pub roots: Roots, + pub proof: Vec, + pub leaf_index: u32, + pub leaf: B256, +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Roots { + pub data_root: B256, + pub blob_root: B256, + pub bridge_root: B256, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AccountStorageProofResponse { + pub account_proof: Vec, + pub storage_proof: Vec, +} + +#[derive(Deserialize)] +pub struct StorageProof { + pub proof: Vec, +} + +#[derive(Deserialize)] +pub struct MekrleProofAPIResponse { + pub data: Option, + pub error: Option, + pub success: Option, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SlotMappingResponse { + pub block_hash: String, + pub block_number: String, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MerkleProofData { + pub range_hash: B256, + pub data_commitment: B256, + pub merkle_branch: Vec, + pub index: u16, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AggregatedResponse { + pub data_root_proof: Vec, + pub leaf_proof: Vec, + pub range_hash: B256, + pub data_root_index: u16, + pub leaf: B256, + pub leaf_index: u32, + pub data_root: B256, + pub blob_root: B256, + pub bridge_root: B256, + pub data_root_commitment: B256, + pub block_hash: B256, + pub message: Option, +} + +impl AggregatedResponse { + pub fn new( + range_data: MerkleProofData, + data_proof_res: KateQueryDataProofResponse, + hash: B256, + ) -> Self { + AggregatedResponse { + data_root_proof: range_data.merkle_branch, + leaf_proof: data_proof_res.data_proof.proof, + range_hash: range_data.range_hash, + data_root_index: range_data.index, + leaf: data_proof_res.data_proof.leaf, + leaf_index: data_proof_res.data_proof.leaf_index, + data_root: data_proof_res.data_proof.roots.data_root, + blob_root: data_proof_res.data_proof.roots.blob_root, + bridge_root: data_proof_res.data_proof.roots.bridge_root, + data_root_commitment: range_data.data_commitment, + block_hash: hash, + message: data_proof_res.message, + } + } +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct EthProofResponse { + pub account_proof: Vec, + pub storage_proof: Vec, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HeadResponseV2 { + pub slot: u64, + pub block_number: u64, + pub block_hash: B256, + pub timestamp: u64, + pub timestamp_diff: u64, +} + +#[derive(Serialize, Deserialize)] +pub struct ChainHeadResponse { + pub head: u32, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RangeBlocks { + start: u32, + end: u32, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RangeBlocksAPIResponse { + data: RangeBlocks, +} + +#[derive(Debug, Deserialize)] +pub struct HeaderBlockNumber { + #[serde(deserialize_with = "hex_to_u32")] + pub number: u32, +} + +fn hex_to_u32<'de, D>(deserializer: D) -> anyhow::Result +where + D: Deserializer<'de>, +{ + let s: &str = Deserialize::deserialize(deserializer)?; + u32::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom) +} + #[derive(Debug, Clone, PartialEq, FromSqlRow, AsExpression, Eq)] #[diesel(sql_type = Status)] #[derive(Serialize, Deserialize)] From 38e283e27d57fef5f68beb3c974f11e12ded100a Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Fri, 24 Oct 2025 11:52:47 +0200 Subject: [PATCH 3/7] Update deps. --- Cargo.lock | 421 ++++++++++++++++++++++++++++++++++++++--------------- Cargo.toml | 9 +- 2 files changed, 304 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 766d0d8..ab79b45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,9 +102,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6f38130b8716f18c69cede2b8ebe6cf70038a3d97740907bb0637941f759be" +checksum = "ae62e633fa48b4190af5e841eb05179841bb8b713945103291e2c0867037c0d1" dependencies = [ "alloy-consensus", "alloy-contract", @@ -120,6 +120,7 @@ dependencies = [ "alloy-signer-local", "alloy-transport", "alloy-transport-http", + "alloy-trie", ] [[package]] @@ -135,15 +136,16 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7329eb72d95576dfb8813175bcf671198fb24266b0b3e520052a513e30c284df" +checksum = "b9b151e38e42f1586a01369ec52a6934702731d07e8509a7307331b09f6c46dc" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-trie", + "alloy-tx-macros", "auto_impl", "c-kzg", "derive_more 2.0.1", @@ -153,15 +155,16 @@ dependencies = [ "rand 0.8.5", "secp256k1 0.30.0", "serde", + "serde_json", "serde_with", "thiserror 2.0.11", ] [[package]] name = "alloy-consensus-any" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31b286aeef04a32720c10defd21c3aa6c626154ac442b55f6d472caeb1c6741" +checksum = "6e2d5e8668ef6215efdb7dcca6f22277b4e483a5650e05f5de22b2350971f4b8" dependencies = [ "alloy-consensus", "alloy-eips", @@ -173,9 +176,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1658352ca9425d7b5bbb3ae364bc276ab18d4afae06f5faf00377b6964fdf68" +checksum = "630288cf4f3a34a8c6bc75c03dce1dbd47833138f65f37d53a1661eafc96b83f" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -189,14 +192,15 @@ dependencies = [ "alloy-transport", "futures", "futures-util", + "serde_json", "thiserror 2.0.11", ] [[package]] name = "alloy-core" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c5a28f166629752f2e7246b813cdea3243cca59aab2d4264b1fd68392c10eb" +checksum = "5ca96214615ec8cf3fa2a54b32f486eb49100ca7fe7eb0b8c1137cd316e7250a" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -207,9 +211,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6" +checksum = "3fdff496dd4e98a81f4861e66f7eaf5f2488971848bb42d9c892f871730245c8" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -259,9 +263,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa190bfa5340aee544ac831114876fa73bc8da487095b49a5ea153a6a4656ea" +checksum = "e5434834adaf64fa20a6fb90877bc1d33214c41b055cc49f82189c98614368cc" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -274,27 +278,30 @@ dependencies = [ "derive_more 2.0.1", "either", "serde", + "serde_with", "sha2 0.10.8", + "thiserror 2.0.11", ] [[package]] name = "alloy-genesis" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b81b2dfd278d58af8bfde8753fa4685407ba8fbad8bc88a2bb0e065eed48478" +checksum = "919a8471cfbed7bcd8cf1197a57dda583ce0e10c6385f6ff4e8b41304b223392" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-serde", "alloy-trie", "serde", + "serde_with", ] [[package]] name = "alloy-json-abi" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" +checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -304,12 +311,13 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ab2dba5dca01ad4281b4d4726a18e2012a20e3950bfc2a90c5376840555366" +checksum = "d7c69f6c9c68a1287c9d5ff903d0010726934de0dac10989be37b75a29190d55" dependencies = [ "alloy-primitives", "alloy-sol-types", + "http", "serde", "serde_json", "thiserror 2.0.11", @@ -318,9 +326,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ed07e76fbc72790a911ea100cdfbe85b1f12a097c91b948042e854959d140e" +checksum = "8eaf2ae05219e73e0979cb2cf55612aafbab191d130f203079805eaf881cca58" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -344,9 +352,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05aa52713c376f797b3c7077708585f22a5c3053a7b1b2b355ea98edeb2052d" +checksum = "e58f4f345cef483eab7374f2b6056973c7419ffe8ad35e994b7a7f5d8e0c7ba4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -357,17 +365,17 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8" +checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more 2.0.1", - "foldhash", - "hashbrown 0.15.2", + "foldhash 0.2.0", + "hashbrown 0.16.0", "indexmap 2.7.0", "itoa", "k256", @@ -384,9 +392,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a3f7a59c276c6e410267e77a166f9297dbe74e4605f1abf625e29d85c53144" +checksum = "de2597751539b1cc8fe4204e5325f9a9ed83fcacfb212018dfcfa7877e76de21" dependencies = [ "alloy-chains", "alloy-consensus", @@ -445,15 +453,14 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f185483536cbcbf55971077140e03548dad4f3a4ddb35044bcdc01b8f02ce1" +checksum = "edf8eb8be597cfa8c312934d2566ec4516f066d69164f9212d7a148979fdcfd8" dependencies = [ "alloy-json-rpc", "alloy-primitives", "alloy-transport", "alloy-transport-http", - "async-stream", "futures", "pin-project", "reqwest", @@ -463,16 +470,15 @@ dependencies = [ "tokio-stream", "tower", "tracing", - "tracing-futures", "url", "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "347dfd77ba4d74886dba9e2872ff64fb246001b08868d27baec94e7248503e08" +checksum = "339af7336571dd39ae3a15bde08ae6a647e62f75350bd415832640268af92c06" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -482,9 +488,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67971a228100ac65bd86e90439028853435f21796330ef08f00a70a918a84126" +checksum = "fbde0801a32d21c5f111f037bee7e22874836fba7add34ed4a6919932dd7cf23" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -493,9 +499,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d9b4293dfd4721781d33ee40de060376932d4a55d421cf6618ad66ff97cc52" +checksum = "361cd87ead4ba7659bda8127902eda92d17fa7ceb18aba1676f7be10f7222487" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -508,14 +514,15 @@ dependencies = [ "itertools 0.13.0", "serde", "serde_json", + "serde_with", "thiserror 2.0.11", ] [[package]] name = "alloy-serde" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7d927aa39ca51545ae4c9cf4bdb2cbc1f6b46ab4b54afc3ed9255f93eedbce" +checksum = "64600fc6c312b7e0ba76f73a381059af044f4f21f43e07f51f1fa76c868fe302" dependencies = [ "alloy-primitives", "serde", @@ -524,9 +531,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63771b50008d2b079187e9e74a08235ab16ecaf4609b4eb895e2890a3bcd465" +checksum = "5772858492b26f780468ae693405f895d6a27dea6e3eab2c36b6217de47c2647" dependencies = [ "alloy-primitives", "async-trait", @@ -539,9 +546,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db906294ee7876bd332cd760f460d30de183554434e07fc19d7d54e16a7aeaf0" +checksum = "f4195b803d0a992d8dbaab2ca1986fc86533d4bc80967c0cce7668b26ad99ef9" dependencies = [ "alloy-consensus", "alloy-network", @@ -555,9 +562,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383" +checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -569,9 +576,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74" +checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -588,9 +595,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "alloy-json-abi", "const-hex", @@ -606,9 +613,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", "winnow 0.7.10", @@ -616,9 +623,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" +checksum = "70319350969a3af119da6fb3e9bddb1bce66c9ea933600cb297c8b1850ad2a3c" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -628,12 +635,13 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9b645fe4f4e6582cfbb4a8d20cedcf5aa23548e92eacbdacac6278b425e023" +checksum = "025a940182bddaeb594c26fe3728525ae262d0806fe6a4befdf5d7bc13d54bce" dependencies = [ "alloy-json-rpc", "alloy-primitives", + "auto_impl", "base64 0.22.1", "derive_more 2.0.1", "futures", @@ -651,9 +659,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.0.7" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee18869ecabe658ff6316e7db7c25d958c7d10f0a1723c2f7447d4f402920b66" +checksum = "e3b5064d1e1e1aabc918b5954e7fb8154c39e77ec6903a581b973198b26628fa" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -666,9 +674,9 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983d99aa81f586cef9dae38443245e585840fcf0fc58b09aee0b1f27aed1d500" +checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -680,6 +688,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-tx-macros" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8e52276fdb553d3c11563afad2898f4085165e4093604afe3d78b69afbf408f" +dependencies = [ + "alloy-primitives", + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -1383,11 +1404,12 @@ dependencies = [ [[package]] name = "backon" -version = "0.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e5b65cc81d81fbb8488f36458ab4771be35a722967bbc959df28b47397e3ff" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ "fastrand", + "gloo-timers", "tokio", ] @@ -1628,7 +1650,6 @@ dependencies = [ "backon", "chrono", "diesel", - "diesel-enum", "dotenvy", "http", "jsonrpsee", @@ -1749,6 +1770,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.39" @@ -2043,8 +2070,18 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] @@ -2061,13 +2098,39 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.101", +] + [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core", + "darling_core 0.20.10", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", "quote", "syn 2.0.101", ] @@ -2206,17 +2269,6 @@ dependencies = [ "r2d2", ] -[[package]] -name = "diesel-enum" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b8470493d7120fd53f7d7db6ad167c2bc06fdf8abb3cef7e7669eb1347b415" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "diesel_derives" version = "2.2.3" @@ -2326,7 +2378,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" dependencies = [ - "darling", + "darling 0.20.10", "either", "heck", "proc-macro2", @@ -2671,6 +2723,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2924,8 +2982,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -2935,9 +2995,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -2973,6 +3035,18 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.13.0" @@ -3054,7 +3128,16 @@ checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.4", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "foldhash 0.2.0", "serde", ] @@ -3216,6 +3299,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots 1.0.3", ] [[package]] @@ -3613,9 +3697,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fba77a59c4c644fd48732367624d1bcf6f409f9c9a286fbc71d2f1fc0b2ea16" +checksum = "3f3f48dc3e6b8bd21e15436c1ddd0bc22a6a54e8ec46fedd6adf3425f396ec6a" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -3626,9 +3710,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693c93cbb7db25f4108ed121304b671a36002c2db67dff2ee4391a688c738547" +checksum = "316c96719901f05d1137f19ba598b5fe9c9bc39f4335f67f6be8613921946480" dependencies = [ "async-trait", "bytes", @@ -3651,9 +3735,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6962d2bd295f75e97dd328891e58fce166894b974c1f7ce2e7597f02eeceb791" +checksum = "790bedefcec85321e007ff3af84b4e417540d5c87b3c9779b9e247d1bcc3dab8" dependencies = [ "base64 0.22.1", "http-body", @@ -3674,9 +3758,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fa4f5daed39f982a1bb9d15449a28347490ad42b212f8eaa2a2a344a0dce9e9" +checksum = "2da3f8ab5ce1bb124b6d082e62dffe997578ceaf0aeb9f3174a214589dc00f07" dependencies = [ "heck", "proc-macro-crate", @@ -3687,9 +3771,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66df7256371c45621b3b7d2fb23aea923d577616b9c0e9c0b950a6ea5c2be0ca" +checksum = "bc88ff4688e43cc3fa9883a8a95c6fa27aa2e76c96e610b737b6554d650d7fd5" dependencies = [ "http", "serde", @@ -3842,6 +3926,12 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mach" version = "0.3.2" @@ -4115,13 +4205,14 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.3.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", - "const-hex", + "cfg-if", "proptest", + "ruint", "serde", "smallvec", ] @@ -4622,6 +4713,61 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.1", + "ring 0.17.8", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.38" @@ -4852,7 +4998,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -4860,6 +5009,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-service", @@ -4867,6 +5017,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.26.11", "windows-registry", ] @@ -4923,13 +5074,14 @@ dependencies = [ [[package]] name = "ruint" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" +checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", + "ark-ff 0.5.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -4943,7 +5095,7 @@ dependencies = [ "rand 0.9.1", "rlp", "ruint-macro", - "serde", + "serde_core", "valuable", "zeroize", ] @@ -5059,6 +5211,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ + "web-time", "zeroize", ] @@ -5338,10 +5491,11 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -5354,11 +5508,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -5367,14 +5530,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -5432,7 +5596,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling", + "darling 0.20.10", "proc-macro2", "quote", "syn 2.0.101", @@ -6573,9 +6737,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.1.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", @@ -6948,9 +7112,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "async-compression", "bitflags 2.8.0", @@ -6958,7 +7122,6 @@ dependencies = [ "futures-core", "http", "http-body", - "http-body-util", "pin-project-lite", "tokio", "tokio-util", @@ -7012,18 +7175,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "futures", - "futures-task", - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.4" @@ -7570,6 +7721,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-root-certs" version = "0.26.11" @@ -7588,6 +7749,24 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.3", +] + +[[package]] +name = "webpki-roots" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 017aa5b..d4dd96b 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,27 +10,26 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -alloy = { version = "1", features = ["serde", "json"] } +alloy = { version = "1.0.27", features = ["serde", "json"] } axum = { version = "0.8", features = ["http2", "macros", "tracing"] } dotenvy = "0.15" -jsonrpsee = { version = "0.25", features = ["http-client", "macros", "async-client"] } +jsonrpsee = { version = "0.26.0", features = ["http-client", "macros", "async-client"] } reqwest = { version = "0.12", features = ["json", "brotli"] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["arbitrary_precision"] } sha3 = "0.10" tokio = { version = "1.35", features = ["macros", "rt-multi-thread", "parking_lot"] } -tower-http = { version = "0.5", features = ["trace", "compression-br", "cors"] } +tower-http = { version = "0.6.6", features = ["trace", "compression-br", "cors"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } sp-io = "34.0" sp-core = "34.0" avail-core = { git = "https://github.com/availproject/avail-core", tag = "core-node-3"} http = "1.1" -backon = { version = "0.5", features = ["tokio-sleep"] } +backon = { version = "1.5.2", features = ["tokio-sleep"] } anyhow = "1" lazy_static = "1.5" diesel = { version = "2.2", features = ["postgres", "chrono", "r2d2"] } -diesel-enum = "0.2.1" serde_with = "3.11.0" chrono = { version = "0.4", features = ["serde"] } From 2c77fe56547e5ec941dda915bdcbb90cfd352064 Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Fri, 24 Oct 2025 12:04:24 +0200 Subject: [PATCH 4/7] Move skipped models. --- src/main.rs | 80 -------------------------------------------------- src/models.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 80 deletions(-) diff --git a/src/main.rs b/src/main.rs index 886c4aa..d41f7b5 100755 --- a/src/main.rs +++ b/src/main.rs @@ -100,86 +100,6 @@ async fn versions(State(_state): State>) -> Result, St Ok(Json(json!(["v1"]))) } -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct TransactionQueryParams { - eth_address: Option, - avail_address: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde_as] -#[serde(rename_all = "camelCase")] -pub struct TransactionData { - pub message_id: i64, - pub status: StatusEnum, - pub source_transaction_hash: String, - pub source_block_number: i64, - pub source_block_hash: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub source_transaction_index: Option, - #[serde_as(as = "TimestampSeconds")] - pub source_timestamp: NaiveDateTime, - pub token_id: String, - pub destination_block_number: Option, - pub destination_block_hash: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub destination_transaction_index: Option, - #[serde_as(as = "Option")] - pub destination_timestamp: Option, - pub depositor_address: String, - pub receiver_address: String, - pub amount: String, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TransactionResult { - pub avail_send: Vec, - pub eth_send: Vec, -} - -fn map_ethereum_send_to_transaction_result(send: EthereumSend) -> TransactionData { - TransactionData { - message_id: send.message_id, - status: send.status, - source_transaction_hash: send.source_transaction_hash, - source_block_number: send.source_block_number, - source_block_hash: send.source_block_hash, - source_transaction_index: None, - source_timestamp: send.source_timestamp, - token_id: send.token_id, - destination_block_number: send.destination_block_number, - destination_block_hash: send.destination_block_hash, - destination_transaction_index: send.destination_transaction_index, - destination_timestamp: send.destination_timestamp, - depositor_address: send.depositor_address, - receiver_address: send.receiver_address, - amount: send.amount, - } -} - -// Function to map AvailSend to TransactionResult -fn map_avail_send_to_transaction_result(send: AvailSend) -> TransactionData { - TransactionData { - message_id: send.message_id, - status: send.status, - source_transaction_hash: send.source_transaction_hash, - source_block_number: send.source_block_number, - source_block_hash: send.source_block_hash, - source_transaction_index: Some(send.source_transaction_index), - source_timestamp: send.source_timestamp, - token_id: send.token_id, - destination_block_number: send.destination_block_number, - destination_block_hash: send.destination_block_hash, - destination_transaction_index: None, - destination_timestamp: send.destination_timestamp, - depositor_address: send.depositor_address, - receiver_address: send.receiver_address, - amount: send.amount, - } -} - #[inline(always)] async fn transactions( Query(address_query): Query, diff --git a/src/models.rs b/src/models.rs index b71b491..0359ddb 100644 --- a/src/models.rs +++ b/src/models.rs @@ -18,6 +18,7 @@ use jsonrpsee::core::Serialize; use serde::{Deserialize, Deserializer}; use serde_json::json; use serde_with::serde_as; +use sp_core::{H160, H256}; use std::io::Write; sol!( @@ -380,3 +381,83 @@ pub struct EthereumSend { pub receiver_address: String, pub amount: String, } + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionQueryParams { + pub eth_address: Option, + pub avail_address: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde_as] +#[serde(rename_all = "camelCase")] +pub struct TransactionData { + pub message_id: i64, + pub status: StatusEnum, + pub source_transaction_hash: String, + pub source_block_number: i64, + pub source_block_hash: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub source_transaction_index: Option, + #[serde_as(as = "TimestampSeconds")] + pub source_timestamp: NaiveDateTime, + pub token_id: String, + pub destination_block_number: Option, + pub destination_block_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub destination_transaction_index: Option, + #[serde_as(as = "Option")] + pub destination_timestamp: Option, + pub depositor_address: String, + pub receiver_address: String, + pub amount: String, +} + +#[derive(Debug, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionResult { + pub avail_send: Vec, + pub eth_send: Vec, +} + +pub fn map_ethereum_send_to_transaction_result(send: EthereumSend) -> TransactionData { + TransactionData { + message_id: send.message_id, + status: send.status, + source_transaction_hash: send.source_transaction_hash, + source_block_number: send.source_block_number, + source_block_hash: send.source_block_hash, + source_transaction_index: None, + source_timestamp: send.source_timestamp, + token_id: send.token_id, + destination_block_number: send.destination_block_number, + destination_block_hash: send.destination_block_hash, + destination_transaction_index: send.destination_transaction_index, + destination_timestamp: send.destination_timestamp, + depositor_address: send.depositor_address, + receiver_address: send.receiver_address, + amount: send.amount, + } +} + +// Function to map AvailSend to TransactionResult +pub fn map_avail_send_to_transaction_result(send: AvailSend) -> TransactionData { + TransactionData { + message_id: send.message_id, + status: send.status, + source_transaction_hash: send.source_transaction_hash, + source_block_number: send.source_block_number, + source_block_hash: send.source_block_hash, + source_transaction_index: Some(send.source_transaction_index), + source_timestamp: send.source_timestamp, + token_id: send.token_id, + destination_block_number: send.destination_block_number, + destination_block_hash: send.destination_block_hash, + destination_transaction_index: None, + destination_timestamp: send.destination_timestamp, + depositor_address: send.depositor_address, + receiver_address: send.receiver_address, + amount: send.amount, + } +} From 91ee37ece399cc95dae8b30737a7780b191d85cc Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Tue, 28 Oct 2025 12:40:39 +0100 Subject: [PATCH 5/7] Add eth fetch tx. --- src/main.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index d41f7b5..6d76cb3 100755 --- a/src/main.rs +++ b/src/main.rs @@ -5,11 +5,13 @@ use crate::models::*; use crate::schema::avail_sends::dsl::avail_sends; use crate::schema::ethereum_sends::dsl::ethereum_sends; +use alloy::consensus::transaction::TxHashable; use alloy::primitives::{Address, B256, U256, hex}; use alloy::providers::ProviderBuilder; use anyhow::{Context, Result, anyhow}; use axum::body::{Body, to_bytes}; use axum::response::Response; +use axum::routing::post; use axum::{ Router, extract::{Json, Path, Query, State}, @@ -40,7 +42,6 @@ use sha3::{Digest, Keccak256}; use sp_core::{Decode, H160, H256}; use sp_io::hashing::twox_128; use std::collections::HashMap; -use std::sync::Arc; use std::{env, process, time::Duration}; #[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; @@ -53,6 +54,8 @@ use tower_http::{ }; use tracing_subscriber::prelude::*; +use alloy::rpc::types::Transaction; +use std::sync::{Arc, Mutex}; #[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; @@ -85,6 +88,39 @@ async fn alive() -> Result, StatusCode> { Ok(Json(json!({ "name": "Avail Bridge API" }))) } +#[inline(always)] +async fn transaction( + State(state): State>, + Path(hash): Path, +) -> Result { + + // fetch details of the eth transaction + let resp: Result = state + .ethereum_client + .request("eth_getTransactionByHash", rpc_params![hash]) + .await; + + let tx: Transaction = resp.map_err(|e| { + tracing::error!("❌ Cannot get transaction: {e:#}"); + if e.to_string().ends_with("status code: 429") { + ErrorResponse::with_status_and_headers( + e.into(), + StatusCode::TOO_MANY_REQUESTS, + &[("Cache-Control", "public, max-age=60, must-revalidate")], + ) + } else { + ErrorResponse::with_status_and_headers( + e.into(), + StatusCode::INTERNAL_SERVER_ERROR, + &[("Cache-Control", "public, max-age=60, must-revalidate")], + ) + } + })?; + + + Ok(Json(json!({ "transaction": tx }))) +} + #[inline(always)] async fn info(State(state): State>) -> Result, StatusCode> { Ok(Json(json!({ @@ -818,19 +854,19 @@ async fn main() { let app = Router::new() .route("/", get(alive)) .route("/versions", get(versions)) - .route("/info", get(info)) .route("/v1/info", get(info)) - .route("/v1/eth/proof/{block_hash}", get(get_eth_proof)) - .route("/v1/eth/head", get(get_eth_head)) - .route("/v1/avl/head", get(get_avl_head)) + .route("/v2/transaction/{txHash}", post(transaction)) + .route("/v1/eth/proof/{block_hash}", get(get_eth_proof)) // get proof from avail for ethereum + .route("/v1/eth/head", get(get_eth_head)) // fetch head form eth contract + .route("/v1/avl/head", get(get_avl_head)) // fetch head form avail pallet .route( "/v1/avl/proof/{block_hash}/{message_id}", - get(get_avl_proof), + get(get_avl_proof), // get proof from ethereum for avail ) - .route("/v1/transactions", get(transactions)) + .route("/v1/transactions", get(transactions)) // fetch all transaction .route("/transactions", get(transactions)) - .route("/v1/head/{chain_id}", get(get_head)) - .route("/v1/proof/{chain_id}", get(get_proof)) + .route("/v1/head/{chain_id}", get(get_head)) // get head based on chain + .route("/v1/proof/{chain_id}", get(get_proof)) // get proof for avail based on chain .layer(TraceLayer::new_for_http()) .layer(CompressionLayer::new()) .layer( From 76b4cfe60762d73a32ea1bd533d19084b9b036ff Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Wed, 29 Oct 2025 15:45:23 +0100 Subject: [PATCH 6/7] Add endpoint to insert tx. --- Cargo.lock | 562 +++++++++++++++++++++++++++++++++++++------- Cargo.toml | 4 +- docker-compose.yaml | 17 ++ src/main.rs | 226 ++++++++++-------- src/models.rs | 109 ++++----- src/schema.rs | 79 ------- 6 files changed, 678 insertions(+), 319 deletions(-) create mode 100644 docker-compose.yaml delete mode 100644 src/schema.rs diff --git a/Cargo.lock b/Cargo.lock index ab79b45..8b7cd0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1285,6 +1285,15 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1564,6 +1573,9 @@ name = "bitflags" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] [[package]] name = "bitvec" @@ -1649,7 +1661,6 @@ dependencies = [ "axum", "backon", "chrono", - "diesel", "dotenvy", "http", "jsonrpsee", @@ -1661,6 +1672,7 @@ dependencies = [ "sha3", "sp-core 34.0.0", "sp-io 34.0.0", + "sqlx", "tikv-jemallocator", "tokio", "tower-http", @@ -1822,6 +1834,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-hex" version = "1.14.0" @@ -1969,6 +1990,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -2156,6 +2186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -2254,43 +2285,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "diesel" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" -dependencies = [ - "bitflags 2.8.0", - "byteorder", - "chrono", - "diesel_derives", - "itoa", - "pq-sys", - "r2d2", -] - -[[package]] -name = "diesel_derives" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" -dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.101", -] - [[package]] name = "digest" version = "0.9.0" @@ -2372,20 +2366,6 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" -[[package]] -name = "dsl_auto_type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" -dependencies = [ - "darling 0.20.10", - "either", - "heck", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "dunce" version = "1.0.5" @@ -2579,6 +2559,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "ethabi-decode" version = "2.0.0" @@ -2611,6 +2602,17 @@ dependencies = [ "uint 0.10.0", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "expander" version = "2.2.1" @@ -2711,6 +2713,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2905,6 +2918,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -3141,6 +3165,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "heck" version = "0.5.0" @@ -3177,6 +3210,15 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.8.1" @@ -3217,6 +3259,15 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "http" version = "1.2.0" @@ -3819,6 +3870,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -3832,6 +3886,17 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.8.0", + "libc", + "redox_syscall", +] + [[package]] name = "libsecp256k1" version = "0.7.1" @@ -3880,6 +3945,16 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -4024,6 +4099,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.7.4" @@ -4138,6 +4223,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -4163,6 +4265,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -4346,6 +4459,12 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -4405,6 +4524,15 @@ dependencies = [ "password-hash", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -4454,6 +4582,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -4559,15 +4698,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "pq-sys" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cc05d7ea95200187117196eee9edd0644424911821aeb28a18ce60ea0b8793" -dependencies = [ - "vcpkg", -] - [[package]] name = "prettyplease" version = "0.2.29" @@ -4783,17 +4913,6 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - [[package]] name = "radium" version = "0.7.0" @@ -4899,9 +5018,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags 2.8.0", ] @@ -5072,6 +5191,26 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "ruint" version = "1.17.0" @@ -5321,15 +5460,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "schnellru" version = "0.2.4" @@ -5612,6 +5742,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.9.9" @@ -6615,6 +6756,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -6626,6 +6770,200 @@ dependencies = [ "der", ] +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.2", + "hashlink", + "indexmap 2.7.0", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.8", + "smallvec", + "thiserror 2.0.11", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.101", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.101", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.8.0", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac 0.12.1", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.11", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.8.0", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.11", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.11", + "tracing", + "url", +] + [[package]] name = "ss58-registry" version = "1.51.0" @@ -6653,6 +6991,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -7349,6 +7698,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.14" @@ -7364,6 +7719,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -7484,6 +7845,12 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -7767,6 +8134,16 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + [[package]] name = "winapi" version = "0.3.9" @@ -7813,6 +8190,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-registry" version = "0.4.0" @@ -7830,7 +8213,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.1", ] [[package]] @@ -7839,7 +8222,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link", + "windows-link 0.1.1", ] [[package]] @@ -7878,6 +8261,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.42.2" diff --git a/Cargo.toml b/Cargo.toml index d4dd96b..2121527 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,10 +29,10 @@ http = "1.1" backon = { version = "1.5.2", features = ["tokio-sleep"] } anyhow = "1" lazy_static = "1.5" -diesel = { version = "2.2", features = ["postgres", "chrono", "r2d2"] } serde_with = "3.11.0" chrono = { version = "0.4", features = ["serde"] } - +sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-rustls", "macros", "chrono"] } +#alloy-rpc-types ="1.0.27" [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = "0.6" diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..472cf3d --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,17 @@ +version: '3' + +services: + db: + image: postgres:latest + container_name: bridge-api + environment: + POSTGRES_USER: avail + POSTGRES_PASSWORD: avail + POSTGRES_DB: ui-indexer + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: diff --git a/src/main.rs b/src/main.rs index 6d76cb3..c67820c 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,7 @@ mod models; -mod schema; - use crate::models::*; -use crate::schema::avail_sends::dsl::avail_sends; -use crate::schema::ethereum_sends::dsl::ethereum_sends; -use alloy::consensus::transaction::TxHashable; +use alloy::consensus::transaction::{Recovered, TxHashable}; use alloy::primitives::{Address, B256, U256, hex}; use alloy::providers::ProviderBuilder; use anyhow::{Context, Result, anyhow}; @@ -22,10 +18,7 @@ use axum::{ use backon::ExponentialBuilder; use backon::Retryable; use chrono::{NaiveDateTime, Utc}; -use diesel::{ - ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl, SelectableHelper, r2d2, - r2d2::ConnectionManager, -}; + use http::Method; use jsonrpsee::{ core::ClientError, @@ -54,8 +47,23 @@ use tower_http::{ }; use tracing_subscriber::prelude::*; +use crate::models::StatusEnum::{InProgress, Initialized}; +use alloy::consensus::TxEnvelope; +use alloy::core::sol; +use alloy::hex::{ToHex, ToHexExt}; +use alloy::network::TransactionResponse; use alloy::rpc::types::Transaction; +use sqlx::{FromRow, PgPool, Pool, Postgres, Row, query}; use std::sync::{Arc, Mutex}; +use tracing::log::__private_api::log; +use tracing::log::info; +use tracing::warn; +// sol! { +// contract AvailBridge { +// function sendAVAIL(bytes32 recipient,uint256 amount) +// } +// } + #[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; @@ -80,7 +88,7 @@ pub struct AppState { pub eth_proof_failure_cache_maxage: u32, pub slot_mapping_cache_maxage: u32, pub transactions_cache_maxage: u32, - pub connection_pool: r2d2::Pool>, + pub db: PgPool, pub chains: HashMap, } @@ -93,14 +101,13 @@ async fn transaction( State(state): State>, Path(hash): Path, ) -> Result { - // fetch details of the eth transaction - let resp: Result = state + let resp: Result = state .ethereum_client .request("eth_getTransactionByHash", rpc_params![hash]) .await; - let tx: Transaction = resp.map_err(|e| { + let tx: TransactionRpc = resp.map_err(|e| { tracing::error!("❌ Cannot get transaction: {e:#}"); if e.to_string().ends_with("status code: 429") { ErrorResponse::with_status_and_headers( @@ -117,8 +124,30 @@ async fn transaction( } })?; + let recipient = &tx.input[10..74]; + let amount = &tx.input[74..]; + + query("INSERT INTO ethereum_sends (message_id, status, source_transaction_hash, source_block_number, source_block_hash, + source_timestamp, depositor_address, receiver_address, amount) VALUES( + $1, $2, $3, $4, $5, $6, $7, $8, $9)") + .bind(1) + .bind(Initialized) + .bind(tx.hash) + .bind(tx.block_number as i64) + .bind(tx.block_hash) + .bind(Utc::now()) + .bind(tx.from) + .bind(format!("0x{}",recipient)) + .bind(amount) + .execute(&state.db) + .await + .map_err(|e|{ + warn!("Cannot insert tx {}", e); + return anyhow!("Cannot insert tx"); + } + )?; - Ok(Json(json!({ "transaction": tx }))) + Ok(()) } #[inline(always)] @@ -141,81 +170,83 @@ async fn transactions( Query(address_query): Query, State(state): State>, ) -> Result { - if address_query.eth_address.is_none() && address_query.avail_address.is_none() { - tracing::error!("Query params not provided."); - return Err(ErrorResponse::with_status_and_headers( - anyhow!("Invalid request: Query params not provided"), - StatusCode::BAD_REQUEST, - &[("Cache-Control", "max-age=60, must-revalidate")], - )); - } + // if address_query.eth_address.is_none() && address_query.avail_address.is_none() { + // tracing::error!("Query params not provided."); + // return Err(ErrorResponse::with_status_and_headers( + // anyhow!("Invalid request: Query params not provided"), + // StatusCode::BAD_REQUEST, + // &[("Cache-Control", "max-age=60, must-revalidate")], + // )); + // } + // + // let cloned_state = state.clone(); + // let mut conn = cloned_state + // .connection_pool + // .get_timeout(Duration::from_secs(1)) + // .expect("Get connection pool"); + // + // // Initialize the result variables + // let mut transaction_results: TransactionResult = TransactionResult::default(); + // + // // Return the combined results + // if let Some(eth_address) = address_query.eth_address { + // let ethereum_sends_results = ethereum_sends + // .select(EthereumSend::as_select()) + // .filter(schema::ethereum_sends::depositor_address.eq(format!("{:?}", eth_address))) + // .order_by(schema::ethereum_sends::source_timestamp.desc()) + // .limit(500) + // .load::(&mut conn); + // + // transaction_results.eth_send = ethereum_sends_results + // .map_err(|e| { + // tracing::error!("Cannot get ethereum send transactions:: {e:#}"); + // ErrorResponse::with_status_and_headers( + // e.into(), + // StatusCode::INTERNAL_SERVER_ERROR, + // &[("Cache-Control", "public, max-age=60, must-revalidate")], + // ) + // })? + // .into_iter() + // .map(map_ethereum_send_to_transaction_result) + // .collect(); + // } + // + // if let Some(avail_address) = address_query.avail_address { + // let avail_sends_results = avail_sends + // .select(AvailSend::as_select()) + // .filter(schema::avail_sends::depositor_address.eq(format!("{:?}", avail_address))) + // .order_by(schema::avail_sends::source_timestamp.desc()) + // .limit(500) + // .load::(&mut conn); + // + // transaction_results.avail_send = avail_sends_results + // .map_err(|e| { + // tracing::error!("Cannot get avail send transactions: {e:#}"); + // ErrorResponse::with_status_and_headers( + // e.into(), + // StatusCode::INTERNAL_SERVER_ERROR, + // &[("Cache-Control", "public, max-age=60, must-revalidate")], + // ) + // })? + // .into_iter() + // .map(map_avail_send_to_transaction_result) + // .collect(); + // } + // + // Ok(( + // StatusCode::OK, + // [( + // "Cache-Control", + // format!( + // "public, max-age={}, immutable", + // state.transactions_cache_maxage + // ), + // )], + // Json(json!(transaction_results)), + // ) + // .into_response()) - let cloned_state = state.clone(); - let mut conn = cloned_state - .connection_pool - .get_timeout(Duration::from_secs(1)) - .expect("Get connection pool"); - - // Initialize the result variables - let mut transaction_results: TransactionResult = TransactionResult::default(); - - // Return the combined results - if let Some(eth_address) = address_query.eth_address { - let ethereum_sends_results = ethereum_sends - .select(EthereumSend::as_select()) - .filter(schema::ethereum_sends::depositor_address.eq(format!("{:?}", eth_address))) - .order_by(schema::ethereum_sends::source_timestamp.desc()) - .limit(500) - .load::(&mut conn); - - transaction_results.eth_send = ethereum_sends_results - .map_err(|e| { - tracing::error!("Cannot get ethereum send transactions:: {e:#}"); - ErrorResponse::with_status_and_headers( - e.into(), - StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], - ) - })? - .into_iter() - .map(map_ethereum_send_to_transaction_result) - .collect(); - } - - if let Some(avail_address) = address_query.avail_address { - let avail_sends_results = avail_sends - .select(AvailSend::as_select()) - .filter(schema::avail_sends::depositor_address.eq(format!("{:?}", avail_address))) - .order_by(schema::avail_sends::source_timestamp.desc()) - .limit(500) - .load::(&mut conn); - - transaction_results.avail_send = avail_sends_results - .map_err(|e| { - tracing::error!("Cannot get avail send transactions: {e:#}"); - ErrorResponse::with_status_and_headers( - e.into(), - StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], - ) - })? - .into_iter() - .map(map_avail_send_to_transaction_result) - .collect(); - } - - Ok(( - StatusCode::OK, - [( - "Cache-Control", - format!( - "public, max-age={}, immutable", - state.transactions_cache_maxage - ), - )], - Json(json!(transaction_results)), - ) - .into_response()) + Ok(()) } #[inline(always)] @@ -756,14 +787,19 @@ async fn main() { // Connection pool let connections_string = format!( "postgresql://{}:{}@{}/{}", - env::var("PG_USERNAME").unwrap_or("myuser".to_owned()), - env::var("PG_PASSWORD").unwrap_or("mypassword".to_owned()), + env::var("PG_USERNAME").unwrap_or("avail".to_owned()), + env::var("PG_PASSWORD").unwrap_or("avail".to_owned()), env::var("POSTGRES_URL").unwrap_or("localhost:5432".to_owned()), - env::var("POSTGRES_DB").unwrap_or("bridge-ui-indexer".to_owned()), + env::var("POSTGRES_DB").unwrap_or("ui-indexer".to_owned()), ); - let connection_pool = r2d2::Pool::builder() - .build(ConnectionManager::::new(connections_string)) - .expect("Failed to create pool."); + + info!("Connecting to {}", connections_string); + + let db = PgPool::connect(&connections_string) + .await + .context("Cannot get connection pool") + .unwrap(); + const SUPPORTED_CHAIN_IDS: [u64; 7] = [1, 123, 32657, 84532, 11155111, 17000, 421614]; // loop through expected_chain_ids and store the chain information, if value is missing, skip chain_id let chains = SUPPORTED_CHAIN_IDS @@ -847,7 +883,7 @@ async fn main() { transactions_mapping_response.parse::().ok() }) .unwrap_or(60), - connection_pool, + db, chains, }); diff --git a/src/models.rs b/src/models.rs index 0359ddb..596edb5 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,18 +1,10 @@ -use crate::schema::sql_types::Status; use alloy::primitives::{Address, B256}; use alloy::sol; use avail_core::data_proof::AddressedMessage; use axum::Json; use axum::response::{IntoResponse, Response}; use chrono::NaiveDateTime; -use diesel::pg::{Pg, PgValue}; -use diesel::serialize::{IsNull, Output}; -use diesel::{ - deserialize::{self, FromSql}, - expression::AsExpression, - serialize::ToSql, - *, -}; + use http::{HeaderMap, HeaderName, HeaderValue, StatusCode}; use jsonrpsee::core::Serialize; use serde::{Deserialize, Deserializer}; @@ -294,49 +286,46 @@ where u32::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom) } -#[derive(Debug, Clone, PartialEq, FromSqlRow, AsExpression, Eq)] -#[diesel(sql_type = Status)] -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Serialize, Deserialize, sqlx::Type)] +#[sqlx(type_name = "status")] pub enum StatusEnum { + #[sqlx(rename = "INITIALIZED")] + Initialized, + #[sqlx(rename = "IN_PROGRESS")] InProgress, + #[sqlx(rename = "CLAIM_PENDING")] ClaimPending, + #[sqlx(rename = "BRIDGED")] Bridged, } -impl ToSql for StatusEnum { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { - match *self { - StatusEnum::InProgress => out.write_all(b"IN_PROGRESS")?, - StatusEnum::ClaimPending => out.write_all(b"CLAIM_PENDING")?, - StatusEnum::Bridged => out.write_all(b"BRIDGED")?, - } - Ok(IsNull::No) - } -} -impl FromSql for StatusEnum { - fn from_sql(bytes: PgValue<'_>) -> deserialize::Result { - match bytes.as_bytes() { - b"IN_PROGRESS" => Ok(StatusEnum::InProgress), - b"CLAIM_PENDING" => Ok(StatusEnum::ClaimPending), - b"BRIDGED" => Ok(StatusEnum::Bridged), - _ => Err(format!( - "Unrecognized enum variant {}", - std::str::from_utf8(bytes.as_bytes()).unwrap() - ) - .as_str() - .into()), - } - } -} +// impl ToSql for StatusEnum { +// fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { +// match *self { +// StatusEnum::InProgress => out.write_all(b"IN_PROGRESS")?, +// StatusEnum::ClaimPending => out.write_all(b"CLAIM_PENDING")?, +// StatusEnum::Bridged => out.write_all(b"BRIDGED")?, +// } +// Ok(IsNull::No) +// } +// } +// +// impl FromSql for StatusEnum { +// fn from_sql(bytes: PgValue<'_>) -> deserialize::Result { +// match bytes.as_bytes() { +// b"IN_PROGRESS" => Ok(StatusEnum::InProgress), +// b"CLAIM_PENDING" => Ok(StatusEnum::ClaimPending), +// b"BRIDGED" => Ok(StatusEnum::Bridged), +// _ => Err(format!( +// "Unrecognized enum variant {}", +// std::str::from_utf8(bytes.as_bytes()).unwrap() +// ) +// .as_str() +// .into()), +// } +// } +// } -#[derive(Queryable, Selectable, Insertable, Identifiable, Serialize)] -#[serde(rename_all = "camelCase")] -#[diesel(table_name = crate::schema::avail_sends)] -#[diesel(primary_key(message_id))] -#[diesel(check_for_backend(diesel::pg::Pg))] -#[derive(Clone, Debug)] -#[serde_as] pub struct AvailSend { pub message_id: i64, pub status: StatusEnum, @@ -344,38 +333,27 @@ pub struct AvailSend { pub source_block_number: i64, pub source_block_hash: String, pub source_transaction_index: i64, - #[serde_as(as = "TimestampSeconds")] pub source_timestamp: NaiveDateTime, pub token_id: String, pub destination_block_number: Option, pub destination_block_hash: Option, - #[serde_as(as = "Option")] pub destination_timestamp: Option, pub depositor_address: String, pub receiver_address: String, pub amount: String, } -#[derive(Queryable, Selectable, Insertable, Identifiable, Serialize)] -#[serde(rename_all = "camelCase")] -#[diesel(table_name = crate::schema::ethereum_sends)] -#[diesel(primary_key(message_id))] -#[diesel(check_for_backend(diesel::pg::Pg))] -#[derive(Clone, Debug)] -#[serde_as] pub struct EthereumSend { pub message_id: i64, pub status: StatusEnum, pub source_transaction_hash: String, pub source_block_number: i64, pub source_block_hash: String, - #[serde_as(as = "TimestampSeconds")] pub source_timestamp: NaiveDateTime, pub token_id: String, pub destination_block_number: Option, pub destination_block_hash: Option, pub destination_transaction_index: Option, - #[serde_as(as = "Option")] pub destination_timestamp: Option, pub depositor_address: String, pub receiver_address: String, @@ -400,14 +378,12 @@ pub struct TransactionData { pub source_block_hash: String, #[serde(skip_serializing_if = "Option::is_none")] pub source_transaction_index: Option, - #[serde_as(as = "TimestampSeconds")] pub source_timestamp: NaiveDateTime, pub token_id: String, pub destination_block_number: Option, pub destination_block_hash: Option, #[serde(skip_serializing_if = "Option::is_none")] pub destination_transaction_index: Option, - #[serde_as(as = "Option")] pub destination_timestamp: Option, pub depositor_address: String, pub receiver_address: String, @@ -461,3 +437,20 @@ pub fn map_avail_send_to_transaction_result(send: AvailSend) -> TransactionData amount: send.amount, } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionRpc { + pub from: String, + pub to: String, + pub input: String, + pub value: String, + #[serde(deserialize_with = "hex_to_u32")] + pub nonce: u32, + pub block_hash: String, + #[serde(deserialize_with = "hex_to_u32")] + pub block_number: u32, + #[serde(deserialize_with = "hex_to_u32")] + pub transaction_index: u32, + pub hash: String, +} diff --git a/src/schema.rs b/src/schema.rs deleted file mode 100644 index 54dec35..0000000 --- a/src/schema.rs +++ /dev/null @@ -1,79 +0,0 @@ -// @generated automatically by Diesel CLI. - -pub mod sql_types { - #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] - #[diesel(postgres_type(name = "claim_type"))] - pub struct ClaimType; - - #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] - #[diesel(postgres_type(name = "status"))] - pub struct Status; -} - -diesel::table! { - use diesel::sql_types::*; - use super::sql_types::Status; - use super::sql_types::ClaimType; - - avail_sends (message_id) { - message_id -> Int8, - status -> Status, - #[max_length = 66] - source_transaction_hash -> Varchar, - source_block_number -> Int8, - #[max_length = 66] - source_block_hash -> Varchar, - source_transaction_index -> Int8, - source_timestamp -> Timestamp, - #[max_length = 66] - token_id -> Varchar, - #[max_length = 66] - destination_transaction_hash -> Nullable, - destination_block_number -> Nullable, - #[max_length = 66] - destination_block_hash -> Nullable, - destination_timestamp -> Nullable, - #[max_length = 66] - depositor_address -> Varchar, - #[max_length = 22] - receiver_address -> Varchar, - #[max_length = 255] - amount -> Varchar, - claim_type -> ClaimType, - } -} - -diesel::table! { - use diesel::sql_types::*; - use super::sql_types::Status; - use super::sql_types::ClaimType; - - ethereum_sends (message_id) { - message_id -> Int8, - status -> Status, - #[max_length = 66] - source_transaction_hash -> Varchar, - source_block_number -> Int8, - #[max_length = 66] - source_block_hash -> Varchar, - source_timestamp -> Timestamp, - #[max_length = 66] - token_id -> Varchar, - #[max_length = 66] - destination_transaction_hash -> Nullable, - destination_block_number -> Nullable, - #[max_length = 66] - destination_block_hash -> Nullable, - destination_transaction_index-> Nullable, - destination_timestamp -> Nullable, - #[max_length = 66] - depositor_address -> Varchar, - #[max_length = 66] - receiver_address -> Varchar, - #[max_length = 255] - amount -> Varchar, - claim_type -> ClaimType, - } -} - -diesel::allow_tables_to_appear_in_same_query!(avail_sends, ethereum_sends,); From e82067b7817e63829c5c3e0d47ee4ba146c0e859 Mon Sep 17 00:00:00 2001 From: Sasa Prsic Date: Thu, 30 Oct 2025 11:47:43 +0100 Subject: [PATCH 7/7] Fetch tx receipt and get message id. --- src/main.rs | 65 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/main.rs b/src/main.rs index c67820c..58fdced 100755 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ mod models; use crate::models::*; use alloy::consensus::transaction::{Recovered, TxHashable}; -use alloy::primitives::{Address, B256, U256, hex}; +use alloy::primitives::{Address, B256, Log, LogData, U256, hex}; use alloy::providers::ProviderBuilder; use anyhow::{Context, Result, anyhow}; use axum::body::{Body, to_bytes}; @@ -50,14 +50,16 @@ use tracing_subscriber::prelude::*; use crate::models::StatusEnum::{InProgress, Initialized}; use alloy::consensus::TxEnvelope; use alloy::core::sol; -use alloy::hex::{ToHex, ToHexExt}; +use alloy::hex::{FromHex, ToHex, ToHexExt}; use alloy::network::TransactionResponse; -use alloy::rpc::types::Transaction; +use alloy::rpc::types::{Transaction, TransactionReceipt}; use sqlx::{FromRow, PgPool, Pool, Postgres, Row, query}; +use std::str::FromStr; use std::sync::{Arc, Mutex}; use tracing::log::__private_api::log; use tracing::log::info; use tracing::warn; + // sol! { // contract AvailBridge { // function sendAVAIL(bytes32 recipient,uint256 amount) @@ -101,37 +103,56 @@ async fn transaction( State(state): State>, Path(hash): Path, ) -> Result { - // fetch details of the eth transaction - let resp: Result = state + let tx: TransactionRpc = state .ethereum_client .request("eth_getTransactionByHash", rpc_params![hash]) - .await; - - let tx: TransactionRpc = resp.map_err(|e| { - tracing::error!("❌ Cannot get transaction: {e:#}"); - if e.to_string().ends_with("status code: 429") { - ErrorResponse::with_status_and_headers( - e.into(), - StatusCode::TOO_MANY_REQUESTS, - &[("Cache-Control", "public, max-age=60, must-revalidate")], + .await + .map_err(|e| { + tracing::error!("Cannot get transaction: {e:#}"); + ErrorResponse::with_status( + anyhow!("Cannot get transaction"), + StatusCode::INTERNAL_SERVER_ERROR, ) - } else { - ErrorResponse::with_status_and_headers( - e.into(), + })?; + + let receipt: TransactionReceipt = state + .ethereum_client + .request("eth_getTransactionReceipt", rpc_params![hash]) + .await + .map_err(|e| { + tracing::error!("Cannot get transaction receipt: {e:#}"); + ErrorResponse::with_status( + anyhow!("Cannot get transaction receipt"), StatusCode::INTERNAL_SERVER_ERROR, - &[("Cache-Control", "public, max-age=60, must-revalidate")], ) - } - })?; + })?; + + let target_topic = + B256::from_str("0x06fd209663be9278f96bc53dfbf6cf3cdcf2172c38b5de30abff93ba443d653a")?; + + let log_data: LogData = receipt + .inner + .logs() + .iter() + .find(|log| log.topics().contains(&target_topic)) + .map(|log| log.data()) + .unwrap() + .clone(); + + let event_data = U256::from_be_slice(&log_data.data); + // Extract the least-significant 64 bits/should match the message size + let message_id = event_data.as_limbs()[0] as i64; + // recipient must be from a function call data recipient+amount + // sendAVAIL(bytes32 recipient,uint256 amount) let recipient = &tx.input[10..74]; let amount = &tx.input[74..]; query("INSERT INTO ethereum_sends (message_id, status, source_transaction_hash, source_block_number, source_block_hash, source_timestamp, depositor_address, receiver_address, amount) VALUES( $1, $2, $3, $4, $5, $6, $7, $8, $9)") - .bind(1) - .bind(Initialized) + .bind(message_id) + .bind(Initialized) .bind(tx.hash) .bind(tx.block_number as i64) .bind(tx.block_hash)