cw1_subkeys/
msg.rs

1use schemars::JsonSchema;
2
3use std::fmt;
4
5use cosmwasm_schema::{cw_serde, QueryResponses};
6use cosmwasm_std::{Coin, CosmosMsg, Empty};
7use cw_utils::{Expiration, NativeBalance};
8
9use crate::state::Permissions;
10
11#[cw_serde]
12pub enum ExecuteMsg<T = Empty>
13where
14    T: Clone + fmt::Debug + PartialEq + JsonSchema,
15{
16    /// Execute requests the contract to re-dispatch all these messages with the
17    /// contract's address as sender. Every implementation has it's own logic to
18    /// determine in
19    Execute { msgs: Vec<CosmosMsg<T>> },
20    /// Freeze will make a mutable contract immutable, must be called by an admin
21    Freeze {},
22    /// UpdateAdmins will change the admin set of the contract, must be called by an existing admin,
23    /// and only works if the contract is mutable
24    UpdateAdmins { admins: Vec<String> },
25
26    /// Add an allowance to a given subkey (subkey must not be admin)
27    IncreaseAllowance {
28        spender: String,
29        amount: Coin,
30        expires: Option<Expiration>,
31    },
32    /// Decreases an allowance for a given subkey (subkey must not be admin)
33    DecreaseAllowance {
34        spender: String,
35        amount: Coin,
36        expires: Option<Expiration>,
37    },
38
39    // Setups up permissions for a given subkey.
40    SetPermissions {
41        spender: String,
42        permissions: Permissions,
43    },
44}
45
46#[cw_serde]
47#[derive(QueryResponses)]
48pub enum QueryMsg<T = Empty>
49where
50    T: Clone + fmt::Debug + PartialEq + JsonSchema,
51{
52    /// Shows all admins and whether or not it is mutable
53    #[returns(cw1_whitelist::msg::AdminListResponse)]
54    AdminList {},
55    /// Get the current allowance for the given subkey (how much it can spend)
56    #[returns(crate::state::Allowance)]
57    Allowance { spender: String },
58    /// Get the current permissions for the given subkey (how much it can spend)
59    #[returns(PermissionsInfo)]
60    Permissions { spender: String },
61    /// Checks permissions of the caller on this proxy.
62    /// If CanExecute returns true then a call to `Execute` with the same message,
63    /// before any further state changes, should also succeed.
64    #[returns(cw1::CanExecuteResponse)]
65    CanExecute { sender: String, msg: CosmosMsg<T> },
66    /// Gets all Allowances for this contract
67    #[returns(AllAllowancesResponse)]
68    AllAllowances {
69        start_after: Option<String>,
70        limit: Option<u32>,
71    },
72    /// Gets all Permissions for this contract
73    #[returns(AllPermissionsResponse)]
74    AllPermissions {
75        start_after: Option<String>,
76        limit: Option<u32>,
77    },
78}
79
80#[cw_serde]
81pub struct AllAllowancesResponse {
82    pub allowances: Vec<AllowanceInfo>,
83}
84
85#[cfg(test)]
86impl AllAllowancesResponse {
87    pub fn canonical(mut self) -> Self {
88        self.allowances = self
89            .allowances
90            .into_iter()
91            .map(AllowanceInfo::canonical)
92            .collect();
93        self.allowances.sort_by(AllowanceInfo::cmp_by_spender);
94        self
95    }
96}
97
98#[cw_serde]
99pub struct AllowanceInfo {
100    pub spender: String,
101    pub balance: NativeBalance,
102    pub expires: Expiration,
103}
104
105#[cfg(test)]
106impl AllowanceInfo {
107    /// Utility function providing some ordering to be used with `slice::sort_by`.
108    ///
109    /// Note, that this doesn't implement full ordering - items with same spender but differing on
110    /// permissions, would be considered equal, however as spender is a unique key in any valid
111    /// state this is enough for testing purposes.
112    ///
113    /// Example:
114    ///
115    /// ```
116    /// # use cw_utils::{Expiration, NativeBalance};
117    /// # use cw1_subkeys::msg::AllowanceInfo;
118    /// # use cosmwasm_schema::{cw_serde, QueryResponses};use cosmwasm_std::coin;
119    ///
120    /// let mut allows = vec![AllowanceInfo {
121    ///   spender: "spender2".to_owned(),
122    ///   balance: NativeBalance(vec![coin(1, "token1")]),
123    ///   expires: Expiration::Never {},
124    /// }, AllowanceInfo {
125    ///   spender: "spender1".to_owned(),
126    ///   balance: NativeBalance(vec![coin(2, "token2")]),
127    ///   expires: Expiration::Never {},
128    /// }];
129    ///
130    /// allows.sort_by(AllowanceInfo::cmp_by_spender);
131    ///
132    /// assert_eq!(
133    ///   allows.into_iter().map(|allow| allow.spender).collect::<Vec<_>>(),
134    ///   vec!["spender1".to_owned(), "spender2".to_owned()]
135    /// );
136    /// ```
137    pub fn cmp_by_spender(left: &Self, right: &Self) -> std::cmp::Ordering {
138        left.spender.cmp(&right.spender)
139    }
140
141    pub fn canonical(mut self) -> Self {
142        self.balance.normalize();
143        self
144    }
145}
146
147#[cw_serde]
148pub struct PermissionsInfo {
149    pub spender: String,
150    pub permissions: Permissions,
151}
152
153#[cfg(any(test, feature = "test-utils"))]
154impl PermissionsInfo {
155    /// Utility function providing some ordering to be used with `slice::sort_by`.
156    ///
157    /// Note, that this doesn't implement full ordering - items with same spender but differing on
158    /// permissions, would be considered equal, however as spender is a unique key in any valid
159    /// state this is enough for testing purposes.
160    ///
161    /// Example:
162    ///
163    /// ```
164    /// # use cw1_subkeys::msg::PermissionsInfo;
165    /// # use cw1_subkeys::state::Permissions;
166    ///
167    /// let mut perms = vec![PermissionsInfo {
168    ///   spender: "spender2".to_owned(),
169    ///   permissions: Permissions::default(),
170    /// }, PermissionsInfo {
171    ///   spender: "spender1".to_owned(),
172    ///   permissions: Permissions::default(),
173    /// }];
174    ///
175    /// perms.sort_by(PermissionsInfo::cmp_by_spender);
176    ///
177    /// assert_eq!(
178    ///   perms.into_iter().map(|perm| perm.spender).collect::<Vec<_>>(),
179    ///   vec!["spender1".to_owned(), "spender2".to_owned()]
180    /// );
181    /// ```
182    pub fn cmp_by_spender(left: &Self, right: &Self) -> std::cmp::Ordering {
183        left.spender.cmp(&right.spender)
184    }
185}
186
187#[cw_serde]
188pub struct AllPermissionsResponse {
189    pub permissions: Vec<PermissionsInfo>,
190}