Skip to content

Commit

Permalink
Merge pull request #469 from CosmWasm/add-ensure
Browse files Browse the repository at this point in the history
Add ensure
  • Loading branch information
ethanfrey authored Oct 5, 2021
2 parents d536358 + cbad4c9 commit 3739811
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 39 deletions.
62 changes: 25 additions & 37 deletions contracts/cw1-subkeys/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use cosmwasm_std::{
to_binary, BankMsg, Binary, Coin, CosmosMsg, Deps, DepsMut, DistributionMsg, Empty, Env,
MessageInfo, Order, Response, StakingMsg, StdResult,
};
use cw0::Expiration;
use cw0::{ensure, Expiration};
use cw1::CanExecuteResponse;
use cw1_whitelist::{
contract::{
Expand Down Expand Up @@ -105,9 +105,10 @@ where
}) => {
ALLOWANCES.update::<_, ContractError>(deps.storage, &info.sender, |allow| {
let mut allowance = allow.ok_or(ContractError::NoAllowance {})?;
if allowance.expires.is_expired(&env.block) {
return Err(ContractError::NoAllowance {});
}
ensure!(
!allowance.expires.is_expired(&env.block),
ContractError::NoAllowance {}
);

// Decrease allowance
allowance.balance = allowance.balance.sub(amount.clone())?;
Expand All @@ -134,19 +135,13 @@ pub fn check_staking_permissions(
) -> Result<(), ContractError> {
match staking_msg {
StakingMsg::Delegate { .. } => {
if !permissions.delegate {
return Err(ContractError::DelegatePerm {});
}
ensure!(permissions.delegate, ContractError::DelegatePerm {});
}
StakingMsg::Undelegate { .. } => {
if !permissions.undelegate {
return Err(ContractError::UnDelegatePerm {});
}
ensure!(permissions.undelegate, ContractError::UnDelegatePerm {});
}
StakingMsg::Redelegate { .. } => {
if !permissions.redelegate {
return Err(ContractError::ReDelegatePerm {});
}
ensure!(permissions.redelegate, ContractError::ReDelegatePerm {});
}
_ => return Err(ContractError::UnsupportedMessage {}),
}
Expand All @@ -159,14 +154,10 @@ pub fn check_distribution_permissions(
) -> Result<(), ContractError> {
match distribution_msg {
DistributionMsg::SetWithdrawAddress { .. } => {
if !permissions.withdraw {
return Err(ContractError::WithdrawAddrPerm {});
}
ensure!(permissions.withdraw, ContractError::WithdrawAddrPerm {});
}
DistributionMsg::WithdrawDelegatorReward { .. } => {
if !permissions.withdraw {
return Err(ContractError::WithdrawPerm {});
}
ensure!(permissions.withdraw, ContractError::WithdrawPerm {});
}
_ => return Err(ContractError::UnsupportedMessage {}),
}
Expand All @@ -185,14 +176,13 @@ where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
let cfg = ADMIN_LIST.load(deps.storage)?;
if !cfg.is_admin(info.sender.as_ref()) {
return Err(ContractError::Unauthorized {});
}
ensure!(cfg.is_admin(&info.sender), ContractError::Unauthorized {});

let spender_addr = deps.api.addr_validate(&spender)?;
if info.sender == spender_addr {
return Err(ContractError::CannotSetOwnAccount {});
}
ensure!(
info.sender != spender_addr,
ContractError::CannotSetOwnAccount {}
);

ALLOWANCES.update::<_, ContractError>(deps.storage, &spender_addr, |allow| {
let prev_expires = allow
Expand Down Expand Up @@ -239,14 +229,13 @@ where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
let cfg = ADMIN_LIST.load(deps.storage)?;
if !cfg.is_admin(info.sender.as_ref()) {
return Err(ContractError::Unauthorized {});
}
ensure!(cfg.is_admin(&info.sender), ContractError::Unauthorized {});

let spender_addr = deps.api.addr_validate(&spender)?;
if info.sender == spender_addr {
return Err(ContractError::CannotSetOwnAccount {});
}
ensure!(
info.sender != spender_addr,
ContractError::CannotSetOwnAccount {}
);

let allowance =
ALLOWANCES.update::<_, ContractError>(deps.storage, &spender_addr, |allow| {
Expand Down Expand Up @@ -291,14 +280,13 @@ where
T: Clone + fmt::Debug + PartialEq + JsonSchema,
{
let cfg = ADMIN_LIST.load(deps.storage)?;
if !cfg.is_admin(info.sender.as_ref()) {
return Err(ContractError::Unauthorized {});
}
ensure!(cfg.is_admin(&info.sender), ContractError::Unauthorized {});

let spender_addr = deps.api.addr_validate(&spender)?;
if info.sender == spender_addr {
return Err(ContractError::CannotSetOwnAccount {});
}
ensure!(
info.sender != spender_addr,
ContractError::CannotSetOwnAccount {}
);
PERMISSIONS.save(deps.storage, &spender_addr, &perm)?;

let res = Response::new()
Expand Down
2 changes: 1 addition & 1 deletion contracts/cw1-whitelist/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub fn execute_update_admins(

fn can_execute(deps: Deps, sender: &str) -> StdResult<bool> {
let cfg = ADMIN_LIST.load(deps.storage)?;
let can = cfg.is_admin(sender.as_ref());
let can = cfg.is_admin(&sender);
Ok(can)
}

Expand Down
3 changes: 2 additions & 1 deletion contracts/cw1-whitelist/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ pub struct AdminList {

impl AdminList {
/// returns true if the address is a registered admin
pub fn is_admin(&self, addr: &str) -> bool {
pub fn is_admin(&self, addr: impl AsRef<str>) -> bool {
let addr = addr.as_ref();
self.admins.iter().any(|a| a.as_ref() == addr)
}

Expand Down
1 change: 1 addition & 0 deletions packages/cw0/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod balance;
mod event;
mod expiration;
mod macros;
mod pagination;
mod payment;

Expand Down
94 changes: 94 additions & 0 deletions packages/cw0/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/// Quick check for a guard. If the condition (first argument) is false,
/// then return the second argument wrapped in Err(x).
///
/// ensure!(permissions.delegate, ContractError::DelegatePerm {});
/// is the same as
/// if !permissions.delegate {
/// return Err(ContractError::DelegatePerm {});
/// }
#[macro_export]
macro_rules! ensure {
($cond:expr, $e:expr) => {
if !($cond) {
return Err($e);
}
};
}

/// Opposite of ensure. If the condition (first argument) is true,
/// then return the second argument wrapped in Err(x).
///
/// fail_if!(!permissions.delegate, ContractError::DelegatePerm {});
/// is the same as
/// if !permissions.delegate {
/// return Err(ContractError::DelegatePerm {});
/// }
#[macro_export]
macro_rules! fail_if {
($cond:expr, $e:expr) => {
if ($cond) {
return Err($e);
}
};
}

/// Quick check for a guard. Like assert_eq!, but rather than panic,
/// it returns the second argument wrapped in Err(x).
///
/// ensure_eq!(info.sender, cfg.admin, ContractError::Unauthorized {});
/// is the same as
/// if info.sender != cfg.admin {
/// return Err(ContractError::Unauthorized {});
/// }
#[macro_export]
macro_rules! ensure_eq {
($a:expr, $b:expr, $e:expr) => {
if $a != $b {
return Err($e);
}
};
}

#[cfg(test)]
mod test {
use cosmwasm_std::StdError;

#[test]
fn ensure_works() {
let check = |a, b| {
ensure!(a == b, StdError::generic_err("foobar"));
Ok(())
};

let err = check(5, 6).unwrap_err();
assert!(matches!(err, StdError::GenericErr { .. }));

check(5, 5).unwrap();
}

#[test]
fn fail_if_works() {
let check = |a, b| {
fail_if!(a == b, StdError::generic_err("failure"));
Ok(())
};

let err = check(5, 5).unwrap_err();
assert!(matches!(err, StdError::GenericErr { .. }));

check(5, 6).unwrap();
}

#[test]
fn ensure_eq_works() {
let check = |a, b| {
ensure_eq!(a, b, StdError::generic_err("foobar"));
Ok(())
};

let err = check("123", "456").unwrap_err();
assert!(matches!(err, StdError::GenericErr { .. }));

check("123", "123").unwrap();
}
}

0 comments on commit 3739811

Please sign in to comment.