-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add listener contract to listen to voice callbacks (#44)
- Loading branch information
Showing
10 changed files
with
315 additions
and
0 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.
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,3 @@ | ||
[alias] | ||
wasm = "build --release --lib --target wasm32-unknown-unknown" | ||
schema = "run --bin 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,29 @@ | ||
[package] | ||
name = "polytone-listener" | ||
authors = ["noah <[email protected]>"] | ||
edition = { workspace = true } | ||
license = { workspace = true } | ||
rust-version = { workspace = true } | ||
version = { workspace = true } | ||
|
||
[lib] | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[features] | ||
# for more explicit tests, cargo test --features=backtraces | ||
backtraces = ["cosmwasm-std/backtraces"] | ||
# disables #[entry_point] (i.e. instantiate/execute/query) export | ||
library = [] | ||
|
||
[dependencies] | ||
cosmwasm-schema = { workspace = true } | ||
cosmwasm-std = { workspace = true } | ||
cw-storage-plus = { workspace = true } | ||
cw2 = { workspace = true } | ||
thiserror = { workspace = true } | ||
polytone = { workspace = true } | ||
|
||
[dev-dependencies] | ||
cw-multi-test = { workspace = true } | ||
anyhow = { workspace = true } | ||
polytone-note = { 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,11 @@ | ||
use cosmwasm_schema::write_api; | ||
|
||
use polytone_listener::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; | ||
|
||
fn main() { | ||
write_api! { | ||
instantiate: InstantiateMsg, | ||
execute: ExecuteMsg, | ||
query: QueryMsg, | ||
} | ||
} |
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,71 @@ | ||
#[cfg(not(feature = "library"))] | ||
use cosmwasm_std::entry_point; | ||
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; | ||
use cw2::set_contract_version; | ||
|
||
use crate::error::ContractError; | ||
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ResultResponse}; | ||
use crate::state::{NOTE, RESULTS}; | ||
|
||
const CONTRACT_NAME: &str = "crates.io:polytone-listener"; | ||
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<Response, ContractError> { | ||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; | ||
|
||
let note = deps.api.addr_validate(&msg.note)?; | ||
NOTE.save(deps.storage, ¬e)?; | ||
|
||
Ok(Response::default() | ||
.add_attribute("method", "instantiate") | ||
.add_attribute("note", msg.note)) | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn execute( | ||
deps: DepsMut, | ||
_env: Env, | ||
info: MessageInfo, | ||
msg: ExecuteMsg, | ||
) -> Result<Response, ContractError> { | ||
match msg { | ||
ExecuteMsg::Callback(callback) => { | ||
// Only the note can execute the callback on this contract. | ||
if info.sender != NOTE.load(deps.storage)? { | ||
return Err(ContractError::Unauthorized {}); | ||
} | ||
|
||
RESULTS.save( | ||
deps.storage, | ||
( | ||
callback.initiator.to_string(), | ||
callback.initiator_msg.to_string(), | ||
), | ||
&callback, | ||
)?; | ||
Ok(Response::default() | ||
.add_attribute("method", "callback") | ||
.add_attribute("initiator", callback.initiator.to_string()) | ||
.add_attribute("initiator_msg", callback.initiator_msg.to_string())) | ||
} | ||
} | ||
} | ||
|
||
#[cfg_attr(not(feature = "library"), entry_point)] | ||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> { | ||
match msg { | ||
QueryMsg::Note {} => to_binary(&NOTE.load(deps.storage)?), | ||
QueryMsg::Result { | ||
initiator, | ||
initiator_msg, | ||
} => to_binary(&ResultResponse { | ||
callback: RESULTS.load(deps.storage, (initiator, initiator_msg))?, | ||
}), | ||
} | ||
} |
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_std::StdError; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug, PartialEq)] | ||
pub enum ContractError { | ||
#[error(transparent)] | ||
Std(#[from] StdError), | ||
|
||
#[error("Unauthorized")] | ||
Unauthorized {}, | ||
} |
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,7 @@ | ||
pub mod contract; | ||
pub mod error; | ||
pub mod msg; | ||
pub mod state; | ||
|
||
#[cfg(test)] | ||
mod tests; |
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,33 @@ | ||
use cosmwasm_schema::{cw_serde, QueryResponses}; | ||
use polytone::callbacks::CallbackMessage; | ||
|
||
#[cw_serde] | ||
pub struct InstantiateMsg { | ||
/// The polytone note contract that can call this contract. | ||
pub note: String, | ||
} | ||
|
||
#[cw_serde] | ||
pub enum ExecuteMsg { | ||
/// Stores the callback in state and makes it queryable. | ||
Callback(CallbackMessage), | ||
} | ||
|
||
#[cw_serde] | ||
#[derive(QueryResponses)] | ||
pub enum QueryMsg { | ||
/// Gets note that can call this contract. | ||
#[returns(String)] | ||
Note {}, | ||
/// Gets callback result. | ||
#[returns(ResultResponse)] | ||
Result { | ||
initiator: String, | ||
initiator_msg: String, | ||
}, | ||
} | ||
|
||
#[cw_serde] | ||
pub struct ResultResponse { | ||
pub callback: CallbackMessage, | ||
} |
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 @@ | ||
use cosmwasm_std::Addr; | ||
use cw_storage_plus::{Item, Map}; | ||
use polytone::callbacks::CallbackMessage; | ||
|
||
/// The note that can call this contract. | ||
pub(crate) const NOTE: Item<Addr> = Item::new("note"); | ||
|
||
/// (initiator, initiator_msg) -> callback | ||
pub(crate) const RESULTS: Map<(String, String), CallbackMessage> = Map::new("results"); |
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,126 @@ | ||
use cosmwasm_std::{to_binary, Addr, Empty, Uint64}; | ||
|
||
use cw_multi_test::{App, Contract, ContractWrapper, Executor}; | ||
use polytone::callbacks::{Callback, CallbackMessage}; | ||
|
||
use crate::{ | ||
error::ContractError, | ||
msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ResultResponse}, | ||
}; | ||
|
||
pub const CREATOR_ADDR: &str = "creator"; | ||
pub const INITIATOR_ADDR: &str = "initiator"; | ||
pub const INITIATOR_MSG: &str = "initiator_msg"; | ||
|
||
fn note_contract() -> Box<dyn Contract<Empty>> { | ||
let contract = ContractWrapper::new( | ||
polytone_note::contract::execute, | ||
polytone_note::contract::instantiate, | ||
polytone_note::contract::query, | ||
); | ||
Box::new(contract) | ||
} | ||
|
||
fn listener_contract() -> Box<dyn Contract<Empty>> { | ||
let contract = ContractWrapper::new( | ||
crate::contract::execute, | ||
crate::contract::instantiate, | ||
crate::contract::query, | ||
); | ||
Box::new(contract) | ||
} | ||
|
||
#[test] | ||
fn test() { | ||
let mut app = App::default(); | ||
|
||
let note_code = app.store_code(note_contract()); | ||
let listener_code = app.store_code(listener_contract()); | ||
|
||
let note1 = app | ||
.instantiate_contract( | ||
note_code, | ||
Addr::unchecked(CREATOR_ADDR), | ||
&polytone_note::msg::InstantiateMsg { | ||
pair: None, | ||
block_max_gas: Uint64::new(110_000), | ||
}, | ||
&[], | ||
"note1", | ||
Some(CREATOR_ADDR.to_string()), | ||
) | ||
.unwrap(); | ||
let note2 = app | ||
.instantiate_contract( | ||
note_code, | ||
Addr::unchecked(CREATOR_ADDR), | ||
&polytone_note::msg::InstantiateMsg { | ||
pair: None, | ||
block_max_gas: Uint64::new(110_000), | ||
}, | ||
&[], | ||
"note2", | ||
Some(CREATOR_ADDR.to_string()), | ||
) | ||
.unwrap(); | ||
|
||
let listener = app | ||
.instantiate_contract( | ||
listener_code, | ||
Addr::unchecked(CREATOR_ADDR), | ||
&InstantiateMsg { | ||
note: note1.to_string(), | ||
}, | ||
&[], | ||
"listener", | ||
Some(CREATOR_ADDR.to_string()), | ||
) | ||
.unwrap(); | ||
|
||
// Returns correct note. | ||
let queried_note: String = app | ||
.wrap() | ||
.query_wasm_smart(listener.clone(), &QueryMsg::Note {}) | ||
.unwrap(); | ||
assert_eq!(queried_note, note1.to_string()); | ||
|
||
// Allows note to execute callback. | ||
let callback = CallbackMessage { | ||
initiator: Addr::unchecked(INITIATOR_ADDR), | ||
initiator_msg: to_binary(INITIATOR_MSG).unwrap(), | ||
result: Callback::Execute(Result::Err("ERROR".to_string())), | ||
}; | ||
app.execute_contract( | ||
note1, | ||
listener.clone(), | ||
&ExecuteMsg::Callback(callback.clone()), | ||
&[], | ||
) | ||
.unwrap(); | ||
|
||
// Prevents different note from executing callback. | ||
let err: ContractError = app | ||
.execute_contract( | ||
note2, | ||
listener.clone(), | ||
&ExecuteMsg::Callback(callback.clone()), | ||
&[], | ||
) | ||
.unwrap_err() | ||
.downcast() | ||
.unwrap(); | ||
assert_eq!(err, ContractError::Unauthorized {}); | ||
|
||
// Returns the correct callback. | ||
let response: ResultResponse = app | ||
.wrap() | ||
.query_wasm_smart( | ||
listener, | ||
&QueryMsg::Result { | ||
initiator: INITIATOR_ADDR.to_string(), | ||
initiator_msg: to_binary(INITIATOR_MSG).unwrap().to_string(), | ||
}, | ||
) | ||
.unwrap(); | ||
assert_eq!(response.callback, callback); | ||
} |