1use cosmwasm_std::{Addr, Event, MessageInfo, Response, StdError, StdResult, Storage};
2use cw_storage_plus::Item;
3
4const OWNER: Item<Addr> = Item::new("_owner");
5
6#[derive(thiserror::Error, Debug, PartialEq)]
7pub enum OwnershipError {
8 #[error("{0}")]
9 Std(#[from] StdError),
10
11 #[error("Unauthorized")]
12 Unauthorized,
13}
14
15pub fn set_owner(storage: &mut dyn Storage, owner: &Addr) -> Result<(), OwnershipError> {
17 OWNER.save(storage, owner)?;
18 Ok(())
19}
20
21pub fn get_owner(storage: &dyn Storage) -> StdResult<Addr> {
24 OWNER.may_load(storage)?.ok_or(StdError::not_found("owner"))
25}
26
27pub fn transfer_ownership(
41 storage: &mut dyn Storage,
42 info: MessageInfo,
43 new_owner: Addr,
44) -> Result<Response, OwnershipError> {
45 assert_owner(storage, &info)?;
46
47 let old_owner = info.sender;
48 OWNER.save(storage, &new_owner)?;
49 Ok(Response::new().add_event(
50 Event::new("TransferredOwnership")
51 .add_attribute("old_owner", old_owner.as_str())
52 .add_attribute("new_owner", new_owner.as_str()),
53 ))
54}
55
56pub fn assert_owner(storage: &dyn Storage, info: &MessageInfo) -> Result<(), OwnershipError> {
58 let owner = OWNER.load(storage)?;
59 if info.sender != owner {
60 return Err(OwnershipError::Unauthorized);
61 }
62 Ok(())
63}
64
65#[cfg(test)]
66mod tests {
67 use crate::ownership::*;
68 use cosmwasm_std::testing::{message_info, mock_dependencies};
69 use cosmwasm_std::Addr;
70
71 #[test]
72 fn test_assert_owner() {
73 let mut deps = mock_dependencies();
74
75 let owner_addr = deps.api.addr_make("owner");
76 OWNER.save(deps.as_mut().storage, &owner_addr).unwrap();
77
78 let owner_info = message_info(&owner_addr, &[]);
79
80 let result = assert_owner(&deps.storage, &owner_info);
81 assert!(result.is_ok());
82
83 let info = message_info(&Addr::unchecked("not_owner"), &[]);
84 let result = assert_owner(&deps.storage, &info);
85 assert_eq!(result, Err(OwnershipError::Unauthorized));
86 }
87
88 #[test]
89 fn test_assert_owner_fail() {
90 let mut deps = mock_dependencies();
91
92 let owner_addr = deps.api.addr_make("owner");
93 OWNER.save(deps.as_mut().storage, &owner_addr).unwrap();
94
95 let owner_info = message_info(&owner_addr, &[]);
96
97 let result = assert_owner(&deps.storage, &owner_info);
98 assert!(result.is_ok());
99
100 let info = message_info(&Addr::unchecked("not_owner"), &[]);
101 let result = assert_owner(&deps.storage, &info);
102 assert_eq!(result, Err(OwnershipError::Unauthorized));
103 }
104
105 #[test]
106 fn test_transfer_ownership() {
107 let mut deps = mock_dependencies();
108
109 let owner_addr = deps.api.addr_make("owner");
110 OWNER.save(deps.as_mut().storage, &owner_addr).unwrap();
111
112 let new_owner_addr = deps.api.addr_make("new_owner");
113
114 let owner_info = message_info(&owner_addr, &[]);
115 transfer_ownership(
116 deps.as_mut().storage,
117 owner_info.clone(),
118 new_owner_addr.clone(),
119 )
120 .unwrap();
121
122 let saved_owner = OWNER.load(&deps.storage).unwrap();
123 assert_eq!(saved_owner, new_owner_addr);
124
125 let res = transfer_ownership(
126 deps.as_mut().storage,
127 owner_info.clone(),
128 owner_addr.clone(),
129 );
130 assert_eq!(res, Err(OwnershipError::Unauthorized));
131
132 let saved_owner = OWNER.load(&deps.storage).unwrap();
133 assert_eq!(saved_owner, new_owner_addr);
134
135 let new_new_owner_addr = deps.api.addr_make("new_new_owner");
136 let new_owner_info = message_info(&new_owner_addr, &[]);
137 transfer_ownership(
138 deps.as_mut().storage,
139 new_owner_info.clone(),
140 new_new_owner_addr.clone(),
141 )
142 .unwrap();
143
144 let saved_owner = OWNER.load(&deps.storage).unwrap();
145 assert_eq!(saved_owner, new_new_owner_addr);
146 }
147}