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