Skip to main content

iris_wasm/
grpc.rs

1use iris_grpc_proto::pb::common::v1::{Base58Hash, Base58Pubkey, PageRequest};
2use iris_grpc_proto::pb::common::v2 as pb_common_v2;
3use iris_grpc_proto::pb::public::v2::*;
4use tonic_web_wasm_client::Client;
5use wasm_bindgen::prelude::*;
6
7#[wasm_bindgen]
8pub struct GrpcClient {
9    endpoint: String,
10}
11
12#[wasm_bindgen]
13impl GrpcClient {
14    #[wasm_bindgen(constructor)]
15    pub fn new(endpoint: String) -> Self {
16        Self { endpoint }
17    }
18
19    /// Get balance for a wallet address
20    #[wasm_bindgen(js_name = getBalanceByAddress)]
21    pub async fn get_balance_by_address(
22        &self,
23        address: String,
24    ) -> Result<pb_common_v2::Balance, JsValue> {
25        let client = Client::new(self.endpoint.clone());
26        let mut grpc_client = nockchain_service_client::NockchainServiceClient::new(client);
27
28        let request = WalletGetBalanceRequest {
29            selector: Some(wallet_get_balance_request::Selector::Address(
30                Base58Pubkey { key: address },
31            )),
32            page: Some(PageRequest {
33                client_page_items_limit: 0,
34                page_token: String::new(),
35                max_bytes: 0,
36            }),
37        };
38
39        let response = grpc_client
40            .wallet_get_balance(request)
41            .await
42            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
43            .into_inner();
44
45        match response.result {
46            Some(wallet_get_balance_response::Result::Balance(balance)) => Ok(balance),
47            Some(wallet_get_balance_response::Result::Error(e)) => {
48                Err(JsValue::from_str(&format!("Server error: {}", e.message)))
49            }
50            None => Err(JsValue::from_str("Empty response from server")),
51        }
52    }
53
54    /// Get balance for a first name
55    #[wasm_bindgen(js_name = getBalanceByFirstName)]
56    pub async fn get_balance_by_first_name(
57        &self,
58        first_name: String,
59    ) -> Result<pb_common_v2::Balance, JsValue> {
60        let client = Client::new(self.endpoint.clone());
61        let mut grpc_client = nockchain_service_client::NockchainServiceClient::new(client);
62
63        let request = WalletGetBalanceRequest {
64            selector: Some(wallet_get_balance_request::Selector::FirstName(
65                Base58Hash { hash: first_name },
66            )),
67            page: Some(PageRequest {
68                client_page_items_limit: 0,
69                page_token: String::new(),
70                max_bytes: 0,
71            }),
72        };
73
74        let response = grpc_client
75            .wallet_get_balance(request)
76            .await
77            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
78            .into_inner();
79
80        match response.result {
81            Some(wallet_get_balance_response::Result::Balance(balance)) => Ok(balance),
82            Some(wallet_get_balance_response::Result::Error(e)) => {
83                Err(JsValue::from_str(&format!("Server error: {}", e.message)))
84            }
85            None => Err(JsValue::from_str("Empty response from server")),
86        }
87    }
88
89    /// Send a transaction
90    #[wasm_bindgen(js_name = sendTransaction)]
91    pub async fn send_transaction(
92        &self,
93        raw_tx: pb_common_v2::RawTransaction,
94    ) -> Result<String, JsValue> {
95        let client = Client::new(self.endpoint.clone());
96        let mut grpc_client = nockchain_service_client::NockchainServiceClient::new(client);
97
98        // Extract the tx_id from the raw transaction
99        let pb_tx_id = raw_tx.id;
100
101        let request = WalletSendTransactionRequest {
102            tx_id: pb_tx_id,
103            raw_tx: Some(raw_tx),
104        };
105
106        let response = grpc_client
107            .wallet_send_transaction(request)
108            .await
109            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
110            .into_inner();
111
112        match response.result {
113            Some(wallet_send_transaction_response::Result::Ack(_)) => {
114                Ok(String::from("Transaction acknowledged"))
115            }
116            Some(wallet_send_transaction_response::Result::Error(e)) => {
117                Err(JsValue::from_str(&format!("Server error: {}", e.message)))
118            }
119            None => Err(JsValue::from_str("Empty response from server")),
120        }
121    }
122
123    /// Check if a transaction was accepted
124    #[wasm_bindgen(js_name = transactionAccepted)]
125    pub async fn transaction_accepted(&self, tx_id: String) -> Result<bool, JsValue> {
126        let client = Client::new(self.endpoint.clone());
127        let mut grpc_client = nockchain_service_client::NockchainServiceClient::new(client);
128
129        let request = TransactionAcceptedRequest {
130            tx_id: Some(Base58Hash { hash: tx_id }),
131        };
132
133        let response = grpc_client
134            .transaction_accepted(request)
135            .await
136            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
137            .into_inner();
138
139        match response.result {
140            Some(transaction_accepted_response::Result::Accepted(accepted)) => Ok(accepted),
141            Some(transaction_accepted_response::Result::Error(e)) => {
142                Err(JsValue::from_str(&format!("Server error: {}", e.message)))
143            }
144            None => Err(JsValue::from_str("Empty response from server")),
145        }
146    }
147
148    /// Peek a value from a Nock application
149    #[cfg(feature = "private-api")]
150    #[wasm_bindgen(js_name = peek)]
151    pub async fn peek(&self, pid: i32, path: iris_ztd::Noun) -> Result<iris_ztd::Noun, JsValue> {
152        let client = Client::new(self.endpoint.clone());
153        let mut grpc_client =
154            iris_grpc_proto::pb::private::v1::nock_app_service_client::NockAppServiceClient::new(
155                client,
156            );
157
158        let path_jam = iris_ztd::jam(path);
159        let request = iris_grpc_proto::pb::private::v1::PeekRequest {
160            pid,
161            path: path_jam,
162        };
163
164        let response = grpc_client
165            .peek(request)
166            .await
167            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
168            .into_inner();
169
170        match response.result {
171            Some(iris_grpc_proto::pb::private::v1::peek_response::Result::Data(data)) => {
172                iris_ztd::cue(&data)
173                    .ok_or_else(|| JsValue::from_str("Failed to cue noun from peek response"))
174            }
175            Some(iris_grpc_proto::pb::private::v1::peek_response::Result::Error(err)) => {
176                Err(JsValue::from_str(&format!("Server error: {}", err.message)))
177            }
178            None => Err(JsValue::from_str("Empty response from server")),
179        }
180    }
181
182    /// Poke a Nock application
183    #[cfg(feature = "private-api")]
184    #[wasm_bindgen(js_name = poke)]
185    pub async fn poke(
186        &self,
187        pid: i32,
188        wire: iris_grpc_proto::pb::common::v1::Wire,
189        payload: iris_ztd::Noun,
190    ) -> Result<(), JsValue> {
191        let client = Client::new(self.endpoint.clone());
192        let mut grpc_client =
193            iris_grpc_proto::pb::private::v1::nock_app_service_client::NockAppServiceClient::new(
194                client,
195            );
196
197        let payload_jam = iris_ztd::jam(payload);
198        let request = iris_grpc_proto::pb::private::v1::PokeRequest {
199            pid,
200            wire: Some(wire),
201            payload: payload_jam,
202        };
203
204        let response = grpc_client
205            .poke(request)
206            .await
207            .map_err(|e| JsValue::from_str(&format!("gRPC error: {}", e)))?
208            .into_inner();
209
210        match response.result {
211            Some(iris_grpc_proto::pb::private::v1::poke_response::Result::Acknowledged(true)) => {
212                Ok(())
213            }
214            Some(iris_grpc_proto::pb::private::v1::poke_response::Result::Acknowledged(false)) => {
215                Err(JsValue::from_str("Poke not acknowledged"))
216            }
217            Some(iris_grpc_proto::pb::private::v1::poke_response::Result::Error(err)) => {
218                Err(JsValue::from_str(&format!("Server error: {}", err.message)))
219            }
220            None => Err(JsValue::from_str("Empty response from server")),
221        }
222    }
223}