From f9f7a81cb0bed5ceb222f6d56bbb4a65ee6a2880 Mon Sep 17 00:00:00 2001 From: hu55a1n1 Date: Wed, 29 Nov 2023 09:13:29 -0800 Subject: [PATCH] Setup cargo workspace to support multiple contracts --- bisenzone-cw-mvp/README.md | 2 +- bisenzone-cw-mvp/scripts/deploy-contract.sh | 2 +- bisenzone-cw-mvp/src/bin/schema.rs | 11 - bisenzone-cw-mvp/src/contract.rs | 322 -------------------- bisenzone-cw-mvp/src/error.rs | 27 -- bisenzone-cw-mvp/src/lib.rs | 15 - bisenzone-cw-mvp/src/msg.rs | 36 --- bisenzone-cw-mvp/src/state.rs | 11 - 8 files changed, 2 insertions(+), 424 deletions(-) delete mode 100644 bisenzone-cw-mvp/src/bin/schema.rs delete mode 100644 bisenzone-cw-mvp/src/contract.rs delete mode 100644 bisenzone-cw-mvp/src/error.rs delete mode 100644 bisenzone-cw-mvp/src/lib.rs delete mode 100644 bisenzone-cw-mvp/src/msg.rs delete mode 100644 bisenzone-cw-mvp/src/state.rs diff --git a/bisenzone-cw-mvp/README.md b/bisenzone-cw-mvp/README.md index ac586cc..1f7c83b 100644 --- a/bisenzone-cw-mvp/README.md +++ b/bisenzone-cw-mvp/README.md @@ -16,7 +16,7 @@ CosmWasm smart contracts used in the Bisenzone MVP. ```bash # terminal-2 ./scripts/build-contract.sh - ./scripts/deploy-contract.sh artifacts/cw_mtcs.wasm + ./scripts/deploy-contract.sh artifacts/cofi_karma_game.wasm ``` * Set contract env var (using the output of the `deploy.sh` script) - diff --git a/bisenzone-cw-mvp/scripts/deploy-contract.sh b/bisenzone-cw-mvp/scripts/deploy-contract.sh index 6215ab9..9deca3e 100755 --- a/bisenzone-cw-mvp/scripts/deploy-contract.sh +++ b/bisenzone-cw-mvp/scripts/deploy-contract.sh @@ -6,7 +6,7 @@ set -eo pipefail usage() { echo "Usage: $0 WASM_BIN [COUNT]" - echo "Example: $0 artifacts/cw_mtcs.wasm" + echo "Example: $0 artifacts/cofi_karma_game.wasm" exit 1 } diff --git a/bisenzone-cw-mvp/src/bin/schema.rs b/bisenzone-cw-mvp/src/bin/schema.rs deleted file mode 100644 index 55a2a8e..0000000 --- a/bisenzone-cw-mvp/src/bin/schema.rs +++ /dev/null @@ -1,11 +0,0 @@ -use cosmwasm_schema::write_api; - -use cw_mtcs::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; - -fn main() { - write_api! { - instantiate: InstantiateMsg, - execute: ExecuteMsg, - query: QueryMsg, - } -} diff --git a/bisenzone-cw-mvp/src/contract.rs b/bisenzone-cw-mvp/src/contract.rs deleted file mode 100644 index a0027df..0000000 --- a/bisenzone-cw-mvp/src/contract.rs +++ /dev/null @@ -1,322 +0,0 @@ -use cosmwasm_std::{ - entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, - StdResult, Uint128, -}; -use cw2::set_contract_version; -use cw20_base::{ - contract::{execute_mint, query_balance}, - state::{MinterData, TokenInfo, TOKEN_INFO}, -}; - -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; -use crate::state::{State, STATE, UTILIZATION}; - -// version info for migration info -const CONTRACT_NAME: &str = "crates.io:cw-mtcs"; -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 state = State { - owner: info.sender.to_string(), - }; - set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - STATE.save(deps.storage, &state)?; - - // store token info using cw20-base format - let data = TokenInfo { - name: "liquidity savings".to_string(), - symbol: "!$".to_string(), - decimals: 0, - total_supply: Uint128::zero(), - // set self as minter, so we can properly execute mint and burn - mint: Some(MinterData { - minter: env.contract.address, - cap: None, - }), - }; - TOKEN_INFO.save(deps.storage, &data)?; - - Ok(Response::new() - .add_attribute("method", "instantiate") - .add_attribute("owner", info.sender)) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, -) -> Result { - match msg { - ExecuteMsg::UploadObligation { - creditor, - amount, - memo, - } => execute::upload_obligation(deps, info, creditor, amount, memo), - ExecuteMsg::ApplyCycle { path, amount } => { - execute::apply_cycle(deps, env, info, path, amount) - } - } -} - -pub mod execute { - use cosmwasm_std::Uint128; - - use super::*; - - pub fn upload_obligation( - deps: DepsMut, - info: MessageInfo, - creditor: String, - amount: Uint128, - memo: String, - ) -> Result { - let creditor = deps.api.addr_validate(&creditor)?; - - UTILIZATION.update( - deps.storage, - (&creditor, &info.sender), - |utilization| -> Result<_, ContractError> { - // Uncomment if we want to only allow ourselves to add obligations - // if info.sender != state.owner { - // return Err(ContractError::Unauthorized); - // } - - let utilization = utilization.unwrap_or_default() + amount; - Ok(utilization) - }, - )?; - - Ok(Response::new() - .add_attribute("action", "upload_obligation") - .add_attribute("memo", memo)) - } - - pub fn apply_cycle( - deps: DepsMut, - env: Env, - info: MessageInfo, - path: Vec, - amount: Uint128, - ) -> Result { - let mut volume_cleared = Uint128::zero(); - - let path = path - .into_iter() - .map(|addr| deps.api.addr_validate(&addr)) - .collect::>>()?; - - validate_cycle(&path, amount, &deps)?; - - for from_to in path.windows(2) { - let (from, to) = (&from_to[0], &from_to[1]); - - UTILIZATION.update( - deps.storage, - (to, from), - |utilization| -> Result<_, ContractError> { - let utilization = utilization.unwrap_or_default() - amount; - volume_cleared += amount; - - Ok(utilization) - }, - )?; - } - - // call into cw20-base to mint the token, call as self as no one else is allowed - let sub_info = MessageInfo { - sender: env.contract.address.clone(), - funds: vec![], - }; - execute_mint(deps, env, sub_info, info.sender.to_string(), volume_cleared)?; - - Ok(Response::new() - .add_attribute("action", "apply_cycle") - .add_attribute("volume_cleared", format!("{}", volume_cleared))) - } - - fn validate_cycle(path: &[Addr], amount: Uint128, deps: &DepsMut) -> Result<(), ContractError> { - if path.first() != path.last() { - return Err(ContractError::PathNotCycle); - } - - for from_to in path.windows(2) { - let (from, to) = (&from_to[0], &from_to[1]); - - if amount > UTILIZATION.load(deps.storage, (to, from))? { - return Err(ContractError::ClearingTooMuch); - } - } - - Ok(()) - } -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { - match msg { - QueryMsg::GetObligations { creditor } => { - to_json_binary(&query::get_obligations(deps, creditor)?) - } - QueryMsg::Balance { address } => to_json_binary(&query_balance(deps, address)?), - } -} - -pub mod query { - use super::*; - use cosmwasm_std::Order; - - use crate::msg::GetObligationsResponse; - use crate::state::UTILIZATION; - - pub fn get_obligations(deps: Deps, creditor: String) -> StdResult { - let creditor = deps.api.addr_validate(&creditor)?; - - let keys = UTILIZATION - .keys(deps.storage, None, None, Order::Ascending) - .collect::>>()? - .into_iter() - .filter(|(from, _)| from == creditor); - Ok(GetObligationsResponse { - obligations: keys - .map(|(from, to)| { - let utilization = UTILIZATION.load(deps.storage, (&from, &to)).unwrap(); - (to.to_string(), utilization) - }) - .collect(), - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::{ - mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage, - }; - use cosmwasm_std::{coins, from_json, OwnedDeps}; - use cw20::BalanceResponse; - - use crate::msg::GetObligationsResponse; - - const ALICE_ADDRESS: &str = "wasm19xlctyn7ha6pqg7pk9lnk8y60rk8646dm86qgv"; - const BOB_ADDRESS: &str = "wasm19u72czh0w4jraan8esalv48nrwemh8kgax69yw"; - const CHARLIE_ADDRESS: &str = "wasm12r9t5wmre89rwakr0e5nyhfmaf4kdleyltsm9f"; - - #[test] - fn test_initialization() { - let mut deps = mock_dependencies(); - - let msg = InstantiateMsg; - let info = mock_info("creator", &coins(1000, "earth")); - - // we can just call .unwrap() to assert this was a success - let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - } - - #[test] - fn test_upload_obligation() { - let mut deps = mock_dependencies(); - - let msg = InstantiateMsg; - let info = mock_info("creator", &coins(2, "token")); - let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); - - create_obligation(&mut deps, ALICE_ADDRESS, BOB_ADDRESS, 100, "alice -> bob"); - - let res = query( - deps.as_ref(), - mock_env(), - QueryMsg::GetObligations { - creditor: BOB_ADDRESS.to_string(), - }, - ) - .unwrap(); - let value: GetObligationsResponse = from_json(&res).unwrap(); - assert_eq!(&100u32.into(), value.obligations[0].1); - } - - fn create_obligation( - deps: &mut OwnedDeps, - debtor: &str, - creditor: &str, - amount: u32, - memo: &str, - ) { - let info = mock_info(debtor, &coins(2, "token")); - let msg = ExecuteMsg::UploadObligation { - creditor: creditor.to_string(), - amount: amount.into(), - memo: memo.to_string(), - }; - let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); - } - - #[test] - fn test_apply_cycle() { - let mut deps = mock_dependencies(); - - let msg = InstantiateMsg; - let info = mock_info("creator", &coins(2, "token")); - let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); - - create_obligation(&mut deps, ALICE_ADDRESS, BOB_ADDRESS, 100, "alice -> bob"); - create_obligation( - &mut deps, - BOB_ADDRESS, - CHARLIE_ADDRESS, - 80, - "bob -> charlie", - ); - create_obligation( - &mut deps, - CHARLIE_ADDRESS, - ALICE_ADDRESS, - 70, - "charlie -> alice", - ); - - let info = mock_info(ALICE_ADDRESS, &coins(2, "token")); - let msg = ExecuteMsg::ApplyCycle { - path: [ALICE_ADDRESS, BOB_ADDRESS, CHARLIE_ADDRESS, ALICE_ADDRESS] - .into_iter() - .map(ToString::to_string) - .collect(), - amount: 70u32.into(), - }; - let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); - - // Cycle should be cleared and only `30` should remain in `alice -> bob` - let res = query( - deps.as_ref(), - mock_env(), - QueryMsg::GetObligations { - creditor: BOB_ADDRESS.to_string(), - }, - ) - .unwrap(); - let value: GetObligationsResponse = from_json(&res).unwrap(); - assert_eq!(&30u32.into(), value.obligations[0].1); - - // Check that alice received her karma tokens - let res = query( - deps.as_ref(), - mock_env(), - QueryMsg::Balance { - address: ALICE_ADDRESS.to_string(), - }, - ) - .unwrap(); - let value: BalanceResponse = from_json(&res).unwrap(); - assert_eq!(&210u32.into(), value.balance); - } -} diff --git a/bisenzone-cw-mvp/src/error.rs b/bisenzone-cw-mvp/src/error.rs deleted file mode 100644 index ce3c93c..0000000 --- a/bisenzone-cw-mvp/src/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use cosmwasm_std::StdError; -use cw20_base::ContractError as Cw20ContractError; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("Unauthorized")] - Unauthorized, - - #[error("Specified path does not form a cycle")] - PathNotCycle, - - #[error("Amount is greater than utilization")] - ClearingTooMuch, - - #[error("Cw20 error: {0}")] - Cw20(Cw20ContractError), -} - -impl From for ContractError { - fn from(e: Cw20ContractError) -> Self { - Self::Cw20(e) - } -} diff --git a/bisenzone-cw-mvp/src/lib.rs b/bisenzone-cw-mvp/src/lib.rs deleted file mode 100644 index f71330c..0000000 --- a/bisenzone-cw-mvp/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![deny( - warnings, - trivial_casts, - trivial_numeric_casts, - unused_import_braces, - unused_qualifications -)] -#![forbid(unsafe_code)] - -pub mod contract; -mod error; -pub mod msg; -pub mod state; - -pub use crate::error::ContractError; diff --git a/bisenzone-cw-mvp/src/msg.rs b/bisenzone-cw-mvp/src/msg.rs deleted file mode 100644 index 54c8b47..0000000 --- a/bisenzone-cw-mvp/src/msg.rs +++ /dev/null @@ -1,36 +0,0 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Uint128; -#[allow(unused)] -use cw20::BalanceResponse; - -#[cw_serde] -pub struct InstantiateMsg; - -#[cw_serde] -pub enum ExecuteMsg { - UploadObligation { - creditor: String, - amount: Uint128, - memo: String, - }, - ApplyCycle { - path: Vec, - amount: Uint128, - }, -} - -#[cw_serde] -#[derive(QueryResponses)] -pub enum QueryMsg { - // GetCount returns the current count as a json-encoded number - #[returns(GetObligationsResponse)] - GetObligations { creditor: String }, - #[returns(BalanceResponse)] - Balance { address: String }, -} - -// We define a custom struct for each query response -#[cw_serde] -pub struct GetObligationsResponse { - pub obligations: Vec<(String, Uint128)>, -} diff --git a/bisenzone-cw-mvp/src/state.rs b/bisenzone-cw-mvp/src/state.rs deleted file mode 100644 index 752d93b..0000000 --- a/bisenzone-cw-mvp/src/state.rs +++ /dev/null @@ -1,11 +0,0 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Uint128}; -use cw_storage_plus::{Item, Map}; - -#[cw_serde] -pub struct State { - pub owner: String, -} - -pub const STATE: Item = Item::new("state"); -pub const UTILIZATION: Map<(&Addr, &Addr), Uint128> = Map::new("utilization");