diff --git a/Cargo.lock b/Cargo.lock index 5ec13e5..e07b7f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,6 +1498,23 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hello-world-counter" +version = "0.1.0" +dependencies = [ + "anyhow", + "cosmwasm-schema 2.0.2", + "cosmwasm-std 2.0.2", + "cw-storage-plus 2.0.0", + "cw2 2.0.0", + "easy-addr", + "nibiru-std", + "schemars", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hex" version = "0.4.3" diff --git a/artifacts/broker_bank.wasm b/artifacts/broker_bank.wasm index 405c9fe..f782f96 100644 Binary files a/artifacts/broker_bank.wasm and b/artifacts/broker_bank.wasm differ diff --git a/artifacts/broker_staking.wasm b/artifacts/broker_staking.wasm index 1e9475d..c03df2e 100644 Binary files a/artifacts/broker_staking.wasm and b/artifacts/broker_staking.wasm differ diff --git a/artifacts/checksums.txt b/artifacts/checksums.txt index c999a17..865dfa7 100644 --- a/artifacts/checksums.txt +++ b/artifacts/checksums.txt @@ -1,13 +1,15 @@ -e3d3422db32e4e6ebe0247a22f6be733ccf6b637bfeb4ff8ffcd8122a68d7853 broker_bank.wasm -40288f4cda1e48740269ab6425ca234b9b99419c165aaf1d410fa37c40843e49 broker_staking.wasm +7b674c043971df4c0a362ab8f6142680afeae32f4be88fc6a5d1e8c0e7dab680 broker_bank.wasm +b544cf24505320138bcd467ab73e8c2a206fe926113e61cf2caeb604d2e25b25 broker_staking.wasm 382c05baf544f2886de849933ecf59e8bc3bcdcdd552d5a63537bd6d63f2ecf1 controller.wasm -ed4a89ae4669b22863fcabd18e3bd7e40d039899f863a07eb0449eed059a898e core_token_vesting_v2.wasm -b56a880d4c67d9f353f549b502256f73159f89b50aa6dae683948e117efa4792 cw3_flex_multisig.wasm -1ecff403bbf3b5fcedccb5de76a0ef5f1fdbcc5f60890e3388f5425584899f0b incentives.wasm -dc89ed88f1c69bf63fc284492b7bf6935e3a85da2945067d70f71f08c01df60d lockup.wasm -222eac4e17c7ddffbecde0b196bc06ed1e458b8578ab25ed200a6fd7db4e5eda nibi_stargate.wasm -ef5b4de76526713e3531c3b9bbc4620b5d61599c4a0e8605365ebb0f1d7ee2ac nibi_stargate_perp.wasm -0074489ff40c8ecbd766f7140b32d288dcaf7302ba630d452f79e7d292ea57ef nusd_valuator.wasm -955592d08017aa41f3c9ba3883153d6de024e8c7a3a79aa3b664a241ec1e7a19 pricefeed.wasm -89e3236c932a73575bf39da532bcb93f8e4a5f4a3a7f3836e43f8970993eb809 shifter.wasm -8d982ca2d679ea8d44f825fe91a3d4e0cb92150b12e4684497eee9e76991d247 token_vesting.wasm +77efd174302c8d4622c1ce855b652aeefd3695064caaba90582bac89213a3187 core_token_vesting_v2.wasm +6b447bd36b84ec14c602c92ff5a2efbec6b9970ea984ee43e4829570c0dc75e3 cw3_fixed_multisig.wasm +8999a6e88c168045833de9a5f77529856ece75a14556aedd3a79c7eda60a3f6a cw3_flex_multisig.wasm +aede52ea6c6e1df652d77da770111e12a606e7718ac54d07a792c509bbb1081e hello_world_counter.wasm +55aef2add88da435dd5bf11aa29eb51edab909a03515e701f771b2869ca43fe1 incentives.wasm +cbd8a9774b2da7d9aceeec555bc44cd20252a05a0ad50b4968a5041df06df8b3 lockup.wasm +32ccda53511b00dffa0bd5b95ef11165a03c955545aac6d2ecc21830e9f610b2 nibi_stargate.wasm +74fc402b1b31336838fdc814f89f17a7ffe4b019422097b38d92e92fd61d6c64 nibi_stargate_perp.wasm +6de11082ba049deaf4702329195f065e555f51a7fbb7d102443e94e75beee1da nusd_valuator.wasm +83d4b903c7aed4f19f8b762ef6bccf286de68ac71fd6e0149fb46274afda7379 pricefeed.wasm +3c9725f2171571f17f921da0bbb60606838d2ad1861f2790d820f79d819036c5 shifter.wasm +584685070441058ff7185e9143113703e09a53852b29795aaaf2e9902eab1ceb token_vesting.wasm diff --git a/artifacts/core_token_vesting_v2.wasm b/artifacts/core_token_vesting_v2.wasm index 31f078d..1ae8436 100644 Binary files a/artifacts/core_token_vesting_v2.wasm and b/artifacts/core_token_vesting_v2.wasm differ diff --git a/artifacts/cw3_fixed_multisig.wasm b/artifacts/cw3_fixed_multisig.wasm new file mode 100644 index 0000000..53dea36 Binary files /dev/null and b/artifacts/cw3_fixed_multisig.wasm differ diff --git a/artifacts/cw3_flex_multisig.wasm b/artifacts/cw3_flex_multisig.wasm index 08fbc57..51e1444 100644 Binary files a/artifacts/cw3_flex_multisig.wasm and b/artifacts/cw3_flex_multisig.wasm differ diff --git a/artifacts/hello_world_counter.wasm b/artifacts/hello_world_counter.wasm new file mode 100644 index 0000000..9a532ca Binary files /dev/null and b/artifacts/hello_world_counter.wasm differ diff --git a/artifacts/incentives.wasm b/artifacts/incentives.wasm index 2bbfd30..0b21f53 100644 Binary files a/artifacts/incentives.wasm and b/artifacts/incentives.wasm differ diff --git a/artifacts/lockup.wasm b/artifacts/lockup.wasm index 9c1c8d3..87fea86 100644 Binary files a/artifacts/lockup.wasm and b/artifacts/lockup.wasm differ diff --git a/artifacts/nibi_stargate.wasm b/artifacts/nibi_stargate.wasm index fb0d82c..c308272 100644 Binary files a/artifacts/nibi_stargate.wasm and b/artifacts/nibi_stargate.wasm differ diff --git a/artifacts/nibi_stargate_perp.wasm b/artifacts/nibi_stargate_perp.wasm index 980b239..e9576b2 100644 Binary files a/artifacts/nibi_stargate_perp.wasm and b/artifacts/nibi_stargate_perp.wasm differ diff --git a/artifacts/nusd_valuator.wasm b/artifacts/nusd_valuator.wasm index 77cb624..0ee2fb8 100644 Binary files a/artifacts/nusd_valuator.wasm and b/artifacts/nusd_valuator.wasm differ diff --git a/artifacts/pricefeed.wasm b/artifacts/pricefeed.wasm index 67ed1c2..02a2bc7 100644 Binary files a/artifacts/pricefeed.wasm and b/artifacts/pricefeed.wasm differ diff --git a/artifacts/shifter.wasm b/artifacts/shifter.wasm index 63de3a9..89b95b2 100644 Binary files a/artifacts/shifter.wasm and b/artifacts/shifter.wasm differ diff --git a/artifacts/token_vesting.wasm b/artifacts/token_vesting.wasm index 38f8c11..e59f0e4 100644 Binary files a/artifacts/token_vesting.wasm and b/artifacts/token_vesting.wasm differ diff --git a/contracts/00-hello-world-counter/.cargo/config.toml b/contracts/00-hello-world-counter/.cargo/config.toml new file mode 100644 index 0000000..051a969 --- /dev/null +++ b/contracts/00-hello-world-counter/.cargo/config.toml @@ -0,0 +1,9 @@ +[alias] +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" +schema = "run --bin schema" + +# OLDER: +# wasm = "build --release --target wasm32-unknown-unknown" +# wasm-debug = "build --target wasm32-unknown-unknown" +# schema = "run --example schema" \ No newline at end of file diff --git a/contracts/00-hello-world-counter/Cargo.toml b/contracts/00-hello-world-counter/Cargo.toml new file mode 100644 index 0000000..ef9e467 --- /dev/null +++ b/contracts/00-hello-world-counter/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "hello-world-counter" +version = "0.1.0" +edition = "2021" +homepage = { workspace = true } +repository = { workspace = true } + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# features.library: Use the library feature to disable all +# instantiate/execute/query exports. This is necessary use this as a dependency +# for another smart contract crate. +library = [] + +[dependencies] +cosmwasm-std = { workspace = true } +cosmwasm-schema = { workspace = true } +cw-storage-plus = { workspace = true } +schemars = { workspace = true } +serde = { workspace = true } +thiserror = { workspace = true } +nibiru-std = { workspace = true } +cw2 = { workspace = true } +serde_json = { workspace = true } +anyhow = { workspace = true } + +[dev-dependencies] +easy-addr = { workspace = true } \ No newline at end of file diff --git a/contracts/00-hello-world-counter/README.md b/contracts/00-hello-world-counter/README.md new file mode 100644 index 0000000..c1a9a18 --- /dev/null +++ b/contracts/00-hello-world-counter/README.md @@ -0,0 +1,4 @@ +# contracts/00-hello-world-counter + +The classic "counter" smart contract. It serves as a hello-world example on +how to implement execute messages and queries in Wasm. \ No newline at end of file diff --git a/contracts/00-hello-world-counter/src/contract.rs b/contracts/00-hello-world-counter/src/contract.rs new file mode 100644 index 0000000..496e197 --- /dev/null +++ b/contracts/00-hello-world-counter/src/contract.rs @@ -0,0 +1,185 @@ +use cosmwasm_std::{ + to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, +}; +use cw2::set_contract_version; + +use crate::{ + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + state::{State, STATE}, +}; + +type ContractError = anyhow::Error; + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + set_contract_version( + deps.storage, + format!("nibiru-wasm/contracts/{CONTRACT_NAME}"), + CONTRACT_VERSION, + )?; + + STATE.save( + deps.storage, + &State { + count: msg.count, + owner: info.sender.clone(), + }, + )?; + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn execute( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Increment {} => { + STATE.update( + deps.storage, + |mut state| -> Result<_, anyhow::Error> { + state.count += 1; + Ok(state) + }, + )?; + Ok(Response::default()) + } + ExecuteMsg::Reset { count } => { + STATE.update( + deps.storage, + |mut state| -> Result<_, anyhow::Error> { + let owner = state.owner.clone(); + if info.sender != owner { + return Err(anyhow::anyhow!( + "Unauthorized: only the owner ({owner}) can use reset", + )); + } + state.count = count; + Ok(state) + }, + )?; + Ok(Response::default()) + } + } +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: QueryMsg, +) -> Result { + match msg { + QueryMsg::Count {} => { + let state = STATE.load(deps.storage)?; + Ok(to_json_binary(&state)?) + } + } +} + +pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); +pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg(test)] +pub mod tests { + + use easy_addr; + use nibiru_std::errors::TestResult; + + use crate::{ + contract::{execute, query}, + msg::{ExecuteMsg, QueryMsg}, + state::State, + tutil::{mock_info_for_sender, setup_contract, TEST_OWNER}, + }; + + struct TestCaseExec<'a> { + exec_msg: ExecuteMsg, + sender: &'a str, + err: Option<&'a str>, + start_count: i64, + want_count_after: i64, + } + + /// Test that all owner-gated execute calls fail when the tx sender is not + /// the smart contract owner. + #[test] + pub fn test_exec() -> TestResult { + let not_owner = easy_addr::addr!("not-owner"); + + let test_cases: Vec = vec![ + TestCaseExec { + sender: not_owner, + exec_msg: ExecuteMsg::Increment {}, + err: None, + start_count: 0, + want_count_after: 1, + }, + TestCaseExec { + sender: not_owner, + exec_msg: ExecuteMsg::Increment {}, + err: None, + start_count: -70, + want_count_after: -69, + }, + TestCaseExec { + sender: TEST_OWNER, + exec_msg: ExecuteMsg::Reset { count: 25 }, + err: None, + start_count: std::i64::MAX, + want_count_after: 25, + }, + TestCaseExec { + sender: TEST_OWNER, + exec_msg: ExecuteMsg::Reset { count: -25 }, + err: None, + start_count: 0, + want_count_after: -25, + }, + TestCaseExec { + sender: not_owner, + exec_msg: ExecuteMsg::Reset { count: 25 }, + err: Some("Unauthorized: only the owner"), + start_count: 0, // unused + want_count_after: 0, // unused + }, + ]; + + for tc in &test_cases { + // instantiate smart contract from the owner + let (mut deps, env, _info) = setup_contract(tc.start_count)?; + + // send the exec msg and it should fail. + let info = mock_info_for_sender(tc.sender); + let res = + execute(deps.as_mut(), env.clone(), info, tc.exec_msg.clone()); + + if let Some(want_err) = tc.err { + let err = res.expect_err("err should be defined"); + let is_contained = err.to_string().contains(want_err); + assert!(is_contained, "got error {}", err); + continue; + } + + let res = res?; + assert_eq!(res.messages.len(), 0); + + let query_req = QueryMsg::Count {}; + let binary = query(deps.as_ref(), env, query_req)?; + let query_resp: State = cosmwasm_std::from_json(binary)?; + + let state = query_resp; + let got_count_after = state.count; + assert_eq!(got_count_after, tc.want_count_after); + assert_eq!(state.owner.as_str(), TEST_OWNER); + } + Ok(()) + } +} diff --git a/contracts/00-hello-world-counter/src/lib.rs b/contracts/00-hello-world-counter/src/lib.rs new file mode 100644 index 0000000..86d02b4 --- /dev/null +++ b/contracts/00-hello-world-counter/src/lib.rs @@ -0,0 +1,5 @@ +pub mod contract; +pub mod msg; +pub mod state; +#[cfg(test)] +pub mod tutil; diff --git a/contracts/00-hello-world-counter/src/msg.rs b/contracts/00-hello-world-counter/src/msg.rs new file mode 100644 index 0000000..4f423ff --- /dev/null +++ b/contracts/00-hello-world-counter/src/msg.rs @@ -0,0 +1,21 @@ +use crate::state; +use cosmwasm_schema::cw_serde; + +#[cw_serde] +pub enum ExecuteMsg { + Increment {}, // Increase count by 1 + Reset { count: i64 }, // Reset to any i64 value +} + +#[cw_serde] +#[derive(cosmwasm_schema::QueryResponses)] +pub enum QueryMsg { + // Count returns the JSON-encoded state + #[returns(state::State)] + Count {}, +} + +#[cw_serde] +pub struct InstantiateMsg { + pub count: i64, +} diff --git a/contracts/00-hello-world-counter/src/state.rs b/contracts/00-hello-world-counter/src/state.rs new file mode 100644 index 0000000..7603437 --- /dev/null +++ b/contracts/00-hello-world-counter/src/state.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +pub const STATE: Item = Item::new("state"); + +#[cw_serde] +pub struct State { + pub count: i64, + pub owner: Addr, +} diff --git a/contracts/00-hello-world-counter/src/tutil.rs b/contracts/00-hello-world-counter/src/tutil.rs new file mode 100644 index 0000000..7bcc630 --- /dev/null +++ b/contracts/00-hello-world-counter/src/tutil.rs @@ -0,0 +1,47 @@ +//! tutil.rs: Test helpers for the contract +#![cfg(not(target_arch = "wasm32"))] + +use cosmwasm_std::{Env, MessageInfo, OwnedDeps}; + +#[cfg(not(target_arch = "wasm32"))] +use cosmwasm_std::testing::{ + mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage, +}; + +use crate::{contract::instantiate, msg::InstantiateMsg}; + +pub const TEST_OWNER: &str = easy_addr::addr!("owner"); + +pub fn setup_contract( + count: i64, +) -> anyhow::Result<( + OwnedDeps, + Env, + MessageInfo, +)> { + let mut deps = mock_dependencies(); + let env = mock_env(); + let info = mock_info(TEST_OWNER, &[]); + let msg = InstantiateMsg { count }; + let res = instantiate(deps.as_mut(), env.clone(), info.clone(), msg)?; + assert_eq!(0, res.messages.len()); + Ok((deps, env, info)) +} + +pub fn setup_contract_defaults() -> anyhow::Result<( + OwnedDeps, + Env, + MessageInfo, +)> { + setup_contract(0) +} + +pub fn mock_info_for_sender(sender: &str) -> MessageInfo { + mock_info(sender, &[]) +} + +pub fn mock_env_height(height: u64) -> Env { + let mut env = mock_env(); + env.block.height = height; + env +} diff --git a/contracts/broker-bank/Cargo.toml b/contracts/broker-bank/Cargo.toml index 053d1e8..ccfdf1b 100644 --- a/contracts/broker-bank/Cargo.toml +++ b/contracts/broker-bank/Cargo.toml @@ -3,7 +3,7 @@ name = "broker-bank" version = "0.1.0" edition = "2021" homepage = { workspace = true } -repository = "https://github.com/NibiruChain/nibiru-wasm" +repository = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib]