sg_controllers/
hooks.rs

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
28// store all hook addresses in one item. We cannot have many of them before the contract becomes unusable anyway.
29pub 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}