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}