-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#155 - feat(00-hello-world-counter): implement the classic, counter c…
…ontract for testing feat(00-hello-world-counter): implement the classic, counter contract for testing
- Loading branch information
Showing
25 changed files
with
345 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Response, ContractError> { | ||
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<Response, ContractError> { | ||
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<Binary, ContractError> { | ||
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<TestCaseExec> = 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(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pub mod contract; | ||
pub mod msg; | ||
pub mod state; | ||
#[cfg(test)] | ||
pub mod tutil; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
use cosmwasm_schema::cw_serde; | ||
use cosmwasm_std::Addr; | ||
use cw_storage_plus::Item; | ||
|
||
pub const STATE: Item<State> = Item::new("state"); | ||
|
||
#[cw_serde] | ||
pub struct State { | ||
pub count: i64, | ||
pub owner: Addr, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<MockStorage, MockApi, MockQuerier>, | ||
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<MockStorage, MockApi, MockQuerier>, | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters