use crate::client::send::TransactionResponse;
use crate::client::type_urls::MSG_TRANSFER_TYPE_URL;
use crate::client::{Contact, MEMO};
use crate::coin::Coin;
use crate::error::CosmosGrpcError;
use crate::msg::Msg;
use crate::private_key::PrivateKey;
use cosmos_sdk_proto::cosmos::base::v1beta1::Coin as ProtoCoin;
use cosmos_sdk_proto::ibc::applications::transfer::v1::query_client::QueryClient as IbcTransferQueryClient;
use cosmos_sdk_proto::ibc::applications::transfer::v1::{
DenomTrace, MsgTransfer, QueryDenomHashRequest, QueryDenomTraceRequest, QueryDenomTracesRequest,
};
use cosmos_sdk_proto::ibc::core::client::v1::Height;
use std::time::Duration;
use std::time::SystemTime;
use tokio::time::timeout;
impl Contact {
#[allow(clippy::too_many_arguments)]
pub async fn send_ibc_transfer(
&self,
amount: Coin,
fee_coin: Option<Coin>,
receiver: String,
channel_id: String,
ibc_timeout: Duration,
wait_timeout: Option<Duration>,
memo: Option<String>,
private_key: impl PrivateKey,
) -> Result<TransactionResponse, CosmosGrpcError> {
let sender = private_key
.to_address(&self.chain_prefix)
.unwrap()
.to_string();
let timeout_timestamp = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map_err(|_| {
CosmosGrpcError::BadInput("System clock error: time before UNIX_EPOCH".to_string())
})?
.checked_add(ibc_timeout)
.ok_or_else(|| CosmosGrpcError::BadInput("IBC timeout duration overflow".to_string()))?
.as_nanos()
.try_into()
.map_err(|_| {
CosmosGrpcError::BadInput("Timeout timestamp exceeds u64::MAX".to_string())
})?;
let memo_string = memo.clone().unwrap_or_else(|| MEMO.to_string());
let msg_transfer = MsgTransfer {
source_port: "transfer".to_string(),
source_channel: channel_id,
token: Some(ProtoCoin {
denom: amount.denom.clone(),
amount: amount.amount.to_string(),
}),
sender,
receiver,
timeout_height: None,
timeout_timestamp,
memo: memo_string.clone(),
};
let msg = Msg::new(MSG_TRANSFER_TYPE_URL, msg_transfer);
let fee_coins = fee_coin.map(|coin| vec![coin]).unwrap_or_default();
self.send_message(
&[msg],
Some(memo_string),
&fee_coins,
wait_timeout,
None,
private_key,
)
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn send_ibc_transfer_with_height(
&self,
amount: Coin,
fee_coin: Option<Coin>,
receiver: String,
channel_id: String,
timeout_height: Height,
wait_timeout: Option<Duration>,
memo: Option<String>,
private_key: impl PrivateKey,
) -> Result<TransactionResponse, CosmosGrpcError> {
let sender = private_key
.to_address(&self.chain_prefix)
.unwrap()
.to_string();
let memo_string = memo.clone().unwrap_or_else(|| MEMO.to_string());
let msg_transfer = MsgTransfer {
source_port: "transfer".to_string(),
source_channel: channel_id,
token: Some(ProtoCoin {
denom: amount.denom.clone(),
amount: amount.amount.to_string(),
}),
sender,
receiver,
timeout_height: Some(timeout_height),
timeout_timestamp: 0,
memo: memo_string.clone(),
};
let msg = Msg::new(MSG_TRANSFER_TYPE_URL, msg_transfer);
let fee_coins = fee_coin.map(|coin| vec![coin]).unwrap_or_default();
self.send_message(
&[msg],
Some(memo_string),
&fee_coins,
wait_timeout,
None,
private_key,
)
.await
}
pub async fn query_ibc_denom_trace(
&self,
hash: String,
) -> Result<Option<DenomTrace>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
IbcTransferQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.denom_trace(QueryDenomTraceRequest { hash }),
)
.await??
.into_inner();
Ok(res.denom_trace)
}
pub async fn query_ibc_denom_traces(&self) -> Result<Vec<DenomTrace>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
IbcTransferQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.denom_traces(QueryDenomTracesRequest { pagination: None }),
)
.await??
.into_inner();
Ok(res.denom_traces)
}
pub async fn query_ibc_denom_hash(&self, trace: String) -> Result<String, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
IbcTransferQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.denom_hash(QueryDenomHashRequest { trace }),
)
.await??
.into_inner();
Ok(res.hash)
}
}