1use cosmwasm_schema::cw_serde;
2use sg_std::SubMsg;
3use thiserror::Error;
4
5use cosmwasm_std::{Addr, CustomQuery, Deps, StdError, StdResult, Storage};
6use cw_storage_plus::Item;
7
8#[cw_serde]
9pub struct HooksResponse {
10 pub hooks: Vec<String>,
11}
12
13#[derive(Error, Debug, PartialEq)]
14pub enum HookError {
15 #[error("{0}")]
16 Std(#[from] StdError),
17
18 #[error("Given address already registered as a hook")]
19 HookAlreadyRegistered {},
20
21 #[error("Given address not registered as a hook")]
22 HookNotRegistered {},
23
24 #[error("Too many hooks")]
25 HookTooMany {},
26}
27
28pub struct Hooks<'a>(Item<'a, Vec<Addr>>);
30
31impl<'a> Hooks<'a> {
32 pub const fn new(storage_key: &'a str) -> Self {
33 Hooks(Item::new(storage_key))
34 }
35
36 pub fn add_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> {
37 let mut hooks = self.0.may_load(storage)?.unwrap_or_default();
38 if hooks.len() >= 5 {
39 return Err(HookError::HookTooMany {});
40 }
41 if !hooks.iter().any(|h| h == addr) {
42 hooks.push(addr);
43 } else {
44 return Err(HookError::HookAlreadyRegistered {});
45 }
46 Ok(self.0.save(storage, &hooks)?)
47 }
48
49 pub fn remove_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> {
50 let mut hooks = self.0.load(storage)?;
51 if let Some(p) = hooks.iter().position(|x| x == addr) {
52 hooks.remove(p);
53 } else {
54 return Err(HookError::HookNotRegistered {});
55 }
56 Ok(self.0.save(storage, &hooks)?)
57 }
58
59 pub fn prepare_hooks<F: Fn(Addr) -> StdResult<SubMsg>>(
60 &self,
61 storage: &dyn Storage,
62 prep: F,
63 ) -> StdResult<Vec<SubMsg>> {
64 self.0
65 .may_load(storage)?
66 .unwrap_or_default()
67 .into_iter()
68 .map(prep)
69 .collect()
70 }
71
72 pub fn query_hooks<Q: CustomQuery>(&self, deps: Deps<Q>) -> StdResult<HooksResponse> {
73 let hooks = self.0.may_load(deps.storage)?.unwrap_or_default();
74 let hooks = hooks.into_iter().map(String::from).collect();
75 Ok(HooksResponse { hooks })
76 }
77}