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}