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