bankai_sdk/fetch/clients/
bankai_api.rs

1use bankai_types::api::blocks::{BlockStatusDto, BlockSummaryDto, LatestBlockQueryDto};
2use bankai_types::api::error::ErrorResponse;
3use bankai_types::api::proofs::{
4    BankaiBlockProofDto, LightClientProofDto, LightClientProofRequestDto, MmrProofDto,
5    MmrProofRequestDto,
6};
7
8use crate::errors::{SdkError, SdkResult};
9use crate::Network;
10
11/// Client for interacting with the Bankai API
12///
13/// This client provides access to the Bankai proof generation service, which generates
14/// STWO zero-knowledge proofs containing MMRs of blockchain headers. These proofs enable
15/// trustless verification of blockchain data.
16///
17/// # Available Operations
18///
19/// - **Light Client Proofs**: Fetch complete proof bundles with STWO proof + multiple MMR proofs
20/// - **Block Proofs**: Fetch just the STWO proof for a Bankai block
21/// - **MMR Proofs**: Fetch individual MMR proofs for specific headers
22/// - **Block Queries**: Query latest block numbers and block metadata
23///
24/// # Example
25///
26/// ```no_run
27/// use bankai_sdk::{ApiClient, Network};
28///
29/// #[tokio::main]
30/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
31///     let api = ApiClient::new(Network::Sepolia);
32///     
33///     // Get latest block
34///     let latest = api.get_latest_block_number().await?;
35///     println!("Latest block: {}", latest);
36///     
37///     // Get block proof
38///     let block_proof = api.get_block_proof(latest).await?;
39///     
40///     Ok(())
41/// }
42/// ```
43#[derive(Clone)]
44pub struct ApiClient {
45    client: reqwest::Client,
46    base_url: String,
47}
48
49impl Default for ApiClient {
50    fn default() -> Self {
51        Self::new(Network::Sepolia)
52    }
53}
54
55impl ApiClient {
56    /// Creates a new API client for the specified network
57    ///
58    /// The API endpoint is automatically selected based on the network.
59    ///
60    /// # Arguments
61    ///
62    /// * `network` - The blockchain network to connect to
63    pub fn new(network: Network) -> Self {
64        Self {
65            client: reqwest::Client::new(),
66            base_url: network.api_url().to_string(),
67        }
68    }
69
70    async fn handle_response<T: serde::de::DeserializeOwned>(
71        &self,
72        response: reqwest::Response,
73    ) -> SdkResult<T> {
74        if response.status().is_success() {
75            let value = response.json::<T>().await?;
76            return Ok(value);
77        }
78
79        let status = response.status();
80        let body = response.text().await.unwrap_or_default();
81        if let Ok(api_err) = serde_json::from_str::<ErrorResponse>(&body) {
82            return Err(SdkError::from(api_err));
83        }
84        Err(SdkError::Api { status, body })
85    }
86
87    /// Fetches a light client proof containing MMR proofs for multiple headers
88    ///
89    /// This is an optimized endpoint for fetching MMR proofs for multiple blockchain headers
90    /// at once, along with the STWO block proof. This is more efficient than requesting
91    /// individual MMR proofs when you need to verify multiple headers.
92    ///
93    /// # Arguments
94    ///
95    /// * `request` - The light client proof request specifying:
96    ///   - `bankai_block_number`: The Bankai block to anchor proofs to
97    ///   - `hashing_function`: The hash function to use (Keccak, Poseidon, Blake3)
98    ///   - `requested_headers`: List of headers to generate MMR proofs for
99    ///
100    /// # Returns
101    ///
102    /// A proof bundle containing:
103    /// - STWO block proof with MMRs
104    /// - MMR proofs for each requested header to decommit from the MMRs
105    pub async fn get_light_client_proof(
106        &self,
107        request: &LightClientProofRequestDto,
108    ) -> SdkResult<LightClientProofDto> {
109        let url = format!("{}/v1/proofs/light-client", self.base_url);
110        let response = self.client.post(&url).json(request).send().await?;
111        self.handle_response(response).await
112    }
113
114    /// Fetches the STWO block proof for a specific Bankai block number
115    ///
116    /// The block proof is an STWO zero-knowledge proof that contains MMRs of valid
117    /// blockchain headers. This proof is the foundation for verifying any blockchain
118    /// data - headers can be decommitted from the MMRs using MMR proofs.
119    ///
120    /// # Arguments
121    ///
122    /// * `block_number` - The Bankai block number to fetch the proof for
123    ///
124    /// # Returns
125    ///
126    /// The STWO block proof containing MMRs with commitments to blockchain headers
127    pub async fn get_block_proof(&self, block_number: u64) -> SdkResult<BankaiBlockProofDto> {
128        let url = format!("{}/v1/proofs/block/{}", self.base_url, block_number);
129        let response = self.client.get(&url).send().await?;
130        self.handle_response(response).await
131    }
132
133    /// Fetches an MMR proof for a specific blockchain header
134    ///
135    /// The MMR proof enables decommitment of a specific header from the STWO block proof's MMR.
136    /// Once decommitted, the header is verified and can be used to verify chain data
137    /// (accounts, transactions, storage) via Merkle proofs against the header's roots.
138    ///
139    /// # Arguments
140    ///
141    /// * `request` - The MMR proof request specifying:
142    ///   - `network_id`: The blockchain network ID (0 = beacon, 1 = execution)
143    ///   - `block_number`: The block number of the header
144    ///   - `hashing_function`: The hash function to use
145    ///   - `header_hash`: The header hash to generate a proof for
146    ///
147    /// # Returns
148    ///
149    /// An MMR proof that can decommit the specified header from the MMR
150    pub async fn get_mmr_proof(&self, request: &MmrProofRequestDto) -> SdkResult<MmrProofDto> {
151        let url = format!("{}/v1/proofs/mmr", self.base_url);
152        let response = self.client.post(&url).json(request).send().await?;
153        self.handle_response(response).await
154    }
155
156    /// Fetches the latest Bankai block number
157    ///
158    /// This is useful for getting the most recent block number when you want to
159    /// anchor proofs to the latest available data. Only returns completed blocks.
160    ///
161    /// # Returns
162    ///
163    /// The latest completed Bankai block number
164    pub async fn get_latest_block_number(&self) -> SdkResult<u64> {
165        let url = format!("{}/v1/blocks/latest", self.base_url);
166        let query = LatestBlockQueryDto {
167            status: Some(BlockStatusDto::Completed),
168        };
169        let response = self.client.get(&url).query(&query).send().await?;
170
171        let block_summary: BlockSummaryDto = self.handle_response(response).await?;
172        Ok(block_summary.height)
173    }
174
175    /// Fetches the latest block summary
176    ///
177    /// This is useful for getting the latest block summary when you want to
178    /// get the latest block summary.
179    ///
180    /// # Returns
181    ///
182    /// The latest block summary
183    pub async fn get_latest_block(&self) -> SdkResult<BlockSummaryDto> {
184        let url = format!("{}/v1/blocks/latest", self.base_url);
185        let response = self.client.get(&url).send().await?;
186        self.handle_response(response).await
187    }
188}