Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions packages/multi-test/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,68 @@ mod test {
assert_eq!(state.beneficiary, random);
}

#[test]
fn send_update_admin_works() {
// The plan:
// create a hackatom contract
// check admin set properly
// update admin succeeds if admin
// update admin fails if not (new) admin
// check admin set properly
let owner = Addr::unchecked("owner");
let owner2 = Addr::unchecked("owner2");
let beneficiary = Addr::unchecked("beneficiary");

let mut app = App::default();

// create a hackatom contract with some funds
let contract_id = app.store_code(hackatom::contract());
let contract = app
.instantiate_contract(
contract_id,
owner.clone(),
&hackatom::InstantiateMsg {
beneficiary: beneficiary.as_str().to_owned(),
},
&[],
"Hackatom",
Some(owner.to_string()),
)
.unwrap();

// check admin set properly
let info = app.contract_data(&contract).unwrap();
assert_eq!(info.admin, Some(owner.clone()));

// transfer adminship to owner2
app.execute(
owner.clone(),
CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
contract_addr: contract.to_string(),
admin: owner2.to_string(),
}),
)
.unwrap();

// check admin set properly
let info = app.contract_data(&contract).unwrap();
assert_eq!(info.admin, Some(owner2.clone()));

// update admin fails if not owner2
app.execute(
owner.clone(),
CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
contract_addr: contract.to_string(),
admin: owner.to_string(),
}),
)
.unwrap_err();

// check admin still the same
let info = app.contract_data(&contract).unwrap();
assert_eq!(info.admin, Some(owner2));
}

mod reply_data_overwrite {
use super::*;

Expand Down
165 changes: 164 additions & 1 deletion packages/multi-test/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,34 @@ where
}
}

/// unified logic for UpdateAdmin and ClearAdmin messages
fn update_admin(
&self,
api: &dyn Api,
storage: &mut dyn Storage,
sender: Addr,
contract_addr: &str,
new_admin: Option<String>,
) -> AnyResult<AppResponse> {
let contract_addr = api.addr_validate(contract_addr)?;
let admin = new_admin.map(|a| api.addr_validate(&a)).transpose()?;

// check admin status
let mut data = self.load_contract(storage, &contract_addr)?;
if data.admin != Some(sender) {
bail!("Only admin can clear contract admin: {:?}", data.admin);
Comment thread
chipshort marked this conversation as resolved.
Outdated
}
// update admin field
data.admin = admin;
self.save_contract(storage, &contract_addr, &data)?;

// no custom event here
Ok(AppResponse {
data: None,
events: vec![],
})
}

// this returns the contract address as well, so we can properly resend the data
fn execute_wasm(
&self,
Expand Down Expand Up @@ -474,6 +502,13 @@ where
res.data = execute_response(res.data);
Ok(res)
}
WasmMsg::UpdateAdmin {
contract_addr,
admin,
} => self.update_admin(api, storage, sender, &contract_addr, Some(admin)),
WasmMsg::ClearAdmin { contract_addr } => {
self.update_admin(api, storage, sender, &contract_addr, None)
}
msg => bail!(Error::UnsupportedWasmMsg(msg)),
}
}
Expand Down Expand Up @@ -906,7 +941,8 @@ mod test {
use crate::app::Router;
use crate::bank::BankKeeper;
use crate::module::FailingModule;
use crate::test_helpers::contracts::{error, payout};
use crate::test_helpers::contracts::{caller, error, payout};
use crate::test_helpers::EmptyMsg;
use crate::transactions::StorageTransaction;

use super::*;
Expand Down Expand Up @@ -1356,4 +1392,131 @@ mod test {
assert_payout(&keeper, &mut wasm_storage, &contract2, &payout2);
assert_payout(&keeper, &mut wasm_storage, &contract3, &payout3);
}

fn assert_admin(
storage: &dyn Storage,
keeper: &WasmKeeper<Empty, Empty>,
contract_addr: &impl ToString,
admin: Option<Addr>,
) {
let api = MockApi::default();
let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
// query
let data = keeper
.query(
&api,
storage,
&querier,
&mock_env().block,
WasmQuery::ContractInfo {
contract_addr: contract_addr.to_string(),
},
)
.unwrap();
let res: ContractInfoResponse = from_slice(&data).unwrap();
assert_eq!(res.admin, admin.as_ref().map(Addr::to_string));
}

#[test]
fn update_clear_admin_works() {
let api = MockApi::default();
let mut keeper = WasmKeeper::new();
let block = mock_env().block;
let code_id = keeper.store_code(caller::contract());

let mut wasm_storage = MockStorage::new();

let admin: Addr = Addr::unchecked("admin");
let new_admin: Addr = Addr::unchecked("new_admin");
let normal_user: Addr = Addr::unchecked("normal_user");

let contract_addr = keeper
.register_contract(
&mut wasm_storage,
code_id,
Addr::unchecked("creator"),
admin.clone(),
"label".to_owned(),
1000,
)
.unwrap();

// init the contract
let info = mock_info("admin", &[]);
let init_msg = to_vec(&EmptyMsg {}).unwrap();
let res = keeper
.call_instantiate(
contract_addr.clone(),
&api,
&mut wasm_storage,
&mock_router(),
&block,
info,
init_msg,
)
.unwrap();
assert_eq!(0, res.messages.len());

assert_admin(&wasm_storage, &keeper, &contract_addr, Some(admin.clone()));

// non-admin should not be allowed to become admin on their own
keeper
.execute_wasm(
&api,
&mut wasm_storage,
&mock_router(),
&block,
normal_user.clone(),
WasmMsg::UpdateAdmin {
contract_addr: contract_addr.to_string(),
admin: normal_user.to_string(),
},
)
.unwrap_err();

// should still be admin
assert_admin(&wasm_storage, &keeper, &contract_addr, Some(admin.clone()));

// admin should be allowed to transfers adminship
let res = keeper
.execute_wasm(
&api,
&mut wasm_storage,
&mock_router(),
&block,
admin,
WasmMsg::UpdateAdmin {
contract_addr: contract_addr.to_string(),
admin: new_admin.to_string(),
},
)
.unwrap();
assert_eq!(res.events.len(), 0);

// new_admin should now be admin
assert_admin(
&wasm_storage,
&keeper,
&contract_addr,
Some(new_admin.clone()),
);

// new_admin should now be able to clear to admin
let res = keeper
.execute_wasm(
&api,
&mut wasm_storage,
&mock_router(),
&block,
new_admin,
WasmMsg::ClearAdmin {
contract_addr: contract_addr.to_string(),
},
)
.unwrap();
assert_eq!(res.events.len(), 0);

// should have no admin now
assert_admin(&wasm_storage, &keeper, &contract_addr, None);
}
}