diff --git a/packages/std/src/query/bank.rs b/packages/std/src/query/bank.rs index 74d8b2b9d7..a1ea2670f7 100644 --- a/packages/std/src/query/bank.rs +++ b/packages/std/src/query/bank.rs @@ -44,6 +44,9 @@ pub struct SupplyResponse { pub amount: Coin, } +#[cfg(feature = "cosmwasm_1_1")] +impl_response_constructor!(SupplyResponse, amount: Coin); + #[cfg(feature = "cosmwasm_1_1")] impl QueryResponseType for SupplyResponse {} @@ -55,6 +58,8 @@ pub struct BalanceResponse { pub amount: Coin, } +impl_response_constructor!(BalanceResponse, amount: Coin); + impl QueryResponseType for BalanceResponse {} #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] @@ -64,10 +69,12 @@ pub struct AllBalanceResponse { pub amount: Vec, } +impl_response_constructor!(AllBalanceResponse, amount: Vec); + impl QueryResponseType for AllBalanceResponse {} #[cfg(feature = "cosmwasm_1_3")] -#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] #[non_exhaustive] pub struct DenomMetadataResponse { @@ -75,11 +82,14 @@ pub struct DenomMetadataResponse { pub metadata: DenomMetadata, } +#[cfg(feature = "cosmwasm_1_3")] +impl_response_constructor!(DenomMetadataResponse, metadata: DenomMetadata); + #[cfg(feature = "cosmwasm_1_3")] impl QueryResponseType for DenomMetadataResponse {} #[cfg(feature = "cosmwasm_1_3")] -#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] #[non_exhaustive] pub struct AllDenomMetadataResponse { @@ -88,5 +98,28 @@ pub struct AllDenomMetadataResponse { pub next_key: Option, } +#[cfg(feature = "cosmwasm_1_3")] +impl_response_constructor!( + AllDenomMetadataResponse, + metadata: Vec, + next_key: Option +); + #[cfg(feature = "cosmwasm_1_3")] impl QueryResponseType for AllDenomMetadataResponse {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn private_constructor_works() { + let response = AllBalanceResponse::new(vec![Coin::new(1234, "uatom")]); + assert_eq!( + response, + AllBalanceResponse { + amount: vec![Coin::new(1234, "uatom")] + } + ); + } +} diff --git a/packages/std/src/query/distribution.rs b/packages/std/src/query/distribution.rs index ffe5772322..bd60fa2654 100644 --- a/packages/std/src/query/distribution.rs +++ b/packages/std/src/query/distribution.rs @@ -1,6 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use crate::Addr; + use super::query_response::QueryResponseType; #[non_exhaustive] @@ -12,11 +14,13 @@ pub enum DistributionQuery { } // https://github.com/cosmos/cosmos-sdk/blob/4f6f6c00021f4b5ee486bbb71ae2071a8ceb47c9/x/distribution/types/query.pb.go#L832-L835 -#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] #[non_exhaustive] pub struct DelegatorWithdrawAddressResponse { - pub withdraw_address: String, + pub withdraw_address: Addr, } +impl_response_constructor!(DelegatorWithdrawAddressResponse, withdraw_address: Addr); + impl QueryResponseType for DelegatorWithdrawAddressResponse {} diff --git a/packages/std/src/query/ibc.rs b/packages/std/src/query/ibc.rs index 0164de3301..4cff9e43b4 100644 --- a/packages/std/src/query/ibc.rs +++ b/packages/std/src/query/ibc.rs @@ -37,12 +37,18 @@ pub struct PortIdResponse { pub port_id: String, } +impl_response_constructor!(PortIdResponse, port_id: String); + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ListChannelsResponse { pub channels: Vec, } +impl_response_constructor!(ListChannelsResponse, channels: Vec); + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ChannelResponse { pub channel: Option, } + +impl_response_constructor!(ChannelResponse, channel: Option); diff --git a/packages/std/src/query/mod.rs b/packages/std/src/query/mod.rs index 5401f9145d..f1694805e6 100644 --- a/packages/std/src/query/mod.rs +++ b/packages/std/src/query/mod.rs @@ -5,6 +5,25 @@ use serde::{Deserialize, Serialize}; use crate::Binary; use crate::Empty; +/// Implements a hidden constructor for query responses. +macro_rules! impl_response_constructor { + ( $response:ty, $( $field: ident : $t: ty),* ) => { + impl $response { + /// Constructor for testing frameworks such as cw-multi-test. + /// This is required because query response types should be #[non_exhaustive]. + /// As a contract developer you should not need this constructor since + /// query responses are constructed for you via deserialization. + /// + /// Warning: This can change in breaking ways in minor versions. + #[doc(hidden)] + #[allow(dead_code)] + pub fn new($( $field: $t),*) -> Self { + Self { $( $field ),* } + } + } + }; +} + mod bank; mod distribution; mod ibc; diff --git a/packages/std/src/query/query_response.rs b/packages/std/src/query/query_response.rs index dca2e766c9..4aa4559e4b 100644 --- a/packages/std/src/query/query_response.rs +++ b/packages/std/src/query/query_response.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use serde::de::DeserializeOwned; /// A marker trait for query response types. @@ -13,4 +15,4 @@ use serde::de::DeserializeOwned; /// - multi-test/cw-sdk: create a default instance and mutate the fields /// /// This trait is crate-internal and can change any time. -pub(crate) trait QueryResponseType: Default + DeserializeOwned {} +pub(crate) trait QueryResponseType: DeserializeOwned + Debug + PartialEq + Clone {} diff --git a/packages/std/src/query/staking.rs b/packages/std/src/query/staking.rs index fa513ac52a..6f7b55513f 100644 --- a/packages/std/src/query/staking.rs +++ b/packages/std/src/query/staking.rs @@ -5,6 +5,8 @@ use serde::{Deserialize, Serialize}; use crate::{Addr, Coin, Decimal}; +use super::query_response::QueryResponseType; + #[non_exhaustive] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -40,6 +42,10 @@ pub struct BondedDenomResponse { pub denom: String, } +impl QueryResponseType for BondedDenomResponse {} + +impl_response_constructor!(BondedDenomResponse, denom: String); + /// DelegationsResponse is data format returned from StakingRequest::AllDelegations query #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -47,6 +53,10 @@ pub struct AllDelegationsResponse { pub delegations: Vec, } +impl QueryResponseType for AllDelegationsResponse {} + +impl_response_constructor!(AllDelegationsResponse, delegations: Vec); + /// Delegation is basic (cheap to query) data about a delegation. /// /// Instances are created in the querier. @@ -76,6 +86,10 @@ pub struct DelegationResponse { pub delegation: Option, } +impl QueryResponseType for DelegationResponse {} + +impl_response_constructor!(DelegationResponse, delegation: Option); + /// FullDelegation is all the info on the delegation, some (like accumulated_reward and can_redelegate) /// is expensive to query. /// @@ -101,12 +115,20 @@ pub struct AllValidatorsResponse { pub validators: Vec, } +impl QueryResponseType for AllValidatorsResponse {} + +impl_response_constructor!(AllValidatorsResponse, validators: Vec); + /// The data format returned from StakingRequest::Validator query #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ValidatorResponse { pub validator: Option, } +impl QueryResponseType for ValidatorResponse {} + +impl_response_constructor!(ValidatorResponse, validator: Option); + /// Instances are created in the querier. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Validator { diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 039251a4d7..e8f72ad737 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -85,6 +85,14 @@ pub struct CodeInfoResponse { pub checksum: HexBinary, } +#[cfg(feature = "cosmwasm_1_2")] +impl_response_constructor!( + CodeInfoResponse, + code_id: u64, + creator: String, + checksum: HexBinary +); + #[cfg(feature = "cosmwasm_1_2")] impl QueryResponseType for CodeInfoResponse {} diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 109342884e..a367e0e8b4 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -972,11 +972,11 @@ impl DistributionQuerier { let contract_result: ContractResult = match request { DistributionQuery::DelegatorWithdrawAddress { delegator_address } => { let res = DelegatorWithdrawAddressResponse { - withdraw_address: self - .withdraw_addresses - .get(delegator_address) - .unwrap_or(delegator_address) - .clone(), + withdraw_address: Addr::unchecked( + self.withdraw_addresses + .get(delegator_address) + .unwrap_or(delegator_address), + ), }; to_binary(&res).into() } diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index f33f3799a5..f7aca97ba4 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -282,7 +282,7 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { pub fn query_delegator_withdraw_address( &self, delegator: impl Into, - ) -> StdResult { + ) -> StdResult { let request = DistributionQuery::DelegatorWithdrawAddress { delegator_address: delegator.into(), }