lighter_rust/api/
transaction.rs1use crate::client::SignerClient;
2use crate::error::Result;
3use crate::models::ApiResponse;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Transaction {
9 pub id: String,
10 pub hash: String,
11 pub block_number: u64,
12 pub block_hash: String,
13 pub transaction_index: u32,
14 pub from_address: String,
15 pub to_address: Option<String>,
16 pub value: String,
17 pub gas_used: String,
18 pub gas_price: String,
19 pub status: TransactionStatus,
20 pub timestamp: DateTime<Utc>,
21 pub confirmations: u32,
22}
23
24#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
25#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
26pub enum TransactionStatus {
27 Pending,
28 Confirmed,
29 Failed,
30 Reverted,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Block {
35 pub number: u64,
36 pub hash: String,
37 pub parent_hash: String,
38 pub timestamp: DateTime<Utc>,
39 pub transaction_count: u32,
40 pub gas_used: String,
41 pub gas_limit: String,
42 pub miner: String,
43}
44
45#[derive(Debug)]
46pub struct TransactionApi {
47 client: SignerClient,
48}
49
50impl TransactionApi {
51 pub fn new(client: SignerClient) -> Self {
52 Self { client }
53 }
54
55 pub async fn get_transaction(&self, tx_hash: &str) -> Result<Transaction> {
56 let response: ApiResponse<Transaction> = self
57 .client
58 .api_client()
59 .get(&format!("/transactions/{}", tx_hash))
60 .await?;
61
62 match response.data {
63 Some(transaction) => Ok(transaction),
64 None => Err(crate::error::LighterError::Api {
65 status: 404,
66 message: response
67 .error
68 .unwrap_or_else(|| "Transaction not found".to_string()),
69 }),
70 }
71 }
72
73 pub async fn get_transactions(
74 &self,
75 address: &str,
76 page: Option<u32>,
77 limit: Option<u32>,
78 ) -> Result<Vec<Transaction>> {
79 let mut query_params = vec![format!("address={}", address)];
80
81 if let Some(page) = page {
82 query_params.push(format!("page={}", page));
83 }
84 if let Some(limit) = limit {
85 query_params.push(format!("limit={}", limit));
86 }
87
88 let endpoint = format!("/transactions?{}", query_params.join("&"));
89
90 let response: ApiResponse<Vec<Transaction>> =
91 self.client.api_client().get(&endpoint).await?;
92
93 match response.data {
94 Some(transactions) => Ok(transactions),
95 None => Err(crate::error::LighterError::Api {
96 status: 500,
97 message: response
98 .error
99 .unwrap_or_else(|| "Failed to fetch transactions".to_string()),
100 }),
101 }
102 }
103
104 pub async fn get_block(&self, block_number: u64) -> Result<Block> {
105 let response: ApiResponse<Block> = self
106 .client
107 .api_client()
108 .get(&format!("/blocks/{}", block_number))
109 .await?;
110
111 match response.data {
112 Some(block) => Ok(block),
113 None => Err(crate::error::LighterError::Api {
114 status: 404,
115 message: response
116 .error
117 .unwrap_or_else(|| "Block not found".to_string()),
118 }),
119 }
120 }
121
122 pub async fn get_latest_block(&self) -> Result<Block> {
123 let response: ApiResponse<Block> = self.client.api_client().get("/blocks/latest").await?;
124
125 match response.data {
126 Some(block) => Ok(block),
127 None => Err(crate::error::LighterError::Api {
128 status: 500,
129 message: response
130 .error
131 .unwrap_or_else(|| "Failed to fetch latest block".to_string()),
132 }),
133 }
134 }
135
136 pub async fn wait_for_confirmation(
137 &self,
138 tx_hash: &str,
139 required_confirmations: u32,
140 ) -> Result<Transaction> {
141 let mut attempts = 0;
142 let max_attempts = 60; loop {
145 if attempts >= max_attempts {
146 return Err(crate::error::LighterError::Unknown(format!(
147 "Transaction {} not confirmed after {} attempts",
148 tx_hash, max_attempts
149 )));
150 }
151
152 match self.get_transaction(tx_hash).await {
153 Ok(tx) => {
154 if tx.confirmations >= required_confirmations {
155 return Ok(tx);
156 }
157 }
158 Err(e) => {
159 if attempts == 0 {
160 return Err(e);
161 }
162 }
163 }
164
165 tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
166 attempts += 1;
167 }
168 }
169}