penumbra_sdk_shielded_pool/component/rpc/
transfer_query.rs

1use anyhow::Context;
2use async_trait::async_trait;
3use futures::StreamExt;
4use ibc_proto::ibc::applications::transfer::v1::query_server::Query as TransferQuery;
5use ibc_proto::ibc::apps::transfer::v1::{
6    DenomTrace, QueryDenomHashRequest, QueryDenomHashResponse, QueryDenomTraceRequest,
7    QueryDenomTraceResponse, QueryDenomTracesRequest, QueryDenomTracesResponse,
8    QueryEscrowAddressRequest, QueryEscrowAddressResponse, QueryParamsRequest, QueryParamsResponse,
9    QueryTotalEscrowForDenomRequest, QueryTotalEscrowForDenomResponse,
10};
11use penumbra_sdk_asset::asset::Metadata;
12use penumbra_sdk_proto::StateReadProto as _;
13
14use crate::state_key;
15
16use super::Server;
17
18#[async_trait]
19impl TransferQuery for Server {
20    async fn total_escrow_for_denom(
21        &self,
22        _: tonic::Request<QueryTotalEscrowForDenomRequest>,
23    ) -> std::result::Result<tonic::Response<QueryTotalEscrowForDenomResponse>, tonic::Status> {
24        Err(tonic::Status::unimplemented("not implemented"))
25    }
26
27    async fn escrow_address(
28        &self,
29        _: tonic::Request<QueryEscrowAddressRequest>,
30    ) -> std::result::Result<tonic::Response<QueryEscrowAddressResponse>, tonic::Status> {
31        Err(tonic::Status::unimplemented("not implemented"))
32    }
33
34    async fn denom_hash(
35        &self,
36        _: tonic::Request<QueryDenomHashRequest>,
37    ) -> std::result::Result<tonic::Response<QueryDenomHashResponse>, tonic::Status> {
38        Err(tonic::Status::unimplemented("not implemented"))
39    }
40
41    async fn params(
42        &self,
43        _: tonic::Request<QueryParamsRequest>,
44    ) -> std::result::Result<tonic::Response<QueryParamsResponse>, tonic::Status> {
45        Err(tonic::Status::unimplemented("not implemented"))
46    }
47
48    async fn denom_trace(
49        &self,
50        _: tonic::Request<QueryDenomTraceRequest>,
51    ) -> std::result::Result<tonic::Response<QueryDenomTraceResponse>, tonic::Status> {
52        Err(tonic::Status::unimplemented("not implemented"))
53    }
54
55    async fn denom_traces(
56        &self,
57        _: tonic::Request<QueryDenomTracesRequest>,
58    ) -> std::result::Result<tonic::Response<QueryDenomTracesResponse>, tonic::Status> {
59        // TODO: Currently pagination is ignored and all denom traces are returned at once.
60        // Since this API isn't streaming, this may be something useful to implement later.
61        let snapshot = self.storage.latest_snapshot();
62        let s = snapshot.prefix(state_key::denom_metadata_by_asset::prefix());
63        let denom_traces = s
64            .filter_map(move |i: anyhow::Result<(String, Metadata)>| async move {
65                if i.is_err() {
66                    return Some(Err(i.context("bad denom in state").err().unwrap()));
67                }
68                let (_key, denom) = i.expect("should not be an error");
69
70                // Convert the key to an IBC asset path
71                match denom.ibc_transfer_path() {
72                    Ok(None) => return None,
73                    Err(e) => return Some(Err(e)),
74                    Ok(Some((path, base_denom))) => Some(Ok(DenomTrace { path, base_denom })),
75                }
76            })
77            .collect::<Vec<_>>()
78            .await
79            .into_iter()
80            .collect::<anyhow::Result<Vec<_>>>()
81            .map_err(|e| tonic::Status::internal(e.to_string()))?;
82        Ok(tonic::Response::new(QueryDenomTracesResponse {
83            denom_traces,
84            // pagination disabled for now
85            pagination: None,
86        }))
87    }
88}