use super::send::TransactionResponse;
use super::{ChainStatus, PAGE};
use crate::client::type_urls::{
MSG_FUND_COMMUNITY_POOL_TYPE_URL, MSG_WITHDRAW_DELEGATOR_REWARD_TYPE_URL,
MSG_WITHDRAW_VALIDATOR_COMMISSION_TYPE_URL,
};
use crate::error::CosmosGrpcError;
use crate::{Address, Coin, Contact, Msg, PrivateKey};
use cosmos_sdk_proto::cosmos::base::v1beta1::DecCoin;
use cosmos_sdk_proto::cosmos::distribution::v1beta1::query_client::QueryClient as DistQueryClient;
use cosmos_sdk_proto::cosmos::distribution::v1beta1::{
MsgFundCommunityPool, QueryValidatorSlashesRequest,
};
use cosmos_sdk_proto::cosmos::distribution::v1beta1::{
MsgWithdrawDelegatorReward, ValidatorSlashEvent,
};
use cosmos_sdk_proto::cosmos::distribution::v1beta1::{
MsgWithdrawValidatorCommission, QueryDelegationRewardsRequest,
};
use cosmos_sdk_proto::cosmos::distribution::v1beta1::{
QueryCommunityPoolRequest, QueryDelegationTotalRewardsRequest,
};
use cosmos_sdk_proto::cosmos::distribution::v1beta1::{
QueryDelegationTotalRewardsResponse, QueryDelegatorValidatorsRequest,
};
use num256::error::ParseError;
use num256::Uint256;
use std::time::Duration;
use tokio::time::timeout;
const ONE_ETH: u128 = 10u128.pow(18);
impl Contact {
pub async fn query_community_pool(&self) -> Result<Vec<Coin>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
DistQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.community_pool(QueryCommunityPoolRequest {}),
)
.await??;
let val = res.into_inner().pool;
let mut res = Vec::new();
for v in val {
let parse_result: Result<Uint256, ParseError> = v.amount.parse();
match parse_result {
Ok(parse_result) => res.push(Coin {
denom: v.denom,
amount: parse_result / ONE_ETH.into(),
}),
Err(e) => return Err(CosmosGrpcError::ParseError { error: e }),
}
}
Ok(res)
}
pub async fn query_validator_slashes(
&self,
validator_address: impl ToString,
) -> Result<Vec<ValidatorSlashEvent>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
DistQueryClient::connect(self.url.clone()),
)
.await??;
let current_block = self.get_chain_status().await?;
let current_block = match current_block {
ChainStatus::Moving { block_height } => block_height,
_ => return Err(CosmosGrpcError::ChainNotRunning),
};
let res = timeout(
self.get_timeout(),
grpc.validator_slashes(QueryValidatorSlashesRequest {
validator_address: validator_address.to_string(),
starting_height: 0,
ending_height: current_block,
pagination: PAGE,
}),
)
.await??
.into_inner();
Ok(res.slashes)
}
pub async fn withdraw_delegator_rewards(
&self,
validator_address: Address,
fee: Coin,
private_key: impl PrivateKey,
wait_timeout: Option<Duration>,
) -> Result<TransactionResponse, CosmosGrpcError> {
let our_address = private_key.to_address(&self.chain_prefix).unwrap();
let msg = MsgWithdrawDelegatorReward {
delegator_address: our_address.to_string(),
validator_address: validator_address.to_string(),
};
let msg = Msg::new(MSG_WITHDRAW_DELEGATOR_REWARD_TYPE_URL, msg);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
pub async fn query_delegator_validators(
&self,
delegator_address: Address,
) -> Result<Vec<String>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
DistQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.delegator_validators(QueryDelegatorValidatorsRequest {
delegator_address: delegator_address.to_string(),
}),
)
.await??
.into_inner();
Ok(res.validators)
}
pub async fn query_delegation_rewards(
&self,
delegator_address: Address,
validator_address: Address,
) -> Result<Vec<DecCoin>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
DistQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.delegation_rewards(QueryDelegationRewardsRequest {
delegator_address: delegator_address.to_string(),
validator_address: validator_address.to_string(),
}),
)
.await??
.into_inner()
.rewards;
Ok(res)
}
pub async fn query_all_delegation_rewards(
&self,
delegator_address: Address,
) -> Result<QueryDelegationTotalRewardsResponse, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
DistQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.delegation_total_rewards(QueryDelegationTotalRewardsRequest {
delegator_address: delegator_address.to_string(),
}),
)
.await??
.into_inner();
Ok(res)
}
pub async fn withdraw_all_delegator_rewards(
&self,
fee: Coin,
private_key: impl PrivateKey,
wait_timeout: Option<Duration>,
) -> Result<TransactionResponse, CosmosGrpcError> {
let our_address = private_key.to_address(&self.chain_prefix).unwrap();
let delegated = self.query_delegator_validators(our_address).await?;
let mut msgs = Vec::new();
for val in delegated {
let msg = MsgWithdrawDelegatorReward {
delegator_address: our_address.to_string(),
validator_address: val,
};
let msg = Msg::new(MSG_WITHDRAW_DELEGATOR_REWARD_TYPE_URL, msg);
msgs.push(msg);
}
self.send_message(&msgs, None, &[fee], wait_timeout, None, private_key)
.await
}
pub async fn withdraw_validator_commission(
&self,
validator_address: Address,
fee: Coin,
private_key: impl PrivateKey,
wait_timeout: Option<Duration>,
) -> Result<TransactionResponse, CosmosGrpcError> {
let msg = MsgWithdrawValidatorCommission {
validator_address: validator_address.to_string(),
};
let msg = Msg::new(MSG_WITHDRAW_VALIDATOR_COMMISSION_TYPE_URL, msg);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
pub async fn fund_community_pool(
&self,
amount: Vec<Coin>,
fee: Coin,
private_key: impl PrivateKey,
wait_timeout: Option<Duration>,
) -> Result<TransactionResponse, CosmosGrpcError> {
let our_address = private_key.to_address(&self.chain_prefix).unwrap();
let msg = MsgFundCommunityPool {
amount: amount.into_iter().map(|a| a.into()).collect(),
depositor: our_address.to_string(),
};
let msg = Msg::new(MSG_FUND_COMMUNITY_POOL_TYPE_URL, msg);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
}