From b8f4777606acee81fb67cf69446c54df24975663 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 21 Jul 2023 17:26:15 +0200 Subject: [PATCH 01/20] Add cosmwasm_1_4 feature --- .vscode/settings.json | 9 +++++++-- packages/std/Cargo.toml | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3105948a84..411942acf5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "rust-analyzer.cargo.features": ["abort", "stargate", "staking", "cosmwasm_1_3"] -} + "rust-analyzer.cargo.features": [ + "abort", + "stargate", + "staking", + "cosmwasm_1_4" + ] +} \ No newline at end of file diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 8b2487fb7c..c24de72d95 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -44,6 +44,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] cosmwasm_1_3 = ["cosmwasm_1_2"] # Together with the `iterator` feature this enables additional imports for more # efficient iteration over DB keys or values. +# It also makes `DistributionQuery::DelegationRewards` available for the contract to call # It requires the host blockchain to run CosmWasm `1.4.0` or higher. cosmwasm_1_4 = ["cosmwasm_1_3"] From 77dd1c03af2cb5ea9fe92ee48b8487ec54c4e0ac Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 21 Jul 2023 18:17:05 +0200 Subject: [PATCH 02/20] Add DelegationRewards query --- packages/std/src/lib.rs | 8 +++--- packages/std/src/query/distribution.rs | 29 +++++++++++++++++++++- packages/std/src/testing/mock.rs | 34 +++++++++++++++++++++++++- packages/std/src/traits.rs | 18 ++++++++++++++ 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 6bccc14595..82858a063e 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -69,10 +69,10 @@ pub use crate::pagination::PageRequest; pub use crate::query::{ AllBalanceResponse, AllDelegationsResponse, AllDenomMetadataResponse, AllValidatorsResponse, BalanceResponse, BankQuery, BondedDenomResponse, ChannelResponse, CodeInfoResponse, - ContractInfoResponse, CustomQuery, Delegation, DelegationResponse, - DelegatorWithdrawAddressResponse, DenomMetadataResponse, DistributionQuery, FullDelegation, - IbcQuery, ListChannelsResponse, PortIdResponse, QueryRequest, StakingQuery, SupplyResponse, - Validator, ValidatorResponse, WasmQuery, + ContractInfoResponse, CustomQuery, DecCoin, Delegation, DelegationResponse, + DelegationRewardsResponse, DelegatorWithdrawAddressResponse, DenomMetadataResponse, + DistributionQuery, FullDelegation, IbcQuery, ListChannelsResponse, PortIdResponse, + QueryRequest, StakingQuery, SupplyResponse, Validator, ValidatorResponse, WasmQuery, }; #[allow(deprecated)] pub use crate::results::SubMsgExecutionResponse; diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index bd60fa2654..35252a05a5 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -10,7 +10,15 @@ use super::query_response::QueryResponseType; #[serde(rename_all = "snake_case")] pub enum DistributionQuery { // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L792-L795 - DelegatorWithdrawAddress { delegator_address: String }, + DelegatorWithdrawAddress { + delegator_address: String, + }, + // https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L525-L532 + #[cfg(feature = "cosmwasm_1_4")] + DelegationRewards { + delegator_address: String, + validator_address: String, + }, } // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L832-L835 @@ -24,3 +32,22 @@ pub struct DelegatorWithdrawAddressResponse { impl_response_constructor!(DelegatorWithdrawAddressResponse, withdraw_address: Addr); impl QueryResponseType for DelegatorWithdrawAddressResponse {} + +// https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L567-L572 +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct DelegationRewardsResponse { + pub rewards: Vec, +} + +impl_response_constructor!(DelegationRewardsResponse, rewards: Vec); +impl QueryResponseType for DelegationRewardsResponse {} + +/// A coin type with decimal amount. +/// Modeled after the Cosmos SDK's `DecCoin` type +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct DecCoin { + pub denom: String, + pub amount: crate::Decimal, +} diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index e3b0248cbf..257f5ac553 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -45,6 +45,8 @@ use crate::{ use crate::{Attribute, DenomMetadata}; #[cfg(feature = "stargate")] use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; +#[cfg(feature = "cosmwasm_1_4")] +use crate::{DecCoin, DelegationRewardsResponse}; use super::riffle_shuffle; @@ -935,12 +937,17 @@ impl StakingQuerier { #[derive(Clone, Default)] pub struct DistributionQuerier { withdraw_addresses: HashMap, + #[cfg(feature = "cosmwasm_1_4")] + rewards: BTreeMap<(String, String), Vec>, } #[cfg(feature = "cosmwasm_1_3")] impl DistributionQuerier { pub fn new(withdraw_addresses: HashMap) -> Self { - DistributionQuerier { withdraw_addresses } + DistributionQuerier { + withdraw_addresses, + ..Default::default() + } } pub fn set_withdraw_address( @@ -969,6 +976,17 @@ impl DistributionQuerier { self.withdraw_addresses.clear(); } + /// Sets accumulated rewards for a given validator and delegator pair. + pub fn set_rewards( + &mut self, + validator: impl Into, + delegator: impl Into, + rewards: Vec, + ) { + self.rewards + .insert((validator.into(), delegator.into()), rewards); + } + pub fn query(&self, request: &DistributionQuery) -> QuerierResult { let contract_result: ContractResult = match request { DistributionQuery::DelegatorWithdrawAddress { delegator_address } => { @@ -981,6 +999,20 @@ impl DistributionQuerier { }; to_binary(&res).into() } + #[cfg(feature = "cosmwasm_1_4")] + DistributionQuery::DelegationRewards { + delegator_address, + validator_address, + } => { + let res = DelegationRewardsResponse { + rewards: self + .rewards + .get(&(validator_address.clone(), delegator_address.clone())) + .cloned() + .unwrap_or_default(), + }; + to_binary(&res).into() + } }; // system result is always ok in the mock implementation SystemResult::Ok(contract_result) diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index 2118e189d2..3f7aef43c2 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -322,6 +322,24 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { self.query(&request) } + #[cfg(feature = "cosmwasm_1_4")] + pub fn query_delegation_rewards( + &self, + delegator: impl Into, + validator: impl Into, + ) -> StdResult> { + use crate::DelegationRewardsResponse; + + let request = DistributionQuery::DelegationRewards { + delegator_address: delegator.into(), + validator_address: validator.into(), + } + .into(); + let DelegationRewardsResponse { rewards } = self.query(&request)?; + + Ok(rewards) + } + /// Queries another wasm contract. You should know a priori the proper types for T and U /// (response and request) based on the contract API pub fn query_wasm_smart( From ace26ab429d07372155d28793604f7b0f9e75aae Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 21 Jul 2023 18:17:22 +0200 Subject: [PATCH 03/20] Add DelegationTotalRewards query --- packages/std/src/lib.rs | 7 ++-- packages/std/src/query/distribution.rs | 26 +++++++++++++ packages/std/src/testing/mock.rs | 54 ++++++++++++++++++++++++-- packages/std/src/traits.rs | 13 +++++++ 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 82858a063e..3b2954b4ce 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -70,9 +70,10 @@ pub use crate::query::{ AllBalanceResponse, AllDelegationsResponse, AllDenomMetadataResponse, AllValidatorsResponse, BalanceResponse, BankQuery, BondedDenomResponse, ChannelResponse, CodeInfoResponse, ContractInfoResponse, CustomQuery, DecCoin, Delegation, DelegationResponse, - DelegationRewardsResponse, DelegatorWithdrawAddressResponse, DenomMetadataResponse, - DistributionQuery, FullDelegation, IbcQuery, ListChannelsResponse, PortIdResponse, - QueryRequest, StakingQuery, SupplyResponse, Validator, ValidatorResponse, WasmQuery, + DelegationRewardsResponse, DelegationTotalRewardsResponse, DelegatorReward, + DelegatorWithdrawAddressResponse, DenomMetadataResponse, DistributionQuery, FullDelegation, + IbcQuery, ListChannelsResponse, PortIdResponse, QueryRequest, StakingQuery, SupplyResponse, + Validator, ValidatorResponse, WasmQuery, }; #[allow(deprecated)] pub use crate::results::SubMsgExecutionResponse; diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index 35252a05a5..152c79994f 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -19,6 +19,11 @@ pub enum DistributionQuery { delegator_address: String, validator_address: String, }, + // https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L614-L619 + #[cfg(feature = "cosmwasm_1_4")] + DelegationTotalRewards { + delegator_address: String, + }, } // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L832-L835 @@ -51,3 +56,24 @@ pub struct DecCoin { pub denom: String, pub amount: crate::Decimal, } + +// https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L654-L661 +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[non_exhaustive] +pub struct DelegationTotalRewardsResponse { + pub rewards: Vec, + pub total: Vec, +} + +impl_response_constructor!( + DelegationTotalRewardsResponse, + rewards: Vec, + total: Vec +); +impl QueryResponseType for DelegationTotalRewardsResponse {} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct DelegatorReward { + pub validator_address: String, + pub reward: Vec, +} diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 257f5ac553..31505a3f0f 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -46,7 +46,7 @@ use crate::{Attribute, DenomMetadata}; #[cfg(feature = "stargate")] use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; #[cfg(feature = "cosmwasm_1_4")] -use crate::{DecCoin, DelegationRewardsResponse}; +use crate::{DecCoin, Decimal, DelegationRewardsResponse}; use super::riffle_shuffle; @@ -938,7 +938,8 @@ impl StakingQuerier { pub struct DistributionQuerier { withdraw_addresses: HashMap, #[cfg(feature = "cosmwasm_1_4")] - rewards: BTreeMap<(String, String), Vec>, + /// Mock of accumulated rewards, indexed first by delegator and then validator address. + rewards: BTreeMap>>, } #[cfg(feature = "cosmwasm_1_3")] @@ -984,7 +985,9 @@ impl DistributionQuerier { rewards: Vec, ) { self.rewards - .insert((validator.into(), delegator.into()), rewards); + .entry(delegator.into()) + .or_default() + .insert(validator.into(), rewards); } pub fn query(&self, request: &DistributionQuery) -> QuerierResult { @@ -1007,16 +1010,59 @@ impl DistributionQuerier { let res = DelegationRewardsResponse { rewards: self .rewards - .get(&(validator_address.clone(), delegator_address.clone())) + .get(delegator_address) + .and_then(|v| v.get(validator_address)) .cloned() .unwrap_or_default(), }; to_binary(&res).into() } + #[cfg(feature = "cosmwasm_1_4")] + DistributionQuery::DelegationTotalRewards { delegator_address } => { + let validator_rewards = self + .validator_rewards(delegator_address) + .unwrap_or_default(); + let res = crate::DelegationTotalRewardsResponse { + total: validator_rewards + .iter() + .fold(BTreeMap::<&str, DecCoin>::new(), |mut acc, rewards| { + for coin in &rewards.reward { + acc.entry(&coin.denom) + .or_insert_with(|| DecCoin { + denom: coin.denom.clone(), + amount: Decimal::zero(), + }) + .amount += coin.amount; + } + + acc + }) + .into_values() + .collect(), + rewards: validator_rewards, + }; + to_binary(&res).into() + } }; // system result is always ok in the mock implementation SystemResult::Ok(contract_result) } + + /// Helper method to get all rewards for a given delegator. + #[cfg(feature = "cosmwasm_1_4")] + fn validator_rewards(&self, delegator_address: &str) -> Option> { + let validator_rewards = self.rewards.get(delegator_address)?; + + Some( + validator_rewards + .iter() + .map(|(validator, rewards)| crate::DelegatorReward { + validator_address: validator.clone(), + reward: rewards.clone(), + }) + .collect(), + ) + } } pub fn digit_sum(input: &[u8]) -> usize { diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index 3f7aef43c2..5895b87a11 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -340,6 +340,19 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { Ok(rewards) } + #[cfg(feature = "cosmwasm_1_4")] + pub fn query_delegation_total_rewards( + &self, + delegator: impl Into, + validator: impl Into, + ) -> StdResult { + let request = DistributionQuery::DelegationTotalRewards { + delegator_address: delegator.into(), + } + .into(); + self.query(&request) + } + /// Queries another wasm contract. You should know a priori the proper types for T and U /// (response and request) based on the contract API pub fn query_wasm_smart( From 0fc4bb37e1d5c487a7c62d77d549f635e044ab1b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 21 Jul 2023 18:23:16 +0200 Subject: [PATCH 04/20] Fix mock --- packages/std/src/testing/mock.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 31505a3f0f..98841e5a55 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -937,9 +937,9 @@ impl StakingQuerier { #[derive(Clone, Default)] pub struct DistributionQuerier { withdraw_addresses: HashMap, - #[cfg(feature = "cosmwasm_1_4")] /// Mock of accumulated rewards, indexed first by delegator and then validator address. - rewards: BTreeMap>>, + #[cfg(feature = "cosmwasm_1_4")] + rewards: BTreeMap>>, } #[cfg(feature = "cosmwasm_1_3")] @@ -978,6 +978,7 @@ impl DistributionQuerier { } /// Sets accumulated rewards for a given validator and delegator pair. + #[cfg(feature = "cosmwasm_1_4")] pub fn set_rewards( &mut self, validator: impl Into, From 5fde07a45e6859da6961067b722634187d7ba330 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 24 Jul 2023 09:20:19 +0200 Subject: [PATCH 05/20] Disable clippy lint --- packages/std/src/testing/mock.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 98841e5a55..a52d554d1d 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -945,6 +945,7 @@ pub struct DistributionQuerier { #[cfg(feature = "cosmwasm_1_3")] impl DistributionQuerier { pub fn new(withdraw_addresses: HashMap) -> Self { + #[allow(clippy::needless_update)] DistributionQuerier { withdraw_addresses, ..Default::default() From 60dae3a250e87bd44d0c190a58ed322db9df8a42 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 25 Jul 2023 12:10:18 +0200 Subject: [PATCH 06/20] Link to protobuf files instead of generated code --- packages/std/src/query/distribution.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index 152c79994f..c6c511b366 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -9,24 +9,20 @@ use super::query_response::QueryResponseType; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum DistributionQuery { - // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L792-L795 - DelegatorWithdrawAddress { - delegator_address: String, - }, - // https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L525-L532 + /// See + DelegatorWithdrawAddress { delegator_address: String }, + /// See #[cfg(feature = "cosmwasm_1_4")] DelegationRewards { delegator_address: String, validator_address: String, }, - // https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L614-L619 + /// See #[cfg(feature = "cosmwasm_1_4")] - DelegationTotalRewards { - delegator_address: String, - }, + DelegationTotalRewards { delegator_address: String }, } -// https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L832-L835 +/// See #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] #[non_exhaustive] @@ -38,7 +34,7 @@ impl_response_constructor!(DelegatorWithdrawAddressResponse, withdraw_address: A impl QueryResponseType for DelegatorWithdrawAddressResponse {} -// https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L567-L572 +/// See #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct DelegationRewardsResponse { @@ -49,7 +45,7 @@ impl_response_constructor!(DelegationRewardsResponse, rewards: Vec); impl QueryResponseType for DelegationRewardsResponse {} /// A coin type with decimal amount. -/// Modeled after the Cosmos SDK's `DecCoin` type +/// Modeled after the Cosmos SDK's [DecCoin](https://github.com/cosmos/cosmos-sdk/blob/c74e2887b0b73e81d48c2f33e6b1020090089ee0/proto/cosmos/base/v1beta1/coin.proto#L32-L41) type #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct DecCoin { @@ -57,7 +53,7 @@ pub struct DecCoin { pub amount: crate::Decimal, } -// https://github.com/cosmos/cosmos-sdk/blob/e3482f2d4142c55f9dc3f47a321b56610a11492c/x/distribution/types/query.pb.go#L654-L661 +/// See #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[non_exhaustive] pub struct DelegationTotalRewardsResponse { From 306ea202dba1bf7cd9187ee27550c041917e6055 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 25 Jul 2023 17:20:20 +0200 Subject: [PATCH 07/20] Add DelegatorValidators query --- packages/std/src/lib.rs | 6 ++-- packages/std/src/query/distribution.rs | 13 +++++++- packages/std/src/testing/mock.rs | 43 ++++++++++++++++++++++---- packages/std/src/traits.rs | 16 +++++++++- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 3b2954b4ce..99706aa22b 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -71,9 +71,9 @@ pub use crate::query::{ BalanceResponse, BankQuery, BondedDenomResponse, ChannelResponse, CodeInfoResponse, ContractInfoResponse, CustomQuery, DecCoin, Delegation, DelegationResponse, DelegationRewardsResponse, DelegationTotalRewardsResponse, DelegatorReward, - DelegatorWithdrawAddressResponse, DenomMetadataResponse, DistributionQuery, FullDelegation, - IbcQuery, ListChannelsResponse, PortIdResponse, QueryRequest, StakingQuery, SupplyResponse, - Validator, ValidatorResponse, WasmQuery, + DelegatorValidatorsResponse, DelegatorWithdrawAddressResponse, DenomMetadataResponse, + DistributionQuery, FullDelegation, IbcQuery, ListChannelsResponse, PortIdResponse, + QueryRequest, StakingQuery, SupplyResponse, Validator, ValidatorResponse, WasmQuery, }; #[allow(deprecated)] pub use crate::results::SubMsgExecutionResponse; diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index c6c511b366..fd052ba651 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -20,6 +20,9 @@ pub enum DistributionQuery { /// See #[cfg(feature = "cosmwasm_1_4")] DelegationTotalRewards { delegator_address: String }, + /// See + #[cfg(feature = "cosmwasm_1_4")] + DelegatorValidators { delegator_address: String }, } /// See @@ -31,7 +34,6 @@ pub struct DelegatorWithdrawAddressResponse { } impl_response_constructor!(DelegatorWithdrawAddressResponse, withdraw_address: Addr); - impl QueryResponseType for DelegatorWithdrawAddressResponse {} /// See @@ -73,3 +75,12 @@ pub struct DelegatorReward { pub validator_address: String, pub reward: Vec, } + +/// See +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct DelegatorValidatorsResponse { + pub validators: Vec, +} + +impl_response_constructor!(DelegatorValidatorsResponse, validators: Vec); +impl QueryResponseType for DelegatorValidatorsResponse {} diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index a52d554d1d..7b7d3f043d 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -5,6 +5,8 @@ use core::ops::Bound; use serde::de::DeserializeOwned; #[cfg(feature = "stargate")] use serde::Serialize; +#[cfg(feature = "cosmwasm_1_3")] +use std::collections::BTreeSet; use std::collections::HashMap; use crate::addresses::{Addr, CanonicalAddr}; @@ -39,7 +41,7 @@ use crate::traits::{Api, Querier, QuerierResult}; use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo}; #[cfg(feature = "cosmwasm_1_3")] use crate::{ - query::{AllDenomMetadataResponse, DenomMetadataResponse}, + query::{AllDenomMetadataResponse, DelegatorValidatorsResponse, DenomMetadataResponse}, PageRequest, }; use crate::{Attribute, DenomMetadata}; @@ -938,14 +940,14 @@ impl StakingQuerier { pub struct DistributionQuerier { withdraw_addresses: HashMap, /// Mock of accumulated rewards, indexed first by delegator and then validator address. - #[cfg(feature = "cosmwasm_1_4")] rewards: BTreeMap>>, + /// Mock of validators that a delegator has bonded to. + validators: BTreeMap>, } #[cfg(feature = "cosmwasm_1_3")] impl DistributionQuerier { pub fn new(withdraw_addresses: HashMap) -> Self { - #[allow(clippy::needless_update)] DistributionQuerier { withdraw_addresses, ..Default::default() @@ -979,17 +981,35 @@ impl DistributionQuerier { } /// Sets accumulated rewards for a given validator and delegator pair. - #[cfg(feature = "cosmwasm_1_4")] pub fn set_rewards( &mut self, validator: impl Into, delegator: impl Into, rewards: Vec, ) { + let delegator = delegator.into(); + let validator = validator.into(); self.rewards - .entry(delegator.into()) + .entry(delegator.clone()) + .or_default() + .insert(validator.clone(), rewards); + // also add to validator set + self.validators + .entry(delegator) .or_default() - .insert(validator.into(), rewards); + .insert(validator); + } + + /// Sets the validators a given delegator has bonded to. + pub fn set_validators( + &mut self, + delegator: impl Into, + validators: impl IntoIterator>, + ) { + self.validators.insert( + delegator.into(), + validators.into_iter().map(Into::into).collect(), + ); } pub fn query(&self, request: &DistributionQuery) -> QuerierResult { @@ -1045,6 +1065,17 @@ impl DistributionQuerier { }; to_binary(&res).into() } + #[cfg(feature = "cosmwasm_1_4")] + DistributionQuery::DelegatorValidators { delegator_address } => { + let res = DelegatorValidatorsResponse { + validators: self + .validators + .get(delegator_address) + .map(|set| set.iter().cloned().collect()) + .unwrap_or_default(), + }; + to_binary(&res).into() + } }; // system result is always ok in the mock implementation SystemResult::Ok(contract_result) diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index 5895b87a11..a5402660d1 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -344,7 +344,6 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { pub fn query_delegation_total_rewards( &self, delegator: impl Into, - validator: impl Into, ) -> StdResult { let request = DistributionQuery::DelegationTotalRewards { delegator_address: delegator.into(), @@ -353,6 +352,21 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { self.query(&request) } + #[cfg(feature = "cosmwasm_1_4")] + pub fn query_delegator_validators( + &self, + delegator: impl Into, + ) -> StdResult> { + use crate::DelegatorValidatorsResponse; + + let request = DistributionQuery::DelegatorValidators { + delegator_address: delegator.into(), + } + .into(); + let res: DelegatorValidatorsResponse = self.query(&request)?; + Ok(res.validators) + } + /// Queries another wasm contract. You should know a priori the proper types for T and U /// (response and request) based on the contract API pub fn query_wasm_smart( From fbea4b8e4c6a7a6bc499e42c7ea8053e397ff714 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 25 Jul 2023 17:34:29 +0200 Subject: [PATCH 08/20] Add cosmwasm_1_4 capability --- packages/check/src/main.rs | 2 +- packages/vm/src/testing/instance.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/check/src/main.rs b/packages/check/src/main.rs index 6ba097470f..48998f889f 100644 --- a/packages/check/src/main.rs +++ b/packages/check/src/main.rs @@ -11,7 +11,7 @@ use cosmwasm_vm::capabilities_from_csv; use cosmwasm_vm::internals::{check_wasm, compile, make_compiling_engine}; const DEFAULT_AVAILABLE_CAPABILITIES: &str = - "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3"; + "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4"; pub fn main() { let matches = Command::new("Contract checking") diff --git a/packages/vm/src/testing/instance.rs b/packages/vm/src/testing/instance.rs index 0b94321d7e..ce1ba84c07 100644 --- a/packages/vm/src/testing/instance.rs +++ b/packages/vm/src/testing/instance.rs @@ -98,8 +98,9 @@ pub struct MockInstanceOptions<'a> { impl MockInstanceOptions<'_> { fn default_capabilities() -> HashSet { #[allow(unused_mut)] - let mut out = - capabilities_from_csv("iterator,staking,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3"); + let mut out = capabilities_from_csv( + "iterator,staking,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4", + ); #[cfg(feature = "stargate")] out.insert("stargate".to_string()); out From 8480348db7ac11e1e062cd669d71f99ee284cc69 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 25 Jul 2023 18:18:36 +0200 Subject: [PATCH 09/20] Add tests for new distribution querier mocks --- packages/std/src/query/distribution.rs | 9 ++ packages/std/src/testing/mock.rs | 109 +++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index fd052ba651..b59b83b50e 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -55,6 +55,15 @@ pub struct DecCoin { pub amount: crate::Decimal, } +impl DecCoin { + pub fn new(amount: crate::Decimal, denom: impl Into) -> Self { + Self { + denom: denom.into(), + amount, + } + } +} + /// See #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[non_exhaustive] diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 7b7d3f043d..d4a6547939 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -987,17 +987,10 @@ impl DistributionQuerier { delegator: impl Into, rewards: Vec, ) { - let delegator = delegator.into(); - let validator = validator.into(); self.rewards - .entry(delegator.clone()) + .entry(delegator.into()) .or_default() - .insert(validator.clone(), rewards); - // also add to validator set - self.validators - .entry(delegator) - .or_default() - .insert(validator); + .insert(validator.into(), rewards); } /// Sets the validators a given delegator has bonded to. @@ -1656,6 +1649,104 @@ mod tests { assert_eq!(res.withdraw_address, "addr1"); } + #[cfg(feature = "cosmwasm_1_4")] + #[test] + fn distribution_querier_delegator_validators() { + let mut distribution = DistributionQuerier::default(); + distribution.set_validators("addr0", ["valoper1", "valoper2"]); + + let query = DistributionQuery::DelegatorValidators { + delegator_address: "addr0".to_string(), + }; + + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegatorValidatorsResponse = from_binary(&res).unwrap(); + assert_eq!(res.validators, ["valoper1", "valoper2"]); + + let query = DistributionQuery::DelegatorValidators { + delegator_address: "addr1".to_string(), + }; + + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegatorValidatorsResponse = from_binary(&res).unwrap(); + assert_eq!(res.validators, ([] as [String; 0])); + } + + #[cfg(feature = "cosmwasm_1_4")] + #[test] + fn distribution_querier_delegation_rewards() { + use crate::{DelegationTotalRewardsResponse, DelegatorReward}; + + let mut distribution = DistributionQuerier::default(); + let valoper0_rewards = vec![ + DecCoin::new(Decimal::from_atomics(1234u128, 0).unwrap(), "uatom"), + DecCoin::new(Decimal::from_atomics(56781234u128, 4).unwrap(), "utest"), + ]; + distribution.set_rewards("valoper0", "addr0", valoper0_rewards.clone()); + + // both exist / are set + let query = DistributionQuery::DelegationRewards { + delegator_address: "addr0".to_string(), + validator_address: "valoper0".to_string(), + }; + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegationRewardsResponse = from_binary(&res).unwrap(); + assert_eq!(res.rewards, valoper0_rewards); + + // delegator does not exist + let query = DistributionQuery::DelegationRewards { + delegator_address: "nonexistent".to_string(), + validator_address: "valoper0".to_string(), + }; + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegationRewardsResponse = from_binary(&res).unwrap(); + assert_eq!(res.rewards.len(), 0); + + // validator does not exist + let query = DistributionQuery::DelegationRewards { + delegator_address: "addr0".to_string(), + validator_address: "valopernonexistent".to_string(), + }; + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegationRewardsResponse = from_binary(&res).unwrap(); + assert_eq!(res.rewards.len(), 0); + + // add one more validator + let valoper1_rewards = vec![DecCoin::new(Decimal::one(), "uatom")]; + distribution.set_rewards("valoper1", "addr0", valoper1_rewards.clone()); + + // total rewards + let query = DistributionQuery::DelegationTotalRewards { + delegator_address: "addr0".to_string(), + }; + let res = distribution.query(&query).unwrap().unwrap(); + let res: DelegationTotalRewardsResponse = from_binary(&res).unwrap(); + assert_eq!( + res.rewards, + vec![ + DelegatorReward { + validator_address: "valoper0".into(), + reward: valoper0_rewards + }, + DelegatorReward { + validator_address: "valoper1".into(), + reward: valoper1_rewards + }, + ] + ); + assert_eq!( + res.total, + [ + DecCoin::new( + Decimal::from_atomics(1234u128, 0).unwrap() + Decimal::one(), + "uatom" + ), + // total for utest should still be the same + DecCoin::new(Decimal::from_atomics(56781234u128, 4).unwrap(), "utest") + ] + ); + } + #[cfg(feature = "stargate")] #[test] fn ibc_querier_channel_existing() { From 3210d26e43fa47278698728e0b1d39a757ec4a08 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 26 Jul 2023 10:43:28 +0200 Subject: [PATCH 10/20] Fix build --- packages/std/src/testing/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index d4a6547939..b3003508f5 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -41,14 +41,14 @@ use crate::traits::{Api, Querier, QuerierResult}; use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo}; #[cfg(feature = "cosmwasm_1_3")] use crate::{ - query::{AllDenomMetadataResponse, DelegatorValidatorsResponse, DenomMetadataResponse}, + query::{AllDenomMetadataResponse, DecCoin, DenomMetadataResponse}, PageRequest, }; use crate::{Attribute, DenomMetadata}; #[cfg(feature = "stargate")] use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; #[cfg(feature = "cosmwasm_1_4")] -use crate::{DecCoin, Decimal, DelegationRewardsResponse}; +use crate::{Decimal, DelegationRewardsResponse, DelegatorValidatorsResponse}; use super::riffle_shuffle; From 09d9a61f67d2ae5096975e0346569fef258c31d8 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 26 Jul 2023 15:58:13 +0200 Subject: [PATCH 11/20] Use cosmwasm_1_4 feature in ci --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fd8abd4538..bae052e68f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -356,15 +356,15 @@ jobs: - run: name: Build library for native target (all features) working_directory: ~/project/packages/std - command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_3 + command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_4 - run: name: Build library for wasm target (all features) working_directory: ~/project/packages/std - command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_3 + command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_4 - run: name: Run unit tests (all features) working_directory: ~/project/packages/std - command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_3 + command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_4 - save_cache: paths: - /usr/local/cargo/registry @@ -907,7 +907,7 @@ jobs: - run: name: Clippy linting on std (all feature flags) working_directory: ~/project/packages/std - command: cargo clippy --all-targets --features abort,iterator,staking,stargate,cosmwasm_1_3 -- -D warnings + command: cargo clippy --all-targets --features abort,iterator,staking,stargate,cosmwasm_1_4 -- -D warnings - run: name: Clippy linting on storage (no feature flags) working_directory: ~/project/packages/storage @@ -984,7 +984,7 @@ jobs: CRYPTO=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/crypto --packages cosmwasm-crypto" DERIVE=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/derive --packages cosmwasm-derive" SCHEMA=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/schema --packages cosmwasm-schema" - STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features abort,iterator,staking,stargate,cosmwasm_1_3" + STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features abort,iterator,staking,stargate,cosmwasm_1_4" STORAGE="cargo tarpaulin --skip-clean --out Xml --output-dir reports/storage --packages cosmwasm-storage" docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.21.0 \ sh -c "$CRYPTO && $DERIVE && $SCHEMA && $STD && $STORAGE" From e063fae3dd57d26bb4058aec511bf1904bd465e5 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 26 Jul 2023 16:07:34 +0200 Subject: [PATCH 12/20] Add cosmwasm_1_4 export --- packages/std/src/exports.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index 473f63a36b..8f057712d4 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -53,6 +53,10 @@ extern "C" fn requires_cosmwasm_1_2() -> () {} #[no_mangle] extern "C" fn requires_cosmwasm_1_3() -> () {} +#[cfg(feature = "cosmwasm_1_4")] +#[no_mangle] +extern "C" fn requires_cosmwasm_1_4() -> () {} + /// interface_version_* exports mark which Wasm VM interface level this contract is compiled for. /// They can be checked by cosmwasm_vm. /// Update this whenever the Wasm VM interface breaks. From 52910b64060aa352f761954532267fdf5d32fcc8 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 26 Jul 2023 16:46:50 +0200 Subject: [PATCH 13/20] Add cosmwasm_1_4 capability docs --- docs/CAPABILITIES-BUILT-IN.md | 4 ++++ docs/USING_COSMWASM_STD.md | 1 + 2 files changed, 5 insertions(+) diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md index 2f2268e4e7..bf31681e9d 100644 --- a/docs/CAPABILITIES-BUILT-IN.md +++ b/docs/CAPABILITIES-BUILT-IN.md @@ -19,3 +19,7 @@ might define others. `BankQuery::DenomMetadata` and `DistributionQuery::DelegatorWithdrawAddress` queries, as well as `DistributionMsg::FundCommunityPool`. Only chains running CosmWasm `1.3.0` or higher support this. +- `cosmwasm_1_4` enables the `DistributionQuery::DelegationRewards`, + `DistributionQuery::DelegationTotalRewards` and + `DistributionQuery::DelegatorValidators` queries. Only chains running CosmWasm + `1.4.0` or higher support this. diff --git a/docs/USING_COSMWASM_STD.md b/docs/USING_COSMWASM_STD.md index 36730f9945..19a04bdb66 100644 --- a/docs/USING_COSMWASM_STD.md +++ b/docs/USING_COSMWASM_STD.md @@ -45,6 +45,7 @@ The libarary comes with the following features: | cosmwasm_1_1 | | Features that require CosmWasm 1.1+ on the chain | | cosmwasm_1_2 | | Features that require CosmWasm 1.2+ on the chain | | cosmwasm_1_3 | | Features that require CosmWasm 1.3+ on the chain | +| cosmwasm_1_4 | | Features that require CosmWasm 1.4+ on the chain | ## The cosmwasm-std dependency for contract developers From 16ff40b036d4639dec9223f0376875fe84f96c72 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 25 Aug 2023 11:58:38 +0200 Subject: [PATCH 14/20] Enable cosmwasm_1_4 feature in go-gen --- packages/go-gen/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/go-gen/Cargo.toml b/packages/go-gen/Cargo.toml index 5f3ad6ed74..5b0a24d80e 100644 --- a/packages/go-gen/Cargo.toml +++ b/packages/go-gen/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dependencies] schemars = "0.8.3" -cosmwasm-std = { path = "../std", version = "1.4.0-beta.1", features = ["cosmwasm_1_3", "staking", "stargate", "ibc3"] } +cosmwasm-std = { path = "../std", version = "1.4.0-beta.1", features = ["cosmwasm_1_4", "staking", "stargate", "ibc3"] } cosmwasm-schema = { path = "../schema", version = "1.4.0-beta.1" } anyhow = "1" Inflector = "0.11.4" From f49390197c5a7a722f49e7df04cfea8b477e364e Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 25 Aug 2023 16:31:13 +0200 Subject: [PATCH 15/20] Add new query responses to go-gen tests --- packages/go-gen/src/main.rs | 3 +++ .../cosmwasm_std__DelegationRewardsResponse.go | 10 ++++++++++ ...wasm_std__DelegationTotalRewardsResponse.go | 16 ++++++++++++++++ ...osmwasm_std__DelegatorValidatorsResponse.go | 4 ++++ .../tests/cosmwasm_std__DistributionQuery.go | 18 +++++++++++++++++- 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 packages/go-gen/tests/cosmwasm_std__DelegationRewardsResponse.go create mode 100644 packages/go-gen/tests/cosmwasm_std__DelegationTotalRewardsResponse.go create mode 100644 packages/go-gen/tests/cosmwasm_std__DelegatorValidatorsResponse.go diff --git a/packages/go-gen/src/main.rs b/packages/go-gen/src/main.rs index 7688db1878..8d3dcc3d40 100644 --- a/packages/go-gen/src/main.rs +++ b/packages/go-gen/src/main.rs @@ -352,6 +352,9 @@ mod tests { // compare_codes!(cosmwasm_std::ValidatorResponse); // does not use "omitempty" for `Validator` field // distribution compare_codes!(cosmwasm_std::DelegatorWithdrawAddressResponse); + compare_codes!(cosmwasm_std::DelegationRewardsResponse); + compare_codes!(cosmwasm_std::DelegationTotalRewardsResponse); + compare_codes!(cosmwasm_std::DelegatorValidatorsResponse); // wasm compare_codes!(cosmwasm_std::ContractInfoResponse); // compare_codes!(cosmwasm_std::CodeInfoResponse); // TODO: Checksum type and "omitempty" diff --git a/packages/go-gen/tests/cosmwasm_std__DelegationRewardsResponse.go b/packages/go-gen/tests/cosmwasm_std__DelegationRewardsResponse.go new file mode 100644 index 0000000000..8779f696dc --- /dev/null +++ b/packages/go-gen/tests/cosmwasm_std__DelegationRewardsResponse.go @@ -0,0 +1,10 @@ +// See +type DelegationRewardsResponse struct { + Rewards []DecCoin `json:"rewards"` +} + +// A coin type with decimal amount. Modeled after the Cosmos SDK's [DecCoin](https://github.com/cosmos/cosmos-sdk/blob/c74e2887b0b73e81d48c2f33e6b1020090089ee0/proto/cosmos/base/v1beta1/coin.proto#L32-L41) type +type DecCoin struct { + Amount string `json:"amount"` + Denom string `json:"denom"` +} \ No newline at end of file diff --git a/packages/go-gen/tests/cosmwasm_std__DelegationTotalRewardsResponse.go b/packages/go-gen/tests/cosmwasm_std__DelegationTotalRewardsResponse.go new file mode 100644 index 0000000000..772861c71b --- /dev/null +++ b/packages/go-gen/tests/cosmwasm_std__DelegationTotalRewardsResponse.go @@ -0,0 +1,16 @@ +// See +type DelegationTotalRewardsResponse struct { + Rewards []DelegatorReward `json:"rewards"` + Total []DecCoin `json:"total"` +} + +// A coin type with decimal amount. Modeled after the Cosmos SDK's [DecCoin](https://github.com/cosmos/cosmos-sdk/blob/c74e2887b0b73e81d48c2f33e6b1020090089ee0/proto/cosmos/base/v1beta1/coin.proto#L32-L41) type +type DecCoin struct { + Amount string `json:"amount"` + Denom string `json:"denom"` +} + +type DelegatorReward struct { + Reward []DecCoin `json:"reward"` + ValidatorAddress string `json:"validator_address"` +} \ No newline at end of file diff --git a/packages/go-gen/tests/cosmwasm_std__DelegatorValidatorsResponse.go b/packages/go-gen/tests/cosmwasm_std__DelegatorValidatorsResponse.go new file mode 100644 index 0000000000..3b831e04ad --- /dev/null +++ b/packages/go-gen/tests/cosmwasm_std__DelegatorValidatorsResponse.go @@ -0,0 +1,4 @@ +// See +type DelegatorValidatorsResponse struct { + Validators []string `json:"validators"` +} \ No newline at end of file diff --git a/packages/go-gen/tests/cosmwasm_std__DistributionQuery.go b/packages/go-gen/tests/cosmwasm_std__DistributionQuery.go index 79b541a7a1..5d33c3805d 100644 --- a/packages/go-gen/tests/cosmwasm_std__DistributionQuery.go +++ b/packages/go-gen/tests/cosmwasm_std__DistributionQuery.go @@ -1,8 +1,24 @@ - type DelegatorWithdrawAddressQuery struct { DelegatorAddress string `json:"delegator_address"` } +type DelegationRewardsQuery struct { + DelegatorAddress string `json:"delegator_address"` + ValidatorAddress string `json:"validator_address"` +} +type DelegationTotalRewardsQuery struct { + DelegatorAddress string `json:"delegator_address"` +} +type DelegatorValidatorsQuery struct { + DelegatorAddress string `json:"delegator_address"` +} type DistributionQuery struct { + // See DelegatorWithdrawAddress *DelegatorWithdrawAddressQuery `json:"delegator_withdraw_address,omitempty"` + // See + DelegationRewards *DelegationRewardsQuery `json:"delegation_rewards,omitempty"` + // See + DelegationTotalRewards *DelegationTotalRewardsQuery `json:"delegation_total_rewards,omitempty"` + // See + DelegatorValidators *DelegatorValidatorsQuery `json:"delegator_validators,omitempty"` } \ No newline at end of file From 75bc92c2efaa3801105567b9769c5ee0360eaad3 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 28 Aug 2023 14:12:17 +0200 Subject: [PATCH 16/20] Fix DecCoin::amount Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- packages/go-gen/src/schema.rs | 1 + packages/std/src/query/distribution.rs | 8 ++++++-- packages/std/src/testing/mock.rs | 16 ++++++++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/go-gen/src/schema.rs b/packages/go-gen/src/schema.rs index 22e6fd7c97..9d9a3fa866 100644 --- a/packages/go-gen/src/schema.rs +++ b/packages/go-gen/src/schema.rs @@ -264,6 +264,7 @@ pub fn custom_type_of(ty: &str) -> Option<&str> { "HexBinary" => Some("Checksum"), "Addr" => Some("string"), "Decimal" => Some("string"), + "Decimal256" => Some("string"), _ => None, } } diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index b59b83b50e..dc6d096a68 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -52,11 +52,15 @@ impl QueryResponseType for DelegationRewardsResponse {} #[serde(rename_all = "snake_case")] pub struct DecCoin { pub denom: String, - pub amount: crate::Decimal, + /// An amount in the base denom of the distributed token. + /// + /// Some chains have choosen atto (10^-18) for their token's base denomination. If we used `Decimal` here, we could only store + /// 340282366920938463463.374607431768211455atoken which is 340.28 TOKEN. + pub amount: crate::Decimal256, } impl DecCoin { - pub fn new(amount: crate::Decimal, denom: impl Into) -> Self { + pub fn new(amount: crate::Decimal256, denom: impl Into) -> Self { Self { denom: denom.into(), amount, diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index b3003508f5..305af4afb1 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -48,7 +48,7 @@ use crate::{Attribute, DenomMetadata}; #[cfg(feature = "stargate")] use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; #[cfg(feature = "cosmwasm_1_4")] -use crate::{Decimal, DelegationRewardsResponse, DelegatorValidatorsResponse}; +use crate::{Decimal256, DelegationRewardsResponse, DelegatorValidatorsResponse}; use super::riffle_shuffle; @@ -1045,7 +1045,7 @@ impl DistributionQuerier { acc.entry(&coin.denom) .or_insert_with(|| DecCoin { denom: coin.denom.clone(), - amount: Decimal::zero(), + amount: Decimal256::zero(), }) .amount += coin.amount; } @@ -1675,12 +1675,12 @@ mod tests { #[cfg(feature = "cosmwasm_1_4")] #[test] fn distribution_querier_delegation_rewards() { - use crate::{DelegationTotalRewardsResponse, DelegatorReward}; + use crate::{Decimal256, DelegationTotalRewardsResponse, DelegatorReward}; let mut distribution = DistributionQuerier::default(); let valoper0_rewards = vec![ - DecCoin::new(Decimal::from_atomics(1234u128, 0).unwrap(), "uatom"), - DecCoin::new(Decimal::from_atomics(56781234u128, 4).unwrap(), "utest"), + DecCoin::new(Decimal256::from_atomics(1234u128, 0).unwrap(), "uatom"), + DecCoin::new(Decimal256::from_atomics(56781234u128, 4).unwrap(), "utest"), ]; distribution.set_rewards("valoper0", "addr0", valoper0_rewards.clone()); @@ -1712,7 +1712,7 @@ mod tests { assert_eq!(res.rewards.len(), 0); // add one more validator - let valoper1_rewards = vec![DecCoin::new(Decimal::one(), "uatom")]; + let valoper1_rewards = vec![DecCoin::new(Decimal256::one(), "uatom")]; distribution.set_rewards("valoper1", "addr0", valoper1_rewards.clone()); // total rewards @@ -1738,11 +1738,11 @@ mod tests { res.total, [ DecCoin::new( - Decimal::from_atomics(1234u128, 0).unwrap() + Decimal::one(), + Decimal256::from_atomics(1234u128, 0).unwrap() + Decimal256::one(), "uatom" ), // total for utest should still be the same - DecCoin::new(Decimal::from_atomics(56781234u128, 4).unwrap(), "utest") + DecCoin::new(Decimal256::from_atomics(56781234u128, 4).unwrap(), "utest") ] ); } From 8193b2d2c978f544cb795bd17f8775fa7caeb712 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 28 Aug 2023 14:16:27 +0200 Subject: [PATCH 17/20] Add suggested DecCoin docs Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- packages/std/src/query/distribution.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index dc6d096a68..0414ef7927 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -47,7 +47,14 @@ impl_response_constructor!(DelegationRewardsResponse, rewards: Vec); impl QueryResponseType for DelegationRewardsResponse {} /// A coin type with decimal amount. -/// Modeled after the Cosmos SDK's [DecCoin](https://github.com/cosmos/cosmos-sdk/blob/c74e2887b0b73e81d48c2f33e6b1020090089ee0/proto/cosmos/base/v1beta1/coin.proto#L32-L41) type +/// Modeled after the Cosmos SDK's [DecCoin] type. +/// However, in contrast to the Cosmos SDK the `amount` string MUST always have a dot at JSON level, +/// see . +/// Also if Cosmos SDK choses to migrate away from fixed point decimals +/// (as shown [here](https://github.com/cosmos/cosmos-sdk/blob/v0.47.4/x/group/internal/math/dec.go#L13-L21 and discussed [here](https://github.com/cosmos/cosmos-sdk/issues/11783)), +/// wasmd needs to truncate the decimal places to 18. +/// +/// [DecCoin]: (https://github.com/cosmos/cosmos-sdk/blob/v0.47.4/proto/cosmos/base/v1beta1/coin.proto#L28-L38) #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct DecCoin { From 8ebbaf30c5cb897c68c2e7fe08a3485a8851fff9 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 28 Aug 2023 14:32:17 +0200 Subject: [PATCH 18/20] Update cosmwasm_1_4 feature description --- packages/std/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index c24de72d95..b617ef8392 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -44,7 +44,8 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] cosmwasm_1_3 = ["cosmwasm_1_2"] # Together with the `iterator` feature this enables additional imports for more # efficient iteration over DB keys or values. -# It also makes `DistributionQuery::DelegationRewards` available for the contract to call +# It also makes `DistributionQuery::{DelegationRewards, DelegationTotalRewards, DelegatorValidators}` +# available for the contract to call. # It requires the host blockchain to run CosmWasm `1.4.0` or higher. cosmwasm_1_4 = ["cosmwasm_1_3"] From 26d4956da3ec7fe811047966d40a590cec3b305d Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 30 Aug 2023 09:42:04 +0200 Subject: [PATCH 19/20] Fix missing new line --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 411942acf5..a9e08224c1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,4 +5,4 @@ "staking", "cosmwasm_1_4" ] -} \ No newline at end of file +} From ea4a20bbf01de0cefdec642d902946db90e3c0b0 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 30 Aug 2023 09:47:25 +0200 Subject: [PATCH 20/20] Add changelog entry --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd9de9720..0f79ddbe7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add + `DistributionQuery::{DelegationRewards, DelegationTotalRewards, DelegatorValidators}`. + This requires the `cosmwasm_1_4` feature to be enabled. ([#1788]) + +[#1788]: https://github.com/CosmWasm/cosmwasm/pull/1788 + ## [1.4.0-beta.1] - 2023-08-29 ### Added