Skip to content

Commit

Permalink
add admin auth to cw-admin-factory
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Mar 18, 2024
1 parent ef21c63 commit 9093de4
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 19 deletions.
4 changes: 3 additions & 1 deletion ci/bootstrap-env/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ fn main() -> Result<()> {
orc.instantiate(
"cw_admin_factory",
"admin_factory_init",
&cw_admin_factory::msg::InstantiateMsg {},
&cw_admin_factory::msg::InstantiateMsg {
admin: None,
},
&key,
None,
vec![],
Expand Down
56 changes: 49 additions & 7 deletions contracts/external/cw-admin-factory/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, SubMsg, WasmMsg,
to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, SubMsg,
WasmMsg,
};

use cw2::set_contract_version;
use cw_utils::parse_reply_instantiate_data;

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use crate::msg::{AdminResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use crate::state::ADMIN;

pub(crate) const CONTRACT_NAME: &str = "crates.io:cw-admin-factory";
pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
Expand All @@ -19,17 +21,21 @@ pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
_msg: InstantiateMsg,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

let admin = msg.admin.map(|a| deps.api.addr_validate(&a)).transpose()?;
ADMIN.save(deps.storage, &admin)?;

Ok(Response::new()
.add_attribute("method", "instantiate")
.add_attribute("creator", info.sender))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
_deps: DepsMut,
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
Expand All @@ -39,17 +45,26 @@ pub fn execute(
instantiate_msg: msg,
code_id,
label,
} => instantiate_contract(env, info, msg, code_id, label),
} => instantiate_contract(deps, env, info, msg, code_id, label),
ExecuteMsg::UpdateAdmin { admin } => execute_update_admin(deps, info, admin),
}
}

pub fn instantiate_contract(
deps: DepsMut,
env: Env,
info: MessageInfo,
instantiate_msg: Binary,
code_id: u64,
label: String,
) -> Result<Response, ContractError> {
// If admin set, require the sender to be the admin.
if let Some(admin) = ADMIN.load(deps.storage)? {
if admin != info.sender {
return Err(ContractError::Unauthorized {});
}
}

// Instantiate the specified contract with factory as the admin.
let instantiate = WasmMsg::Instantiate {
admin: Some(env.contract.address.to_string()),
Expand All @@ -65,9 +80,36 @@ pub fn instantiate_contract(
.add_submessage(msg))
}

pub fn execute_update_admin(
deps: DepsMut,
info: MessageInfo,
admin: Option<String>,
) -> Result<Response, ContractError> {
// Only allow the current admin to update the admin. If no admin, no admin
// can ever be set.
let current_admin = ADMIN.load(deps.storage)?;
if current_admin.map_or(false, |a| a != info.sender) {
return Err(ContractError::Unauthorized {});
}

let new_admin = admin.map(|s| deps.api.addr_validate(&s)).transpose()?;
ADMIN.save(deps.storage, &new_admin)?;

Ok(Response::default()
.add_attribute("action", "update_admin")
.add_attribute(
"admin",
new_admin.map_or("_none".to_string(), |a| a.to_string()),
))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {}
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::Admin {} => Ok(to_json_binary(&AdminResponse {
admin: ADMIN.load(deps.storage)?,
})?),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down
2 changes: 1 addition & 1 deletion contracts/external/cw-admin-factory/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use cosmwasm_std::StdError;
use cw_utils::ParseReplyError;
use thiserror::Error;

#[derive(Error, Debug)]
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
Expand Down
1 change: 1 addition & 0 deletions contracts/external/cw-admin-factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod contract;
mod error;
pub mod msg;
pub mod state;

#[cfg(test)]
mod tests;
Expand Down
20 changes: 17 additions & 3 deletions contracts/external/cw-admin-factory/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::Binary;
use cosmwasm_std::{Addr, Binary};

#[cw_serde]
pub struct InstantiateMsg {}
pub struct InstantiateMsg {
/// The account allowed to execute this contract.
pub admin: Option<String>,
}

#[cw_serde]
pub enum ExecuteMsg {
Expand All @@ -13,11 +16,22 @@ pub enum ExecuteMsg {
code_id: u64,
label: String,
},
/// Update the admin that is allowed to execute this contract. If there is
/// no admin, this cannot be called and there will never be an admin.
UpdateAdmin { admin: Option<String> },
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {}
pub enum QueryMsg {
#[returns(AdminResponse)]
Admin {},
}

#[cw_serde]
pub struct MigrateMsg {}

#[cw_serde]
pub struct AdminResponse {
pub admin: Option<Addr>,
}
5 changes: 5 additions & 0 deletions contracts/external/cw-admin-factory/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use cosmwasm_std::Addr;
use cw_storage_plus::Item;

/// The account allowed to execute the contract. If None, anyone is allowed.
pub const ADMIN: Item<Option<Addr>> = Item::new("admin");
Loading

0 comments on commit 9093de4

Please sign in to comment.