1use crate::{cosmos_modules, error::DaemonError, Daemon};
2use cosmos_modules::ibc_channel;
3use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest;
4use cosmrs::proto::ibc::{
5 applications::transfer::v1::{DenomTrace, QueryDenomHashResponse, QueryDenomTraceResponse},
6 core::{
7 channel::v1::QueryPacketCommitmentResponse,
8 client::v1::{IdentifiedClientState, QueryClientStatesResponse},
9 connection::v1::{ConnectionEnd, IdentifiedConnection, State},
10 },
11 lightclients::tendermint::v1::ClientState,
12};
13use cw_orch_core::environment::{Querier, QuerierGetter};
14use prost::Message;
15use tokio::runtime::Handle;
16use tonic::transport::Channel;
17
18pub struct Ibc {
21 pub channel: Channel,
22 pub rt_handle: Option<Handle>,
23}
24
25impl Ibc {
26 pub fn new(daemon: &Daemon) -> Self {
27 Self {
28 channel: daemon.channel(),
29 rt_handle: Some(daemon.rt_handle.clone()),
30 }
31 }
32
33 pub fn new_async(channel: Channel) -> Self {
34 Self {
35 channel,
36 rt_handle: None,
37 }
38 }
39}
40
41impl Querier for Ibc {
42 type Error = DaemonError;
43}
44
45impl QuerierGetter<Ibc> for Daemon {
46 fn querier(&self) -> Ibc {
47 Ibc::new(self)
48 }
49}
50
51impl Ibc {
52 pub async fn _denom_trace(&self, hash: String) -> Result<DenomTrace, DaemonError> {
56 let denom_trace: QueryDenomTraceResponse = cosmos_query!(
57 self,
58 ibc_transfer,
59 denom_trace,
60 QueryDenomTraceRequest { hash: hash }
61 );
62 Ok(denom_trace.denom_trace.unwrap())
63 }
64
65 pub async fn _denom_hash(&self, trace: String) -> Result<String, DaemonError> {
67 let denom_hash: QueryDenomHashResponse = cosmos_query!(
68 self,
69 ibc_transfer,
70 denom_hash,
71 QueryDenomHashRequest { trace: trace }
72 );
73 Ok(denom_hash.hash)
74 }
75
76 pub async fn _clients(&self) -> Result<Vec<IdentifiedClientState>, DaemonError> {
80 let ibc_clients: QueryClientStatesResponse = cosmos_query!(
81 self,
82 ibc_client,
83 client_states,
84 QueryClientStatesRequest { pagination: None }
85 );
86 Ok(ibc_clients.client_states)
87 }
88
89 pub async fn _client_state(
91 &self,
92 client_id: impl ToString,
93 ) -> Result<cosmos_modules::ibc_client::QueryClientStateResponse, DaemonError> {
95 let response: cosmos_modules::ibc_client::QueryClientStateResponse = cosmos_query!(
96 self,
97 ibc_client,
98 client_state,
99 QueryClientStateRequest {
100 client_id: client_id.to_string(),
101 }
102 );
103 Ok(response)
104 }
105
106 pub async fn _consensus_states(
108 &self,
109 client_id: impl ToString,
110 ) -> Result<cosmos_modules::ibc_client::QueryConsensusStatesResponse, DaemonError> {
111 let client_id = client_id.to_string();
112 let response: cosmos_modules::ibc_client::QueryConsensusStatesResponse = cosmos_query!(
113 self,
114 ibc_client,
115 consensus_states,
116 QueryConsensusStatesRequest {
117 client_id: client_id,
118 pagination: None,
119 }
120 );
121 Ok(response)
122 }
123
124 pub async fn _client_status(
126 &self,
127 client_id: impl ToString,
128 ) -> Result<cosmos_modules::ibc_client::QueryClientStatusResponse, DaemonError> {
130 let response: cosmos_modules::ibc_client::QueryClientStatusResponse = cosmos_query!(
131 self,
132 ibc_client,
133 client_status,
134 QueryClientStatusRequest {
135 client_id: client_id.to_string(),
136 }
137 );
138 Ok(response)
139 }
140
141 pub async fn _client_params(
143 &self,
144 ) -> Result<cosmos_modules::ibc_client::QueryClientParamsResponse, DaemonError> {
145 let response: cosmos_modules::ibc_client::QueryClientParamsResponse =
146 cosmos_query!(self, ibc_client, client_params, QueryClientParamsRequest {});
147 Ok(response)
148 }
149
150 pub async fn _connections(&self) -> Result<Vec<IdentifiedConnection>, DaemonError> {
154 use cosmos_modules::ibc_connection::QueryConnectionsResponse;
155
156 let ibc_connections: QueryConnectionsResponse = cosmos_query!(
157 self,
158 ibc_connection,
159 connections,
160 QueryConnectionsRequest { pagination: None }
161 );
162 Ok(ibc_connections.connections)
163 }
164
165 pub async fn _open_connections(
167 &self,
168 client_chain_id: impl ToString,
169 ) -> Result<Vec<IdentifiedConnection>, DaemonError> {
170 let connections = self._connections().await?;
171 let mut open_connections = Vec::new();
172 for connection in connections {
173 if connection.state() == State::Open {
174 open_connections.push(connection);
175 }
176 }
177
178 let mut filtered_connections = Vec::new();
180 for connection in open_connections {
181 let client_state = self._connection_client(&connection.id).await?;
182 if client_state.chain_id == client_chain_id.to_string() {
183 filtered_connections.push(connection);
184 }
185 }
186
187 Ok(filtered_connections)
188 }
189
190 pub async fn _connection_end(
192 &self,
193 connection_id: impl Into<String>,
194 ) -> Result<Option<ConnectionEnd>, DaemonError> {
195 use cosmos_modules::ibc_connection::QueryConnectionResponse;
196
197 let connection_id = connection_id.into();
198 let ibc_client_connections: QueryConnectionResponse = cosmos_query!(
199 self,
200 ibc_connection,
201 connection,
202 QueryConnectionRequest {
203 connection_id: connection_id.clone()
204 }
205 );
206
207 Ok(ibc_client_connections.connection)
208 }
209
210 pub async fn _client_connections(
212 &self,
213 client_id: impl Into<String>,
214 ) -> Result<Vec<String>, DaemonError> {
215 use cosmos_modules::ibc_connection::QueryClientConnectionsResponse;
216
217 let client_id = client_id.into();
218 let ibc_client_connections: QueryClientConnectionsResponse = cosmos_query!(
219 self,
220 ibc_connection,
221 client_connections,
222 QueryClientConnectionsRequest {
223 client_id: client_id.clone()
224 }
225 );
226
227 Ok(ibc_client_connections.connection_paths)
228 }
229
230 pub async fn _connection_client(
232 &self,
233 connection_id: impl Into<String>,
234 ) -> Result<ClientState, DaemonError> {
235 use cosmos_modules::ibc_connection::QueryConnectionClientStateResponse;
236 let connection_id = connection_id.into();
237
238 let ibc_connection_client: QueryConnectionClientStateResponse = cosmos_query!(
239 self,
240 ibc_connection,
241 connection_client_state,
242 QueryConnectionClientStateRequest {
243 connection_id: connection_id.clone()
244 }
245 );
246
247 let client_state =
248 ibc_connection_client
249 .identified_client_state
250 .ok_or(DaemonError::ibc_err(format!(
251 "error identifying client for connection {}",
252 connection_id
253 )))?;
254
255 let client_state = ClientState::decode(client_state.client_state.unwrap().value.as_slice())
256 .map_err(|e| DaemonError::ibc_err(format!("error decoding client state: {}", e)))?;
257
258 Ok(client_state)
259 }
260
261 pub async fn _channel(
265 &self,
266 port_id: impl Into<String>,
267 channel_id: impl Into<String>,
268 ) -> Result<ibc_channel::Channel, DaemonError> {
269 use cosmos_modules::ibc_channel::QueryChannelResponse;
270
271 let port_id = port_id.into();
272 let channel_id = channel_id.into();
273 let ibc_channel: QueryChannelResponse = cosmos_query!(
274 self,
275 ibc_channel,
276 channel,
277 QueryChannelRequest {
278 port_id: port_id.clone(),
279 channel_id: channel_id.clone(),
280 }
281 );
282
283 ibc_channel.channel.ok_or(DaemonError::ibc_err(format!(
284 "error fetching channel {} on port {}",
285 channel_id, port_id
286 )))
287 }
288
289 pub async fn _channels(
291 &self,
292 pagination: Option<PageRequest>,
293 ) -> Result<Vec<ibc_channel::IdentifiedChannel>, DaemonError> {
294 use cosmos_modules::ibc_channel::QueryChannelsResponse;
295
296 let ibc_channels: QueryChannelsResponse = cosmos_query!(
297 self,
298 ibc_channel,
299 channels,
300 QueryChannelsRequest {
301 pagination: pagination
302 }
303 );
304
305 Ok(ibc_channels.channels)
306 }
307
308 pub async fn _connection_channels(
310 &self,
311 connection_id: impl Into<String>,
312 ) -> Result<Vec<ibc_channel::IdentifiedChannel>, DaemonError> {
313 use cosmos_modules::ibc_channel::QueryConnectionChannelsResponse;
314
315 let connection_id = connection_id.into();
316 let ibc_connection_channels: QueryConnectionChannelsResponse = cosmos_query!(
317 self,
318 ibc_channel,
319 connection_channels,
320 QueryConnectionChannelsRequest {
321 connection: connection_id.clone(),
322 pagination: None,
323 }
324 );
325
326 Ok(ibc_connection_channels.channels)
327 }
328
329 pub async fn _channel_client_state(
331 &self,
332 port_id: impl Into<String>,
333 channel_id: impl Into<String>,
334 ) -> Result<IdentifiedClientState, DaemonError> {
335 use cosmos_modules::ibc_channel::QueryChannelClientStateResponse;
336
337 let port_id = port_id.into();
338 let channel_id = channel_id.into();
339 let ibc_channel_client_state: QueryChannelClientStateResponse = cosmos_query!(
340 self,
341 ibc_channel,
342 channel_client_state,
343 QueryChannelClientStateRequest {
344 port_id: port_id.clone(),
345 channel_id: channel_id.clone(),
346 }
347 );
348
349 ibc_channel_client_state
350 .identified_client_state
351 .ok_or(DaemonError::ibc_err(format!(
352 "error identifying client for channel {} on port {}",
353 channel_id, port_id
354 )))
355 }
356
357 pub async fn _packet_commitments(
363 &self,
364 port_id: impl Into<String>,
365 channel_id: impl Into<String>,
366 ) -> Result<Vec<ibc_channel::PacketState>, DaemonError> {
367 use cosmos_modules::ibc_channel::QueryPacketCommitmentsResponse;
368
369 let port_id = port_id.into();
370 let channel_id = channel_id.into();
371 let ibc_packet_commitments: QueryPacketCommitmentsResponse = cosmos_query!(
372 self,
373 ibc_channel,
374 packet_commitments,
375 QueryPacketCommitmentsRequest {
376 port_id: port_id.clone(),
377 channel_id: channel_id.clone(),
378 pagination: None,
379 }
380 );
381
382 Ok(ibc_packet_commitments.commitments)
383 }
384
385 pub async fn _packet_commitment(
387 &self,
388 port_id: impl Into<String>,
389 channel_id: impl Into<String>,
390 sequence: u64,
391 ) -> Result<QueryPacketCommitmentResponse, DaemonError> {
392 let port_id = port_id.into();
393 let channel_id = channel_id.into();
394 let ibc_packet_commitment: QueryPacketCommitmentResponse = cosmos_query!(
395 self,
396 ibc_channel,
397 packet_commitment,
398 QueryPacketCommitmentRequest {
399 port_id: port_id.clone(),
400 channel_id: channel_id.clone(),
401 sequence: sequence,
402 }
403 );
404
405 Ok(ibc_packet_commitment)
406 }
407
408 pub async fn _packet_receipt(
412 &self,
413 port_id: impl Into<String>,
414 channel_id: impl Into<String>,
415 sequence: u64,
416 ) -> Result<bool, DaemonError> {
417 let port_id = port_id.into();
418 let channel_id = channel_id.into();
419 let ibc_packet_receipt: ibc_channel::QueryPacketReceiptResponse = cosmos_query!(
420 self,
421 ibc_channel,
422 packet_receipt,
423 QueryPacketReceiptRequest {
424 port_id: port_id.clone(),
425 channel_id: channel_id.clone(),
426 sequence: sequence,
427 }
428 );
429
430 Ok(ibc_packet_receipt.received)
431 }
432
433 pub async fn _packet_acknowledgements(
437 &self,
438 port_id: impl Into<String>,
439 channel_id: impl Into<String>,
440 packet_commitment_sequences: Vec<u64>,
441 ) -> Result<Vec<ibc_channel::PacketState>, DaemonError> {
442 use cosmos_modules::ibc_channel::QueryPacketAcknowledgementsResponse;
443
444 let port_id = port_id.into();
445 let channel_id = channel_id.into();
446 let ibc_packet_acknowledgements: QueryPacketAcknowledgementsResponse = cosmos_query!(
447 self,
448 ibc_channel,
449 packet_acknowledgements,
450 QueryPacketAcknowledgementsRequest {
451 port_id: port_id.clone(),
452 channel_id: channel_id.clone(),
453 packet_commitment_sequences: packet_commitment_sequences,
454 pagination: None,
455 }
456 );
457
458 Ok(ibc_packet_acknowledgements.acknowledgements)
459 }
460
461 pub async fn _packet_acknowledgement(
463 &self,
464 port_id: impl Into<String>,
465 channel_id: impl Into<String>,
466 sequence: u64,
467 ) -> Result<Vec<u8>, DaemonError> {
468 let port_id = port_id.into();
469 let channel_id = channel_id.into();
470 let ibc_packet_acknowledgement: ibc_channel::QueryPacketAcknowledgementResponse = cosmos_query!(
471 self,
472 ibc_channel,
473 packet_acknowledgement,
474 QueryPacketAcknowledgementRequest {
475 port_id: port_id.clone(),
476 channel_id: channel_id.clone(),
477 sequence: sequence,
478 }
479 );
480
481 Ok(ibc_packet_acknowledgement.acknowledgement)
482 }
483
484 pub async fn _unreceived_packets(
487 &self,
488 port_id: impl Into<String>,
489 channel_id: impl Into<String>,
490 packet_commitment_sequences: Vec<u64>,
491 ) -> Result<Vec<u64>, DaemonError> {
492 use cosmos_modules::ibc_channel::QueryUnreceivedPacketsResponse;
493
494 let port_id = port_id.into();
495 let channel_id = channel_id.into();
496 let ibc_packet_unreceived: QueryUnreceivedPacketsResponse = cosmos_query!(
497 self,
498 ibc_channel,
499 unreceived_packets,
500 QueryUnreceivedPacketsRequest {
501 port_id: port_id.clone(),
502 channel_id: channel_id.clone(),
503 packet_commitment_sequences: packet_commitment_sequences,
504 }
505 );
506
507 Ok(ibc_packet_unreceived.sequences)
508 }
509
510 pub async fn _unreceived_acks(
514 &self,
515 port_id: impl Into<String>,
516 channel_id: impl Into<String>,
517 packet_ack_sequences: Vec<u64>,
518 ) -> Result<Vec<u64>, DaemonError> {
519 let port_id = port_id.into();
520 let channel_id = channel_id.into();
521 let ibc_packet_unreceived: ibc_channel::QueryUnreceivedAcksResponse = cosmos_query!(
522 self,
523 ibc_channel,
524 unreceived_acks,
525 QueryUnreceivedAcksRequest {
526 port_id: port_id.clone(),
527 channel_id: channel_id.clone(),
528 packet_ack_sequences: packet_ack_sequences,
529 }
530 );
531
532 Ok(ibc_packet_unreceived.sequences)
533 }
534
535 pub async fn _next_sequence_receive(
539 &self,
540 port_id: impl Into<String>,
541 channel_id: impl Into<String>,
542 ) -> Result<u64, DaemonError> {
543 let port_id = port_id.into();
544 let channel_id = channel_id.into();
545 let next_receive: ibc_channel::QueryNextSequenceReceiveResponse = cosmos_query!(
546 self,
547 ibc_channel,
548 next_sequence_receive,
549 QueryNextSequenceReceiveRequest {
550 port_id: port_id.clone(),
551 channel_id: channel_id.clone(),
552 }
553 );
554
555 Ok(next_receive.next_sequence_receive)
556 }
557}