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
//! Admin functionality where a new admin can be set by sending a single message by the current admin.
//! Use this when the admin can be another contract.

use crate::{
    cosmwasm_std::{self, StdResult, Response, Addr},
    schemars,
    derive_contract::*
};

use super::STORE;

#[contract]
pub trait SimpleAdmin {
    #[execute]
    fn change_admin(address: String) -> StdResult<Response> {
        super::assert(deps.as_ref(), &info)?;
        STORE.canonize_and_save(deps, address.as_str())?;

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

    #[query]
    fn admin() -> StdResult<Option<Addr>> {
        STORE.load_humanize(deps)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        admin,
        cosmwasm_std::{
            StdError, from_binary,
            testing::{mock_dependencies, mock_env, mock_info},
        }
    };

    #[test]
    fn test_admin() {
        let mut deps = mock_dependencies();

        let admin = "admin";
        admin::init(deps.as_mut(), Some(admin), &mock_info("sender", &[])).unwrap();

        let msg = ExecuteMsg::ChangeAdmin { 
            address: "will fail".into()
        };

        let result = execute(
            deps.as_mut(),
            mock_env(),
            mock_info("unauthorized", &[]),
            msg,
            DefaultImpl
        ).unwrap_err();
        
        match result {
            StdError::GenericErr { .. } => { },
            _ => panic!("Expected \"StdError::GenericErr\"")
        };

        let new_admin = "new_admin";

        let msg = ExecuteMsg::ChangeAdmin { 
            address: new_admin.into()
        };

        execute(
            deps.as_mut(),
            mock_env(),
            mock_info(admin, &[]),
            msg,
            DefaultImpl
        ).unwrap();

        let result = query(deps.as_ref(), mock_env(), QueryMsg::Admin {}, DefaultImpl).unwrap();
        let stored_admin: Option<Addr> = from_binary(&result).unwrap();
        assert_eq!(stored_admin.unwrap(), new_admin);
    }

    #[test]
    fn test_init_default_admin() {
        let ref mut deps = mock_dependencies();

        let result = query(deps.as_ref(), mock_env(), QueryMsg::Admin {}, DefaultImpl).unwrap();
        let admin: Option<Addr> = from_binary(&result).unwrap();
        assert!(admin.is_none());

        let admin = "admin";
        admin::init(deps.as_mut(), None, &mock_info(admin, &[])).unwrap();

        let result = query(deps.as_ref(), mock_env(), QueryMsg::Admin {}, DefaultImpl).unwrap();
        let stored_admin: Option<Addr> = from_binary(&result).unwrap();
        assert_eq!(stored_admin.unwrap(), admin);
    }
}