use super::send::TransactionResponse;
use super::PAGE;
use crate::client::type_urls::{
MSG_BEGIN_REDELEGATE_TYPE_URL, MSG_DELEGATE_TYPE_URL, MSG_UNDELEGATE_TYPE_URL,
};
use crate::error::CosmosGrpcError;
use crate::Address;
use crate::Coin;
use crate::Contact;
use crate::Msg;
use crate::PrivateKey;
use cosmos_sdk_proto::cosmos::staking::v1beta1::query_client::QueryClient as StakingQueryClient;
use cosmos_sdk_proto::cosmos::staking::v1beta1::MsgBeginRedelegate;
use cosmos_sdk_proto::cosmos::staking::v1beta1::MsgUndelegate;
use cosmos_sdk_proto::cosmos::staking::v1beta1::QueryDelegationRequest;
use cosmos_sdk_proto::cosmos::staking::v1beta1::QueryValidatorDelegationsRequest;
use cosmos_sdk_proto::cosmos::staking::v1beta1::QueryValidatorsRequest;
use cosmos_sdk_proto::cosmos::staking::v1beta1::Validator;
use cosmos_sdk_proto::cosmos::staking::v1beta1::{DelegationResponse, QueryPoolRequest};
use cosmos_sdk_proto::cosmos::staking::v1beta1::{MsgDelegate, Pool};
use num256::Uint256;
use std::time::Duration;
use tokio::time::timeout;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StakingPool {
pub bonded_tokens: Uint256,
pub not_bonded_tokens: Uint256,
}
impl From<Pool> for StakingPool {
fn from(pool: Pool) -> Self {
StakingPool {
bonded_tokens: pool.bonded_tokens.parse().unwrap(),
not_bonded_tokens: pool.not_bonded_tokens.parse().unwrap(),
}
}
}
impl Contact {
pub async fn get_staking_pool_info(&self) -> Result<Pool, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
StakingQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(self.get_timeout(), grpc.pool(QueryPoolRequest {}))
.await??
.into_inner();
Ok(res.pool.unwrap())
}
pub async fn get_validators_list(
&self,
filters: QueryValidatorsRequest,
) -> Result<Vec<Validator>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
StakingQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(self.get_timeout(), grpc.validators(filters))
.await??
.into_inner()
.validators;
Ok(res)
}
pub async fn get_active_validators(&self) -> Result<Vec<Validator>, CosmosGrpcError> {
let req = QueryValidatorsRequest {
pagination: PAGE,
status: "BOND_STATUS_BONDED".to_string(),
};
self.get_validators_list(req).await
}
pub async fn get_validator_delegations(
&self,
validator: Address,
) -> Result<Vec<DelegationResponse>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
StakingQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.validator_delegations(QueryValidatorDelegationsRequest {
validator_addr: validator.to_string(),
pagination: PAGE,
}),
)
.await??
.into_inner()
.delegation_responses;
Ok(res)
}
pub async fn get_delegation(
&self,
validator: Address,
delegator: Address,
) -> Result<Option<DelegationResponse>, CosmosGrpcError> {
let mut grpc = timeout(
self.get_timeout(),
StakingQueryClient::connect(self.url.clone()),
)
.await??;
let res = timeout(
self.get_timeout(),
grpc.delegation(QueryDelegationRequest {
delegator_addr: delegator.to_string(),
validator_addr: validator.to_string(),
}),
)
.await??
.into_inner()
.delegation_response;
Ok(res)
}
pub async fn delegate_to_validator(
&self,
validator_address: Address,
amount_to_delegate: 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 vote = MsgDelegate {
amount: Some(amount_to_delegate.into()),
delegator_address: our_address.to_string(),
validator_address: validator_address.to_string(),
};
let msg = Msg::new(MSG_DELEGATE_TYPE_URL, vote);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
pub async fn redelegate(
&self,
validator_address: Address,
new_validator_address: Address,
amount_to_redelegate: 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 redelegate = MsgBeginRedelegate {
amount: Some(amount_to_redelegate.into()),
delegator_address: our_address.to_string(),
validator_src_address: validator_address.to_string(),
validator_dst_address: new_validator_address.to_string(),
};
let msg = Msg::new(MSG_BEGIN_REDELEGATE_TYPE_URL, redelegate);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
pub async fn undelegate(
&self,
validator_address: Address,
amount_to_undelegate: 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 undelegate = MsgUndelegate {
amount: Some(amount_to_undelegate.into()),
delegator_address: our_address.to_string(),
validator_address: validator_address.to_string(),
};
let msg = Msg::new(MSG_UNDELEGATE_TYPE_URL, undelegate);
self.send_message(&[msg], None, &[fee], wait_timeout, None, private_key)
.await
}
}