From 9ab6409239ad786c2a27bee5d86f5e3412cda7c1 Mon Sep 17 00:00:00 2001 From: mdjakovic0920 Date: Tue, 9 Jul 2024 16:49:23 +0000 Subject: [PATCH 1/5] feat: add single string ADO --- Cargo.lock | 17 +- .../andromeda-string-storage/.cargo/config | 4 + .../andromeda-string-storage/Cargo.toml | 40 +++ .../examples/schema.rs | 10 + .../andromeda-string-storage/src/contract.rs | 74 +++++ .../andromeda-string-storage/src/execute.rs | 158 +++++++++ .../andromeda-string-storage/src/lib.rs | 9 + .../andromeda-string-storage/src/mock.rs | 113 +++++++ .../andromeda-string-storage/src/query.rs | 34 ++ .../andromeda-string-storage/src/state.rs | 7 + .../src/testing/mock.rs | 71 ++++ .../src/testing/mod.rs | 2 + .../src/testing/tests.rs | 312 ++++++++++++++++++ packages/andromeda-data-storage/src/lib.rs | 1 + .../src/string_storage.rs | 142 ++++++++ 15 files changed, 993 insertions(+), 1 deletion(-) create mode 100644 contracts/data-storage/andromeda-string-storage/.cargo/config create mode 100644 contracts/data-storage/andromeda-string-storage/Cargo.toml create mode 100644 contracts/data-storage/andromeda-string-storage/examples/schema.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/contract.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/execute.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/lib.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/mock.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/query.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/state.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/testing/mock.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/testing/mod.rs create mode 100644 contracts/data-storage/andromeda-string-storage/src/testing/tests.rs create mode 100644 packages/andromeda-data-storage/src/string_storage.rs diff --git a/Cargo.lock b/Cargo.lock index b462121a7..09f7cda8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "andromeda-app-contract" -version = "1.1.1" +version = "1.1.0" dependencies = [ "andromeda-app", "andromeda-std", @@ -492,6 +492,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "andromeda-string-storage" +version = "1.0.0" +dependencies = [ + "andromeda-data-storage", + "andromeda-std", + "andromeda-testing", + "cosmwasm-schema", + "cosmwasm-std", + "cw-multi-test", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw20", +] + [[package]] name = "andromeda-testing" version = "1.0.0" diff --git a/contracts/data-storage/andromeda-string-storage/.cargo/config b/contracts/data-storage/andromeda-string-storage/.cargo/config new file mode 100644 index 000000000..336b618a1 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/.cargo/config @@ -0,0 +1,4 @@ +[alias] +wasm = "build --release --target wasm32-unknown-unknown" +unit-test = "test --lib" +schema = "run --example schema" diff --git a/contracts/data-storage/andromeda-string-storage/Cargo.toml b/contracts/data-storage/andromeda-string-storage/Cargo.toml new file mode 100644 index 000000000..a9401b228 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "andromeda-string-storage" +version = "1.0.0" +authors = ["Mitar Djakovic "] +edition = "2021" +rust-version = "1.75.0" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] +testing = ["cw-multi-test", "andromeda-testing"] + +[dependencies] +cosmwasm-std = { workspace = true } +cosmwasm-schema = { workspace = true } +cw-storage-plus = { workspace = true } +cw-utils = { workspace = true } +cw20 = { workspace = true } + + +andromeda-std = { workspace = true, features = ["rates"] } +andromeda-data-storage = { workspace = true } + + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +cw-multi-test = { workspace = true, optional = true } +andromeda-testing = { workspace = true, optional = true } diff --git a/contracts/data-storage/andromeda-string-storage/examples/schema.rs b/contracts/data-storage/andromeda-string-storage/examples/schema.rs new file mode 100644 index 000000000..0ae06361e --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/examples/schema.rs @@ -0,0 +1,10 @@ +use andromeda_data_storage::string_storage::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use cosmwasm_schema::write_api; +fn main() { + write_api! { + instantiate: InstantiateMsg, + query: QueryMsg, + execute: ExecuteMsg, + + } +} \ No newline at end of file diff --git a/contracts/data-storage/andromeda-string-storage/src/contract.rs b/contracts/data-storage/andromeda-string-storage/src/contract.rs new file mode 100644 index 000000000..11e91a4f0 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/contract.rs @@ -0,0 +1,74 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response}; + +use andromeda_data_storage::string_storage::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use andromeda_std::{ + ado_base::{InstantiateMsg as BaseInstantiateMsg, MigrateMsg}, + ado_contract::ADOContract, + common::{context::ExecuteContext, encode_binary}, + error::ContractError, +}; +use crate::{ + execute::handle_execute, + query::{get_value, get_data_owner}, + state::RESTRICTION, +}; + +// version info for migration info +const CONTRACT_NAME: &str = "crates.io:andromeda-string-storage"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + let resp = ADOContract::default().instantiate( + deps.storage, + env, + deps.api, + &deps.querier, + info, + BaseInstantiateMsg { + ado_type: CONTRACT_NAME.to_string(), + ado_version: CONTRACT_VERSION.to_string(), + kernel_address: msg.kernel_address, + owner: msg.owner, + }, + )?; + RESTRICTION.save(deps.storage, &msg.restriction)?; + Ok(resp) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + let ctx = ExecuteContext::new(deps, info, env); + match msg { + ExecuteMsg::AMPReceive(pkt) => { + ADOContract::default().execute_amp_receive(ctx, pkt, handle_execute) + }, + _ => handle_execute(ctx, msg), + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { + match msg { + QueryMsg::GetValue { } => encode_binary(&get_value(deps.storage)?), + QueryMsg::GetDataOwner { } => encode_binary(&get_data_owner(deps.storage)?), + _ => ADOContract::default().query(deps, env, msg), + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { + ADOContract::default().migrate(deps, CONTRACT_NAME, CONTRACT_VERSION) +} \ No newline at end of file diff --git a/contracts/data-storage/andromeda-string-storage/src/execute.rs b/contracts/data-storage/andromeda-string-storage/src/execute.rs new file mode 100644 index 000000000..c7afaa537 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/execute.rs @@ -0,0 +1,158 @@ +use andromeda_data_storage::string_storage::{ExecuteMsg, StringStorage, StringStorageRestriction}; +use andromeda_std::{ + ado_base::rates::{Rate, RatesMessage}, + ado_contract::ADOContract, + common::{ + actions::call_action, call_action::get_action_name, context::ExecuteContext, + rates::get_tax_amount, Funds, + }, + error::ContractError, +}; +use cosmwasm_std::{ + coin, ensure, BankMsg, Coin, CosmosMsg, Deps, MessageInfo, Response, SubMsg, Uint128, +}; +use cw_utils::nonpayable; + +use crate::{ + query::has_permission, + state::{DATA, DATA_OWNER, RESTRICTION}, +}; +const CONTRACT_NAME: &str = "crates.io:andromeda-string-storage"; + +pub fn handle_execute(mut ctx: ExecuteContext, msg: ExecuteMsg) -> Result { + let action = get_action_name(CONTRACT_NAME, msg.as_ref()); + call_action( + &mut ctx.deps, + &ctx.info, + &ctx.env, + &ctx.amp_ctx, + msg.as_ref(), + )?; + + match msg.clone() { + ExecuteMsg::UpdateRestriction { restriction } => update_restriction(ctx, restriction), + ExecuteMsg::SetValue { value } => set_value(ctx, value, action), + ExecuteMsg::DeleteValue { } => delete_value(ctx), + ExecuteMsg::Rates(rates_message) => match rates_message { + RatesMessage::SetRate { rate, .. } => match rate { + Rate::Local(local_rate) => { + // Percent rates aren't applicable in this case, so we enforce Flat rates + ensure!(local_rate.value.is_flat(), ContractError::InvalidRate {}); + ADOContract::default().execute(ctx, msg) + } + Rate::Contract(_) => ADOContract::default().execute(ctx, msg), + }, + RatesMessage::RemoveRate { .. } => ADOContract::default().execute(ctx, msg), + }, + _ => ADOContract::default().execute(ctx, msg), + } +} + +pub fn update_restriction( + ctx: ExecuteContext, + restriction: StringStorageRestriction, +) -> Result { + nonpayable(&ctx.info)?; + let sender = ctx.info.sender; + ensure!( + ADOContract::default().is_owner_or_operator(ctx.deps.storage, sender.as_ref())?, + ContractError::Unauthorized {} + ); + RESTRICTION.save(ctx.deps.storage, &restriction)?; + Ok(Response::new() + .add_attribute("method", "update_restriction") + .add_attribute("sender", sender)) +} + +pub fn set_value( + ctx: ExecuteContext, + value: StringStorage, + action: String, +) -> Result { + let sender = ctx.info.sender.clone(); + ensure!( + has_permission(ctx.deps.storage, &sender)?, + ContractError::Unauthorized {} + ); + + value.validate()?; + + let tax_response = tax_set_value(ctx.deps.as_ref(), &ctx.info, action)?; + + DATA.save(ctx.deps.storage, &value.clone())?; + DATA_OWNER.save(ctx.deps.storage, &sender)?; + + let mut response = Response::new() + .add_attribute("method", "set_value") + .add_attribute("sender", sender) + .add_attribute("value", format!("{value:?}")); + + if let Some(tax_response) = tax_response { + response = response.add_submessages(tax_response.1); + let refund = tax_response.0.try_get_coin()?; + if !refund.amount.is_zero() { + return Ok(response.add_message(CosmosMsg::Bank(BankMsg::Send { + to_address: ctx.info.sender.into_string(), + amount: vec![refund], + }))); + } + } + + Ok(response) +} + +pub fn delete_value(ctx: ExecuteContext) -> Result { + nonpayable(&ctx.info)?; + let sender = ctx.info.sender; + ensure!( + has_permission(ctx.deps.storage, &sender)?, + ContractError::Unauthorized {} + ); + DATA.remove(ctx.deps.storage); + DATA_OWNER.remove(ctx.deps.storage); + Ok(Response::new() + .add_attribute("method", "delete_value") + .add_attribute("sender", sender) + ) +} + +fn tax_set_value( + deps: Deps, + info: &MessageInfo, + action: String, +) -> Result)>, ContractError> { + let default_coin = coin(0_u128, "uandr".to_string()); + let sent_funds = info.funds.first().unwrap_or(&default_coin); + + let transfer_response = ADOContract::default().query_deducted_funds( + deps, + action, + Funds::Native(sent_funds.clone()), + )?; + + if let Some(transfer_response) = transfer_response { + let remaining_funds = transfer_response.leftover_funds.try_get_coin()?; + let tax_amount = get_tax_amount( + &transfer_response.msgs, + remaining_funds.amount, + remaining_funds.amount, + ); + + let refund = if sent_funds.amount > tax_amount { + sent_funds.amount.checked_sub(tax_amount)? + } else { + Uint128::zero() + }; + + let after_tax_payment = Coin { + denom: remaining_funds.denom, + amount: refund, + }; + Ok(Some(( + Funds::Native(after_tax_payment), + transfer_response.msgs, + ))) + } else { + Ok(None) + } +} diff --git a/contracts/data-storage/andromeda-string-storage/src/lib.rs b/contracts/data-storage/andromeda-string-storage/src/lib.rs new file mode 100644 index 000000000..36553fb8f --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/lib.rs @@ -0,0 +1,9 @@ +pub mod contract; +mod execute; +#[cfg(all(not(target_arch = "wasm32"), feature = "testing"))] +pub mod mock; +mod query; +mod state; + +#[cfg(test)] +mod testing; diff --git a/contracts/data-storage/andromeda-string-storage/src/mock.rs b/contracts/data-storage/andromeda-string-storage/src/mock.rs new file mode 100644 index 000000000..5942bbfeb --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/mock.rs @@ -0,0 +1,113 @@ +#![cfg(all(not(target_arch = "wasm32"), feature = "testing"))] +use crate::contract::{execute, instantiate, query}; +use andromeda_data_storage::string_storage::{ + ExecuteMsg, GetDataOwnerResponse, GetValueResponse, InstantiateMsg, StringStorage, StringStorageRestriction, + QueryMsg, +}; +use andromeda_std::ado_base::rates::{Rate, RatesMessage}; +use andromeda_testing::mock::MockApp; +use andromeda_testing::{ + mock_ado, + mock_contract::{ExecuteResult, MockADO, MockContract}, +}; +use cosmwasm_std::{Addr, Coin, Empty}; +use cw_multi_test::{Contract, ContractWrapper, Executor}; + +pub struct MockStringStorage(Addr); +mock_ado!(MockStringStorage, ExecuteMsg, QueryMsg); + +impl MockStringStorage { + pub fn instantiate( + code_id: u64, + sender: Addr, + app: &mut MockApp, + kernel_address: String, + owner: Option, + restriction: StringStorageRestriction, + ) -> MockStringStorage { + let msg = mock_string_storage_instantiate_msg(kernel_address, owner, restriction); + let addr = app + .instantiate_contract( + code_id, + sender.clone(), + &msg, + &[], + "String Storage Contract", + Some(sender.to_string()), + ) + .unwrap(); + MockStringStorage(Addr::unchecked(addr)) + } + + pub fn execute_set_value( + &self, + app: &mut MockApp, + sender: Addr, + key: Option, + value: StringStorage, + funds: Option, + ) -> ExecuteResult { + let msg = mock_store_value_msg(value); + if let Some(funds) = funds { + app.execute_contract(sender, self.addr().clone(), &msg, &[funds]) + } else { + app.execute_contract(sender, self.addr().clone(), &msg, &[]) + } + } + + pub fn execute_add_rate( + &self, + app: &mut MockApp, + sender: Addr, + action: String, + rate: Rate, + ) -> ExecuteResult { + self.execute(app, &mock_set_rate_msg(action, rate), sender, &[]) + } + + pub fn query_value(&self, app: &mut MockApp) -> GetValueResponse { + let msg = mock_string_storage_get_value(); + let res: GetValueResponse = self.query(app, msg); + res + } + + pub fn query_data_owner(&self, app: &mut MockApp) -> GetDataOwnerResponse { + let msg = mock_string_storage_get_data_owner(); + let res: GetDataOwnerResponse = self.query(app, msg); + res + } +} + +pub fn mock_andromeda_string_storage() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + Box::new(contract) +} + +pub fn mock_string_storage_instantiate_msg( + kernel_address: String, + owner: Option, + restriction: StringStorageRestriction, +) -> InstantiateMsg { + InstantiateMsg { + kernel_address, + owner, + restriction, + } +} + +/// Used to generate a message to store a string storage value +pub fn mock_store_value_msg(value: StringStorage) -> ExecuteMsg { + ExecuteMsg::SetValue { value } +} + +pub fn mock_set_rate_msg(action: String, rate: Rate) -> ExecuteMsg { + ExecuteMsg::Rates(RatesMessage::SetRate { action, rate }) +} + +pub fn mock_string_storage_get_value() -> QueryMsg { + QueryMsg::GetValue {} +} + +pub fn mock_string_storage_get_data_owner() -> QueryMsg { + QueryMsg::GetDataOwner {} +} diff --git a/contracts/data-storage/andromeda-string-storage/src/query.rs b/contracts/data-storage/andromeda-string-storage/src/query.rs new file mode 100644 index 000000000..00f503def --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/query.rs @@ -0,0 +1,34 @@ +use crate::state::{DATA, RESTRICTION, DATA_OWNER}; +use andromeda_data_storage::string_storage::{GetDataOwnerResponse, GetValueResponse, StringStorageRestriction}; +use andromeda_std::{ado_contract::ADOContract, amp::AndrAddr, error::ContractError}; +use cosmwasm_std::{Addr, Storage}; + +pub fn has_permission( + storage: &dyn Storage, + addr: &Addr, +) -> Result { + let is_operator = ADOContract::default().is_owner_or_operator(storage, addr.as_str())?; + let allowed = match RESTRICTION.load(storage)? { + StringStorageRestriction::Private => is_operator, + StringStorageRestriction::Public => true, + StringStorageRestriction::Restricted => match DATA_OWNER.load(storage).ok() { + Some(owner) => addr == owner, + None => true, + }, + }; + Ok(is_operator || allowed) +} + +pub fn get_value(storage: &dyn Storage) -> Result { + let value = DATA.load(storage)?.into(); + Ok(GetValueResponse { + value, + }) +} + +pub fn get_data_owner(storage: &dyn Storage) -> Result { + let owner = DATA_OWNER.load(storage)?; + Ok(GetDataOwnerResponse { + owner: AndrAddr::from_string(owner), + }) +} diff --git a/contracts/data-storage/andromeda-string-storage/src/state.rs b/contracts/data-storage/andromeda-string-storage/src/state.rs new file mode 100644 index 000000000..1f731ac4e --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/state.rs @@ -0,0 +1,7 @@ +use andromeda_data_storage::string_storage::{StringStorage, StringStorageRestriction}; +use cw_storage_plus::Item; +use cosmwasm_std::Addr; + +pub const DATA: Item = Item::new("data"); +pub const DATA_OWNER: Item = Item::new("data_owner"); +pub const RESTRICTION: Item = Item::new("restriction"); \ No newline at end of file diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs b/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs new file mode 100644 index 000000000..5ba6b1ebd --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs @@ -0,0 +1,71 @@ +use andromeda_data_storage::string_storage::{ + ExecuteMsg, GetValueResponse, InstantiateMsg, StringStorage, StringStorageRestriction, QueryMsg, +}; +use andromeda_std::{ + error::ContractError, + testing::mock_querier::{mock_dependencies_custom, WasmMockQuerier, MOCK_KERNEL_CONTRACT}, +}; +use cosmwasm_std::{ + from_json, + testing::{mock_env, mock_info, MockApi, MockStorage}, + Coin, Deps, DepsMut, MessageInfo, OwnedDeps, Response, +}; + +use crate::contract::{execute, instantiate, query}; + +pub type MockDeps = OwnedDeps; + +pub fn proper_initialization(restriction: StringStorageRestriction) -> (MockDeps, MessageInfo) { + let mut deps = mock_dependencies_custom(&[]); + let info = mock_info("creator", &[]); + let msg = InstantiateMsg { + kernel_address: MOCK_KERNEL_CONTRACT.to_string(), + owner: None, + restriction, + }; + let env = mock_env(); + instantiate(deps.as_mut(), env, info.clone(), msg).unwrap(); + (deps, info) +} + +pub fn query_value(deps: Deps) -> Result { + let res = query(deps, mock_env(), QueryMsg::GetValue {}); + match res { + Ok(res) => Ok(from_json(res).unwrap()), + Err(err) => Err(err), + } +} + +pub fn set_value( + deps: DepsMut<'_>, + value: &StringStorage, + sender: &str, +) -> Result { + let msg = ExecuteMsg::SetValue { + value: value.clone(), + }; + let info = mock_info(sender, &[]); + execute(deps, mock_env(), info, msg) +} + +pub fn set_value_with_funds( + deps: DepsMut<'_>, + value: &StringStorage, + sender: &str, + coin: Coin, +) -> Result { + let msg = ExecuteMsg::SetValue { + value: value.clone(), + }; + let info = mock_info(sender, &[coin]); + execute(deps, mock_env(), info, msg) +} + +pub fn delete_value( + deps: DepsMut<'_>, + sender: &str, +) -> Result { + let msg = ExecuteMsg::DeleteValue {}; + let info = mock_info(sender, &[]); + execute(deps, mock_env(), info, msg) +} \ No newline at end of file diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs b/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs new file mode 100644 index 000000000..aea717dc8 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs @@ -0,0 +1,2 @@ +mod mock; +mod tests; \ No newline at end of file diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs b/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs new file mode 100644 index 000000000..ad0108ec6 --- /dev/null +++ b/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs @@ -0,0 +1,312 @@ +use crate::contract::{execute, query}; +use andromeda_data_storage::string_storage::{ + ExecuteMsg, GetValueResponse, StringStorage, StringStorageRestriction, QueryMsg, GetDataOwnerResponse, +}; +use cosmwasm_std::{ + coin, from_json, testing::mock_env, BankMsg, CosmosMsg, Decimal, Response, SubMsg, +}; + +use andromeda_std::{ + ado_base::rates::{LocalRate, LocalRateType, LocalRateValue, PercentRate, Rate, RatesMessage}, + ado_contract::ADOContract, + amp::{AndrAddr, Recipient}, + error::ContractError, +}; + +use super::mock::{ + delete_value, proper_initialization, query_value, set_value, set_value_with_funds, +}; + +#[test] +fn test_instantiation() { + proper_initialization(StringStorageRestriction::Private); +} + +#[test] +fn test_set_and_update_value() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Private); + let value = StringStorage::String("value".to_string()); + set_value( + deps.as_mut(), + &value, + info.sender.as_ref(), + ) + .unwrap(); + + let query_res: GetValueResponse = query_value(deps.as_ref()).unwrap(); + + assert_eq!( + GetValueResponse { + value: value.into() + }, + query_res + ); + + let value = StringStorage::String("value2".to_string()); + set_value( + deps.as_mut(), + &value, + info.sender.as_ref(), + ) + .unwrap(); + + let query_res: GetValueResponse = query_value(deps.as_ref()).unwrap(); + + assert_eq!(GetValueResponse { value: value.into() }, query_res); +} + +#[test] +fn test_set_value_with_tax() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Private); + let value = StringStorage::String("value".to_string()); + let tax_recipient = "tax_recipient"; + + // Set percent rates + let set_percent_rate_msg = ExecuteMsg::Rates(RatesMessage::SetRate { + action: "StringStorageSetValue".to_string(), + rate: Rate::Local(LocalRate { + rate_type: LocalRateType::Additive, + recipients: vec![], + value: LocalRateValue::Percent(PercentRate { + percent: Decimal::one(), + }), + description: None, + }), + }); + + let err = execute( + deps.as_mut(), + mock_env(), + info.clone(), + set_percent_rate_msg, + ) + .unwrap_err(); + + assert_eq!(err, ContractError::InvalidRate {}); + + let rate: Rate = Rate::Local(LocalRate { + rate_type: LocalRateType::Additive, + recipients: vec![Recipient { + address: AndrAddr::from_string(tax_recipient.to_string()), + msg: None, + ibc_recovery_address: None, + }], + value: LocalRateValue::Flat(coin(20_u128, "uandr")), + description: None, + }); + + // Set rates + ADOContract::default() + .set_rates(deps.as_mut().storage, "StringStorageSetValue", rate) + .unwrap(); + + // Sent the exact amount required for tax + let res = set_value_with_funds( + deps.as_mut(), + &value, + info.sender.as_ref(), + coin(20_u128, "uandr".to_string()), + ) + .unwrap(); + let expected_response: Response = Response::new() + .add_submessage(SubMsg::new(CosmosMsg::Bank(BankMsg::Send { + to_address: tax_recipient.to_string(), + amount: vec![coin(20, "uandr")], + }))) + .add_attributes(vec![ + ("method", "set_value"), + ("sender", "creator"), + ]) + .add_attribute("value", format!("{value:?}")); + assert_eq!(expected_response, res); + + // Sent less than amount required for tax + let err = set_value_with_funds( + deps.as_mut(), + &value, + info.sender.as_ref(), + coin(19_u128, "uandr".to_string()), + ) + .unwrap_err(); + assert_eq!(err, ContractError::InsufficientFunds {}); + + // Sent more than required amount for tax + let res = set_value_with_funds( + deps.as_mut(), + &value, + info.sender.as_ref(), + coin(200_u128, "uandr".to_string()), + ) + .unwrap(); + let expected_response: Response = Response::new() + .add_submessage(SubMsg::new(CosmosMsg::Bank(BankMsg::Send { + to_address: tax_recipient.to_string(), + amount: vec![coin(20, "uandr")], + }))) + // 200 was sent, but the tax is only 20, so we send back the difference + .add_submessage(SubMsg::new(CosmosMsg::Bank(BankMsg::Send { + to_address: "creator".to_string(), + amount: vec![coin(180, "uandr")], + }))) + .add_attributes(vec![ + ("method", "set_value"), + ("sender", "creator"), + ]) + .add_attribute("value", format!("{value:?}")); + assert_eq!(expected_response, res); +} + +struct TestHandleStringStorage { + name: &'static str, + string_storage: StringStorage, + expected_error: Option, +} + +#[test] +fn test_set_value_invalid() { + let test_cases = vec![ + TestHandleStringStorage { + name: "Empty String", + string_storage: StringStorage::String("".to_string()), + expected_error: Some(ContractError::EmptyString {}), + }, + ]; + + for test in test_cases { + + let res = test.string_storage.validate(); + + if let Some(err) = test.expected_error { + assert_eq!(res.unwrap_err(), err, "{}", test.name); + continue; + } + + assert!(res.is_ok()) + } +} + +#[test] +fn test_delete_value() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Private); + let value = StringStorage::String("value".to_string()); + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); + query_value(deps.as_ref()).unwrap_err(); +} + +#[test] +fn test_restriction_private() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Private); + + let value = StringStorage::String("value".to_string()); + let external_user = "external".to_string(); + + // Set Value as owner + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as external user + // This should error + set_value(deps.as_mut(), &value, &external_user).unwrap_err(); + // Set a value by owner so we can test delete for it + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + // Delete value set by owner by external user + // This will error + delete_value(deps.as_mut(), &external_user).unwrap_err(); + + // Value is still present + query_value(deps.as_ref()).unwrap(); +} + +#[test] +fn test_restriction_public() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Public); + + let value = StringStorage::String("value".to_string()); + let external_user = "external".to_string(); + + // Set Value as owner + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); + // This should error + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as external user + set_value(deps.as_mut(), &value, &external_user).unwrap(); + delete_value(deps.as_mut(), &external_user).unwrap(); + // This should error + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as owner + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + // Delete the value as external user + delete_value(deps.as_mut(), &external_user).unwrap(); + // This should error + query_value(deps.as_ref()).unwrap_err(); +} + +#[test] +fn test_restriction_restricted() { + let (mut deps, info) = proper_initialization(StringStorageRestriction::Restricted); + + let value = StringStorage::String("value".to_string()); + let value2 = StringStorage::String("value2".to_string()); + let external_user = "external".to_string(); + let external_user2 = "external2".to_string(); + + // Set Value as owner + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); + // This should error + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as external user + set_value(deps.as_mut(), &value, &external_user).unwrap(); + delete_value(deps.as_mut(), &external_user).unwrap(); + // This should error + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as owner and try to delete as external user + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + // Try to modify it as external user + set_value(deps.as_mut(), &value2, &external_user).unwrap_err(); + // Delete the value as external user, this should error + delete_value(deps.as_mut(), &external_user).unwrap_err(); + + query_value(deps.as_ref()).unwrap(); + + // Set Value as external user and try to delete as owner + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); + // Delete the value as external user, this will success as owner has permission to do anything + delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); + + query_value(deps.as_ref()).unwrap_err(); + + // Set Value as external user 1 and try to delete as external user 2 + set_value(deps.as_mut(), &value, &external_user).unwrap(); + // Delete the value as external user, this will error + delete_value(deps.as_mut(), &external_user2).unwrap_err(); + + query_value(deps.as_ref()).unwrap(); +} + +#[test] +fn test_query_data_owner() { + let (mut deps, _) = proper_initialization(StringStorageRestriction::Restricted); + let external_user = "external".to_string(); + let external_user2 = "external2".to_string(); + let value = StringStorage::String("value".to_string()); + set_value(deps.as_mut(), &value, &external_user.clone()).unwrap(); + + let res: GetDataOwnerResponse = from_json(query(deps.as_ref(), mock_env(), QueryMsg::GetDataOwner {}).unwrap()).unwrap(); + + assert_eq!(res, GetDataOwnerResponse{owner: AndrAddr::from_string(external_user.clone())}); + + let res = delete_value(deps.as_mut(), &external_user2).unwrap_err(); + assert_eq!(res, ContractError::Unauthorized {}); + + delete_value(deps.as_mut(), &external_user).unwrap(); + + query(deps.as_ref(), mock_env(), QueryMsg::GetDataOwner {}).unwrap_err(); +} diff --git a/packages/andromeda-data-storage/src/lib.rs b/packages/andromeda-data-storage/src/lib.rs index 2d8afe570..bc816d3f0 100644 --- a/packages/andromeda-data-storage/src/lib.rs +++ b/packages/andromeda-data-storage/src/lib.rs @@ -1 +1,2 @@ pub mod primitive; +pub mod string_storage; diff --git a/packages/andromeda-data-storage/src/string_storage.rs b/packages/andromeda-data-storage/src/string_storage.rs new file mode 100644 index 000000000..83ca2290b --- /dev/null +++ b/packages/andromeda-data-storage/src/string_storage.rs @@ -0,0 +1,142 @@ +use andromeda_std::{amp::AndrAddr, andr_exec, andr_instantiate, andr_query, error::ContractError}; +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{ensure, StdError}; + +#[andr_instantiate] +#[cw_serde] +pub struct InstantiateMsg { + pub restriction: StringStorageRestriction, +} + +#[andr_exec] +#[cw_serde] +pub enum ExecuteMsg { + SetValue { + value: StringStorage, + }, + DeleteValue {}, + UpdateRestriction { + restriction: StringStorageRestriction, + }, +} + +#[andr_query] +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(GetValueResponse)] + GetValue {}, + #[returns(GetDataOwnerResponse)] + GetDataOwner {}, +} + +#[cw_serde] +pub enum StringStorage { + String(String), +} + +impl StringStorage { + pub fn validate(&self) -> Result<(), ContractError> { + match self { + StringStorage::String(value) => { + ensure!( + !value.to_string().is_empty(), + ContractError::EmptyString {} + ); + } + } + Ok(()) + } +} + +impl From for String { + fn from(string_storage: StringStorage) -> Self { + match string_storage { + StringStorage::String(value) => value, + } + } +} + +impl From for StringStorage { + fn from(value: String) -> Self { + StringStorage::String(value) + } +} + +impl StringStorage { + pub fn try_get_value(&self) -> Result { + match self { + StringStorage::String(value) => Ok(value.to_string()), + } + } +} + +#[cw_serde] +pub enum StringStorageRestriction { + Private, + Public, + Restricted, +} + +#[cw_serde] +pub struct GetValueResponse { + pub value: String, +} + +#[cw_serde] +pub struct GetDataOwnerResponse { + pub owner: AndrAddr, +} + +#[cfg(test)] +mod tests { + use super::*; + + struct TestValidate { + name: &'static str, + string_storage: StringStorage, + expected_error: Option, + } + + #[test] + fn test_from_string() { + let cases = vec![ + ( + StringStorage::String("Some string".to_string()), + "String".to_string(), + ), + ]; + + for (value, expected_str) in cases.iter() { + assert_eq!(String::from(value.to_owned()), expected_str.to_owned()); + } + } + + #[test] + fn test_validate() { + let test_cases = vec![ + TestValidate { + name: "Empty string", + string_storage: StringStorage::String("".to_string()), + expected_error: Some(ContractError::EmptyString {}), + }, + ]; + + for test in test_cases { + let res = test.string_storage.validate(); + + if let Some(err) = test.expected_error { + assert_eq!(res.unwrap_err(), err, "{}", test.name); + continue; + } + + assert!(res.is_ok()); + } + } + + #[test] + fn try_get_string() { + let string_storage = StringStorage::String("String".to_string()); + assert_eq!("String".to_string(), string_storage.try_get_value().unwrap()); + } +} From 20872201d60df2038ddf1c03ec8b0ecd59600f6c Mon Sep 17 00:00:00 2001 From: mdjakovic0920 Date: Wed, 10 Jul 2024 16:13:18 +0000 Subject: [PATCH 2/5] fix: remove unused key --- contracts/data-storage/andromeda-string-storage/src/mock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/data-storage/andromeda-string-storage/src/mock.rs b/contracts/data-storage/andromeda-string-storage/src/mock.rs index 5942bbfeb..cb26678db 100644 --- a/contracts/data-storage/andromeda-string-storage/src/mock.rs +++ b/contracts/data-storage/andromeda-string-storage/src/mock.rs @@ -43,7 +43,6 @@ impl MockStringStorage { &self, app: &mut MockApp, sender: Addr, - key: Option, value: StringStorage, funds: Option, ) -> ExecuteResult { From cb3e854bf16acc33bd7acfc21a905b5d8c6ad588 Mon Sep 17 00:00:00 2001 From: mdjakovic0920 Date: Fri, 23 Aug 2024 13:38:39 +0000 Subject: [PATCH 3/5] fix: removed get_action_name and checked fmt --- .../examples/schema.rs | 2 +- .../andromeda-string-storage/src/contract.rs | 18 ++--- .../andromeda-string-storage/src/execute.rs | 13 ++-- .../andromeda-string-storage/src/mock.rs | 4 +- .../andromeda-string-storage/src/query.rs | 15 ++--- .../andromeda-string-storage/src/state.rs | 4 +- .../src/testing/mock.rs | 9 +-- .../src/testing/mod.rs | 2 +- .../src/testing/tests.rs | 65 +++++++++---------- .../src/string_storage.rs | 32 ++++----- 10 files changed, 71 insertions(+), 93 deletions(-) diff --git a/contracts/data-storage/andromeda-string-storage/examples/schema.rs b/contracts/data-storage/andromeda-string-storage/examples/schema.rs index 0ae06361e..6e88537f6 100644 --- a/contracts/data-storage/andromeda-string-storage/examples/schema.rs +++ b/contracts/data-storage/andromeda-string-storage/examples/schema.rs @@ -7,4 +7,4 @@ fn main() { execute: ExecuteMsg, } -} \ No newline at end of file +} diff --git a/contracts/data-storage/andromeda-string-storage/src/contract.rs b/contracts/data-storage/andromeda-string-storage/src/contract.rs index 11e91a4f0..2662d510e 100644 --- a/contracts/data-storage/andromeda-string-storage/src/contract.rs +++ b/contracts/data-storage/andromeda-string-storage/src/contract.rs @@ -2,6 +2,11 @@ use cosmwasm_std::entry_point; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response}; +use crate::{ + execute::handle_execute, + query::{get_data_owner, get_value}, + state::RESTRICTION, +}; use andromeda_data_storage::string_storage::{ExecuteMsg, InstantiateMsg, QueryMsg}; use andromeda_std::{ ado_base::{InstantiateMsg as BaseInstantiateMsg, MigrateMsg}, @@ -9,11 +14,6 @@ use andromeda_std::{ common::{context::ExecuteContext, encode_binary}, error::ContractError, }; -use crate::{ - execute::handle_execute, - query::{get_value, get_data_owner}, - state::RESTRICTION, -}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:andromeda-string-storage"; @@ -54,7 +54,7 @@ pub fn execute( match msg { ExecuteMsg::AMPReceive(pkt) => { ADOContract::default().execute_amp_receive(ctx, pkt, handle_execute) - }, + } _ => handle_execute(ctx, msg), } } @@ -62,8 +62,8 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { match msg { - QueryMsg::GetValue { } => encode_binary(&get_value(deps.storage)?), - QueryMsg::GetDataOwner { } => encode_binary(&get_data_owner(deps.storage)?), + QueryMsg::GetValue {} => encode_binary(&get_value(deps.storage)?), + QueryMsg::GetDataOwner {} => encode_binary(&get_data_owner(deps.storage)?), _ => ADOContract::default().query(deps, env, msg), } } @@ -71,4 +71,4 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { ADOContract::default().migrate(deps, CONTRACT_NAME, CONTRACT_VERSION) -} \ No newline at end of file +} diff --git a/contracts/data-storage/andromeda-string-storage/src/execute.rs b/contracts/data-storage/andromeda-string-storage/src/execute.rs index c7afaa537..70120fbdd 100644 --- a/contracts/data-storage/andromeda-string-storage/src/execute.rs +++ b/contracts/data-storage/andromeda-string-storage/src/execute.rs @@ -2,10 +2,7 @@ use andromeda_data_storage::string_storage::{ExecuteMsg, StringStorage, StringSt use andromeda_std::{ ado_base::rates::{Rate, RatesMessage}, ado_contract::ADOContract, - common::{ - actions::call_action, call_action::get_action_name, context::ExecuteContext, - rates::get_tax_amount, Funds, - }, + common::{actions::call_action, context::ExecuteContext, rates::get_tax_amount, Funds}, error::ContractError, }; use cosmwasm_std::{ @@ -17,10 +14,9 @@ use crate::{ query::has_permission, state::{DATA, DATA_OWNER, RESTRICTION}, }; -const CONTRACT_NAME: &str = "crates.io:andromeda-string-storage"; pub fn handle_execute(mut ctx: ExecuteContext, msg: ExecuteMsg) -> Result { - let action = get_action_name(CONTRACT_NAME, msg.as_ref()); + let action = msg.as_ref().to_string(); call_action( &mut ctx.deps, &ctx.info, @@ -32,7 +28,7 @@ pub fn handle_execute(mut ctx: ExecuteContext, msg: ExecuteMsg) -> Result update_restriction(ctx, restriction), ExecuteMsg::SetValue { value } => set_value(ctx, value, action), - ExecuteMsg::DeleteValue { } => delete_value(ctx), + ExecuteMsg::DeleteValue {} => delete_value(ctx), ExecuteMsg::Rates(rates_message) => match rates_message { RatesMessage::SetRate { rate, .. } => match rate { Rate::Local(local_rate) => { @@ -112,8 +108,7 @@ pub fn delete_value(ctx: ExecuteContext) -> Result { DATA_OWNER.remove(ctx.deps.storage); Ok(Response::new() .add_attribute("method", "delete_value") - .add_attribute("sender", sender) - ) + .add_attribute("sender", sender)) } fn tax_set_value( diff --git a/contracts/data-storage/andromeda-string-storage/src/mock.rs b/contracts/data-storage/andromeda-string-storage/src/mock.rs index cb26678db..bd3766480 100644 --- a/contracts/data-storage/andromeda-string-storage/src/mock.rs +++ b/contracts/data-storage/andromeda-string-storage/src/mock.rs @@ -1,8 +1,8 @@ #![cfg(all(not(target_arch = "wasm32"), feature = "testing"))] use crate::contract::{execute, instantiate, query}; use andromeda_data_storage::string_storage::{ - ExecuteMsg, GetDataOwnerResponse, GetValueResponse, InstantiateMsg, StringStorage, StringStorageRestriction, - QueryMsg, + ExecuteMsg, GetDataOwnerResponse, GetValueResponse, InstantiateMsg, QueryMsg, StringStorage, + StringStorageRestriction, }; use andromeda_std::ado_base::rates::{Rate, RatesMessage}; use andromeda_testing::mock::MockApp; diff --git a/contracts/data-storage/andromeda-string-storage/src/query.rs b/contracts/data-storage/andromeda-string-storage/src/query.rs index 00f503def..013fc2fdd 100644 --- a/contracts/data-storage/andromeda-string-storage/src/query.rs +++ b/contracts/data-storage/andromeda-string-storage/src/query.rs @@ -1,12 +1,11 @@ -use crate::state::{DATA, RESTRICTION, DATA_OWNER}; -use andromeda_data_storage::string_storage::{GetDataOwnerResponse, GetValueResponse, StringStorageRestriction}; +use crate::state::{DATA, DATA_OWNER, RESTRICTION}; +use andromeda_data_storage::string_storage::{ + GetDataOwnerResponse, GetValueResponse, StringStorageRestriction, +}; use andromeda_std::{ado_contract::ADOContract, amp::AndrAddr, error::ContractError}; use cosmwasm_std::{Addr, Storage}; -pub fn has_permission( - storage: &dyn Storage, - addr: &Addr, -) -> Result { +pub fn has_permission(storage: &dyn Storage, addr: &Addr) -> Result { let is_operator = ADOContract::default().is_owner_or_operator(storage, addr.as_str())?; let allowed = match RESTRICTION.load(storage)? { StringStorageRestriction::Private => is_operator, @@ -21,9 +20,7 @@ pub fn has_permission( pub fn get_value(storage: &dyn Storage) -> Result { let value = DATA.load(storage)?.into(); - Ok(GetValueResponse { - value, - }) + Ok(GetValueResponse { value }) } pub fn get_data_owner(storage: &dyn Storage) -> Result { diff --git a/contracts/data-storage/andromeda-string-storage/src/state.rs b/contracts/data-storage/andromeda-string-storage/src/state.rs index 1f731ac4e..9424f3403 100644 --- a/contracts/data-storage/andromeda-string-storage/src/state.rs +++ b/contracts/data-storage/andromeda-string-storage/src/state.rs @@ -1,7 +1,7 @@ use andromeda_data_storage::string_storage::{StringStorage, StringStorageRestriction}; -use cw_storage_plus::Item; use cosmwasm_std::Addr; +use cw_storage_plus::Item; pub const DATA: Item = Item::new("data"); pub const DATA_OWNER: Item = Item::new("data_owner"); -pub const RESTRICTION: Item = Item::new("restriction"); \ No newline at end of file +pub const RESTRICTION: Item = Item::new("restriction"); diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs b/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs index 5ba6b1ebd..db8278c6a 100644 --- a/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs +++ b/contracts/data-storage/andromeda-string-storage/src/testing/mock.rs @@ -1,5 +1,5 @@ use andromeda_data_storage::string_storage::{ - ExecuteMsg, GetValueResponse, InstantiateMsg, StringStorage, StringStorageRestriction, QueryMsg, + ExecuteMsg, GetValueResponse, InstantiateMsg, QueryMsg, StringStorage, StringStorageRestriction, }; use andromeda_std::{ error::ContractError, @@ -61,11 +61,8 @@ pub fn set_value_with_funds( execute(deps, mock_env(), info, msg) } -pub fn delete_value( - deps: DepsMut<'_>, - sender: &str, -) -> Result { +pub fn delete_value(deps: DepsMut<'_>, sender: &str) -> Result { let msg = ExecuteMsg::DeleteValue {}; let info = mock_info(sender, &[]); execute(deps, mock_env(), info, msg) -} \ No newline at end of file +} diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs b/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs index aea717dc8..3bfda2893 100644 --- a/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs +++ b/contracts/data-storage/andromeda-string-storage/src/testing/mod.rs @@ -1,2 +1,2 @@ mod mock; -mod tests; \ No newline at end of file +mod tests; diff --git a/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs b/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs index ad0108ec6..df9cc8b59 100644 --- a/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs +++ b/contracts/data-storage/andromeda-string-storage/src/testing/tests.rs @@ -1,6 +1,7 @@ use crate::contract::{execute, query}; use andromeda_data_storage::string_storage::{ - ExecuteMsg, GetValueResponse, StringStorage, StringStorageRestriction, QueryMsg, GetDataOwnerResponse, + ExecuteMsg, GetDataOwnerResponse, GetValueResponse, QueryMsg, StringStorage, + StringStorageRestriction, }; use cosmwasm_std::{ coin, from_json, testing::mock_env, BankMsg, CosmosMsg, Decimal, Response, SubMsg, @@ -26,12 +27,7 @@ fn test_instantiation() { fn test_set_and_update_value() { let (mut deps, info) = proper_initialization(StringStorageRestriction::Private); let value = StringStorage::String("value".to_string()); - set_value( - deps.as_mut(), - &value, - info.sender.as_ref(), - ) - .unwrap(); + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); let query_res: GetValueResponse = query_value(deps.as_ref()).unwrap(); @@ -43,16 +39,16 @@ fn test_set_and_update_value() { ); let value = StringStorage::String("value2".to_string()); - set_value( - deps.as_mut(), - &value, - info.sender.as_ref(), - ) - .unwrap(); + set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); let query_res: GetValueResponse = query_value(deps.as_ref()).unwrap(); - assert_eq!(GetValueResponse { value: value.into() }, query_res); + assert_eq!( + GetValueResponse { + value: value.into() + }, + query_res + ); } #[test] @@ -97,7 +93,7 @@ fn test_set_value_with_tax() { // Set rates ADOContract::default() - .set_rates(deps.as_mut().storage, "StringStorageSetValue", rate) + .set_rates(deps.as_mut().storage, "SetValue", rate) .unwrap(); // Sent the exact amount required for tax @@ -113,10 +109,7 @@ fn test_set_value_with_tax() { to_address: tax_recipient.to_string(), amount: vec![coin(20, "uandr")], }))) - .add_attributes(vec![ - ("method", "set_value"), - ("sender", "creator"), - ]) + .add_attributes(vec![("method", "set_value"), ("sender", "creator")]) .add_attribute("value", format!("{value:?}")); assert_eq!(expected_response, res); @@ -148,10 +141,7 @@ fn test_set_value_with_tax() { to_address: "creator".to_string(), amount: vec![coin(180, "uandr")], }))) - .add_attributes(vec![ - ("method", "set_value"), - ("sender", "creator"), - ]) + .add_attributes(vec![("method", "set_value"), ("sender", "creator")]) .add_attribute("value", format!("{value:?}")); assert_eq!(expected_response, res); } @@ -164,16 +154,13 @@ struct TestHandleStringStorage { #[test] fn test_set_value_invalid() { - let test_cases = vec![ - TestHandleStringStorage { - name: "Empty String", - string_storage: StringStorage::String("".to_string()), - expected_error: Some(ContractError::EmptyString {}), - }, - ]; + let test_cases = vec![TestHandleStringStorage { + name: "Empty String", + string_storage: StringStorage::String("".to_string()), + expected_error: Some(ContractError::EmptyString {}), + }]; for test in test_cases { - let res = test.string_storage.validate(); if let Some(err) = test.expected_error { @@ -273,21 +260,21 @@ fn test_restriction_restricted() { set_value(deps.as_mut(), &value2, &external_user).unwrap_err(); // Delete the value as external user, this should error delete_value(deps.as_mut(), &external_user).unwrap_err(); - + query_value(deps.as_ref()).unwrap(); // Set Value as external user and try to delete as owner set_value(deps.as_mut(), &value, info.sender.as_ref()).unwrap(); // Delete the value as external user, this will success as owner has permission to do anything delete_value(deps.as_mut(), info.sender.as_ref()).unwrap(); - + query_value(deps.as_ref()).unwrap_err(); // Set Value as external user 1 and try to delete as external user 2 set_value(deps.as_mut(), &value, &external_user).unwrap(); // Delete the value as external user, this will error delete_value(deps.as_mut(), &external_user2).unwrap_err(); - + query_value(deps.as_ref()).unwrap(); } @@ -299,9 +286,15 @@ fn test_query_data_owner() { let value = StringStorage::String("value".to_string()); set_value(deps.as_mut(), &value, &external_user.clone()).unwrap(); - let res: GetDataOwnerResponse = from_json(query(deps.as_ref(), mock_env(), QueryMsg::GetDataOwner {}).unwrap()).unwrap(); + let res: GetDataOwnerResponse = + from_json(query(deps.as_ref(), mock_env(), QueryMsg::GetDataOwner {}).unwrap()).unwrap(); - assert_eq!(res, GetDataOwnerResponse{owner: AndrAddr::from_string(external_user.clone())}); + assert_eq!( + res, + GetDataOwnerResponse { + owner: AndrAddr::from_string(external_user.clone()) + } + ); let res = delete_value(deps.as_mut(), &external_user2).unwrap_err(); assert_eq!(res, ContractError::Unauthorized {}); diff --git a/packages/andromeda-data-storage/src/string_storage.rs b/packages/andromeda-data-storage/src/string_storage.rs index 83ca2290b..3403aa6be 100644 --- a/packages/andromeda-data-storage/src/string_storage.rs +++ b/packages/andromeda-data-storage/src/string_storage.rs @@ -39,10 +39,7 @@ impl StringStorage { pub fn validate(&self) -> Result<(), ContractError> { match self { StringStorage::String(value) => { - ensure!( - !value.to_string().is_empty(), - ContractError::EmptyString {} - ); + ensure!(!value.to_string().is_empty(), ContractError::EmptyString {}); } } Ok(()) @@ -100,12 +97,10 @@ mod tests { #[test] fn test_from_string() { - let cases = vec![ - ( - StringStorage::String("Some string".to_string()), - "String".to_string(), - ), - ]; + let cases = vec![( + StringStorage::String("Some string".to_string()), + "String".to_string(), + )]; for (value, expected_str) in cases.iter() { assert_eq!(String::from(value.to_owned()), expected_str.to_owned()); @@ -114,13 +109,11 @@ mod tests { #[test] fn test_validate() { - let test_cases = vec![ - TestValidate { - name: "Empty string", - string_storage: StringStorage::String("".to_string()), - expected_error: Some(ContractError::EmptyString {}), - }, - ]; + let test_cases = vec![TestValidate { + name: "Empty string", + string_storage: StringStorage::String("".to_string()), + expected_error: Some(ContractError::EmptyString {}), + }]; for test in test_cases { let res = test.string_storage.validate(); @@ -137,6 +130,9 @@ mod tests { #[test] fn try_get_string() { let string_storage = StringStorage::String("String".to_string()); - assert_eq!("String".to_string(), string_storage.try_get_value().unwrap()); + assert_eq!( + "String".to_string(), + string_storage.try_get_value().unwrap() + ); } } From 549205ec9f777410e0b8bd048e5638ef3c328953 Mon Sep 17 00:00:00 2001 From: mdjakovic0920 Date: Fri, 23 Aug 2024 13:42:55 +0000 Subject: [PATCH 4/5] added log to CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 691b5fe16..00b24e4f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added Expiry Enum [(#419)](https://github.com/andromedaprotocol/andromeda-core/pull/419) - Added Conditional Splitter [(#441)](https://github.com/andromedaprotocol/andromeda-core/pull/441) - Validator Staking: Added the option to set an amount while unstaking [(#458)](https://github.com/andromedaprotocol/andromeda-core/pull/458) +- Added String Storage ADO [(#512)](https://github.com/andromedaprotocol/andromeda-core/pull/512) ### Changed From 01ad147a280e8eeb5ad25cc5e53fa95094dd8c26 Mon Sep 17 00:00:00 2001 From: mdjakovic0920 Date: Fri, 23 Aug 2024 13:47:02 +0000 Subject: [PATCH 5/5] fix: fixed test case --- packages/andromeda-data-storage/src/string_storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/andromeda-data-storage/src/string_storage.rs b/packages/andromeda-data-storage/src/string_storage.rs index 3403aa6be..34d36b9d9 100644 --- a/packages/andromeda-data-storage/src/string_storage.rs +++ b/packages/andromeda-data-storage/src/string_storage.rs @@ -98,7 +98,7 @@ mod tests { #[test] fn test_from_string() { let cases = vec![( - StringStorage::String("Some string".to_string()), + StringStorage::String("String".to_string()), "String".to_string(), )];