Skip to content

Commit

Permalink
implemented execute_add_strategy(), execute_remove_strategy()
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Zavgorodnii committed Jan 23, 2024
1 parent aba293c commit 9ab32be
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 33 deletions.
87 changes: 55 additions & 32 deletions contracts/dao/neutron-chain-manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use neutron_sdk::bindings::msg::NeutronMsg;

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, Strategy};
use crate::state::STRATEGIES;
use crate::state::{STRATEGIES_ALLOW_ALL, STRATEGIES_ALLOW_ONLY};

pub(crate) const CONTRACT_NAME: &str = "crates.io:neutron-chain-manager";
pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
Expand Down Expand Up @@ -46,58 +46,69 @@ pub fn execute_add_strategy(
deps: DepsMut,
_env: Env,
info: MessageInfo,
_strategy: Strategy,
strategy: Strategy,
) -> Result<Response, ContractError> {
if !is_authorised(deps.as_ref(), info.sender)? {
if !STRATEGIES_ALLOW_ALL.has(deps.storage, info.sender) {
return Err(ContractError::Unauthorized {});
}

Ok(Response::new().add_attribute("action", "execute_add_strategy"))
// An address cannot have both an ALLOW_ALL strategy and an ALLOW_ONLY
// strategy associated with it.
if strategy.permissions.is_empty() {
STRATEGIES_ALLOW_ALL.save(deps.storage, strategy.address.clone(), &strategy)?;
// If an address was *promoted* to an ALLOW_ALL permission strategy,
// we remove its ALLOW_ONLY entry.
STRATEGIES_ALLOW_ONLY.remove(deps.storage, strategy.address.clone());
} else {
STRATEGIES_ALLOW_ONLY.save(deps.storage, strategy.address.clone(), &strategy)?;

// If an address was *demoted* to an ALLOW_ONLY permission strategy, we
// remove its ALLOW_ALL entry. If this operation leaves us without a
// single ALLOW_ALL strategy, we abort the operation.
STRATEGIES_ALLOW_ALL.remove(deps.storage, strategy.address.clone());
if STRATEGIES_ALLOW_ALL.is_empty(deps.storage) {
return Err(ContractError::InvalidDemotion {});
}
}

Ok(Response::new()
.add_attribute("action", "execute_add_strategy")
.add_attribute("address", strategy.address)
.add_attribute("permissions_count", strategy.permissions.len().to_string()))
}

pub fn execute_remove_strategy(
deps: DepsMut,
_env: Env,
info: MessageInfo,
_address: Addr,
address: Addr,
) -> Result<Response, ContractError> {
if !is_authorised(deps.as_ref(), info.sender)? {
if !STRATEGIES_ALLOW_ALL.has(deps.storage, info.sender) {
return Err(ContractError::Unauthorized {});
}

Ok(Response::new().add_attribute("action", "execute_remove_strategy"))
STRATEGIES_ALLOW_ONLY.remove(deps.storage, address.clone());
// If this operation leaves us without a single ALLOW_ALL strategy, we
// abort the operation.
STRATEGIES_ALLOW_ALL.remove(deps.storage, address.clone());
if STRATEGIES_ALLOW_ALL.is_empty(deps.storage) {
return Err(ContractError::InvalidDemotion {});
}

Ok(Response::new()
.add_attribute("action", "execute_remove_strategy")
.add_attribute("address", address))
}

pub fn execute_execute_messages(
deps: DepsMut,
_deps: DepsMut,
_env: Env,
info: MessageInfo,
_info: MessageInfo,
_messages: Vec<CosmosMsg<NeutronMsg>>,
) -> Result<Response, ContractError> {
if !is_authorised(deps.as_ref(), info.sender)? {
return Err(ContractError::Unauthorized {});
}

Ok(Response::new().add_attribute("action", "execute_execute_messages"))
}

fn is_authorised(deps: Deps, address: Addr) -> StdResult<bool> {
let mut is_authorised: bool = false;
let strategies: Vec<Strategy> = STRATEGIES
.range_raw(deps.storage, None, None, Order::Ascending)
.map(|item| item.map(|(_key, value)| value))
.collect::<StdResult<Vec<Strategy>>>()?;

for strategy in strategies {
if strategy.permissions.is_empty() && address != strategy.address {
is_authorised = true;
break;
}
}

Ok(is_authorised)
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
Expand All @@ -106,10 +117,22 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
}

pub fn query_strategies(deps: Deps) -> StdResult<Vec<Strategy>> {
STRATEGIES
let mut all_strategies: Vec<Strategy> = vec![];

let allow_all_strategies = STRATEGIES_ALLOW_ALL
.range_raw(deps.storage, None, None, Order::Ascending)
.map(|item| item.map(|(_key, value)| value))
.collect::<StdResult<Vec<Strategy>>>()
.collect::<StdResult<Vec<Strategy>>>()?;

let allow_only_strategies = STRATEGIES_ALLOW_ONLY
.range_raw(deps.storage, None, None, Order::Ascending)
.map(|item| item.map(|(_key, value)| value))
.collect::<StdResult<Vec<Strategy>>>()?;

all_strategies.extend(allow_all_strategies);
all_strategies.extend(allow_only_strategies);

Ok(all_strategies)
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down
3 changes: 3 additions & 0 deletions contracts/dao/neutron-chain-manager/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ pub enum ContractError {

#[error("Unauthorized")]
Unauthorized {},

#[error("InvalidDemotion")]
InvalidDemotion {},
}
5 changes: 4 additions & 1 deletion contracts/dao/neutron-chain-manager/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ use cosmwasm_std::Addr;
use cw_storage_plus::Map;

/// Defines a mapping from an address to a strategy associated with the address.
pub const STRATEGIES: Map<Addr, Strategy> = Map::new("chain-manager-strategies");
pub const STRATEGIES_ALLOW_ALL: Map<Addr, Strategy> =
Map::new("chain-manager-strategies-allow-all");
pub const STRATEGIES_ALLOW_ONLY: Map<Addr, Strategy> =
Map::new("chain-manager-strategies-allow-only");

0 comments on commit 9ab32be

Please sign in to comment.