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}