variable-manager 1.0.4

variable manager smart contract
Documentation
use cosmwasm_std::{attr, Addr, Attribute, Deps, DepsMut, Response};
use rhaki_cw_plus::traits::IntoAddr;
use variable_manager_pkg::{
    definitions::Config,
    msgs::{RegisterVariableMsg, RemoveVariableMsg, UpdateOwnerMsg},
};

use crate::{
    response::{ContractError, ContractResponse, ContractResult},
    state::{CONFIG, VARIABLES},
};

pub fn run_register_variable(deps: DepsMut, msg: RegisterVariableMsg) -> ContractResponse {
    if let Ok(variable) = VARIABLES.load(deps.storage, msg.key.clone()) {
        return Err(ContractError::KeyAlredyRegistered {
            key: msg.key,
            value: variable,
        });
    }

    let validate = msg.value.clone().validate(deps.as_ref())?;

    VARIABLES.save(deps.storage, msg.key.clone(), &validate)?;

    Ok(Response::new()
        .add_attribute("action", "register_variable")
        .add_attribute("key", msg.key)
        .add_attribute("value", format!("{}", msg.value)))
}

pub fn run_register_variables(
    mut deps: DepsMut,
    msgs: Vec<RegisterVariableMsg>,
) -> ContractResponse {
    let mut attrs = vec![attr("action", "register_variable")];
    for msg in msgs {
        run_register_variable(deps.branch(), msg.clone())?;
        attrs.push(attr("key", msg.key));
        attrs.push(attr("value", format!("{}", msg.value)));
    }

    Ok(Response::new().add_attributes(attrs))
}

pub fn run_update_variable(deps: DepsMut, msg: RegisterVariableMsg) -> ContractResponse {
    let validated = msg.value.clone().validate(deps.as_ref())?;

    VARIABLES.update(deps.storage, msg.key.clone(), |val| -> ContractResult<_> {
        val.ok_or(ContractError::KeyNotFound {
            key: msg.key.clone(),
        })?;
        Ok(validated)
    })?;

    Ok(Response::new()
        .add_attribute("action", "update_variable")
        .add_attribute("key", msg.key)
        .add_attribute("value", format!("{}", msg.value)))
}

pub fn run_update_variables(mut deps: DepsMut, msgs: Vec<RegisterVariableMsg>) -> ContractResponse {
    let mut attrs = vec![attr("action", "update_variable")];
    for msg in msgs {
        run_update_variable(deps.branch(), msg.clone())?;
        attrs.push(attr("key", msg.key));
        attrs.push(attr("value", format!("{}", msg.value)));
    }

    Ok(Response::new().add_attributes(attrs))
}

pub fn run_remove_variable(deps: DepsMut, msg: RemoveVariableMsg) -> ContractResponse {
    let variable =
        VARIABLES
            .load(deps.storage, msg.key.clone())
            .map_err(|_| ContractError::KeyNotFound {
                key: msg.key.to_string(),
            })?;

    VARIABLES.remove(deps.storage, msg.key.clone());

    Ok(Response::new()
        .add_attribute("action", "remove_variable")
        .add_attribute("key", msg.key)
        .add_attribute("value", format!("{}", variable)))
}

pub fn run_update_owner_msg(deps: DepsMut, msg: UpdateOwnerMsg) -> ContractResponse {
    let mut config = CONFIG.load(deps.storage)?;

    let attrs = match (msg.add, msg.remove) {
        (None, None) => Err(ContractError::InvalidUpdateOwnerMsg),
        (None, Some(to_remove)) => remove_owners(deps.as_ref(), &mut config, to_remove),
        (Some(to_add), None) => add_owners(deps.as_ref(), &mut config, to_add),
        (Some(to_add), Some(to_remove)) => {
            let mut combined = vec![];
            combined.extend_from_slice(&add_owners(deps.as_ref(), &mut config, to_add)?);
            combined.extend_from_slice(&remove_owners(deps.as_ref(), &mut config, to_remove)?);
            Ok(combined)
        }
    }?;

    config.validate()?;

    CONFIG.save(deps.storage, &config)?;
    Ok(Response::new()
        .add_attribute("action", "update_owners")
        .add_attributes(attrs))
}

fn add_owners(
    deps: Deps,
    config: &mut Config,
    addresses: Vec<String>,
) -> ContractResult<Vec<Attribute>> {
    let mut attrs: Vec<Attribute> = vec![];

    for address in addresses {
        let address = address.into_addr(deps.api)?;

        if config.owners.contains(&address) {
            return Err(ContractError::IsAlredyOwner { addr: address });
        }

        attrs.push(attr("owner_added", address.clone()));

        config.owners.push(address)
    }

    Ok(attrs)
}

fn remove_owners(
    deps: Deps,
    config: &mut Config,
    addresses: Vec<String>,
) -> ContractResult<Vec<Attribute>> {
    let mut attrs: Vec<Attribute> = vec![];

    let addresses = addresses
        .into_iter()
        .map(|address| -> ContractResult<Addr> {
            let address = address.into_addr(deps.api)?;

            if !config.owners.contains(&address) {
                return Err(ContractError::IsNotOwner { addr: address });
            }

            attrs.push(attr("owner_removed", address.clone()));

            Ok(address)
        })
        .collect::<ContractResult<Vec<Addr>>>()?;

    config.owners.retain_mut(|addr| !addresses.contains(addr));

    Ok(attrs)
}