Skip to content

Commit

Permalink
Simplify, implement receiver contract example
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeHartnell committed Aug 6, 2022
1 parent b4e7d14 commit 737233a
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 149 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions contracts/cw-ibc-queries/examples/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use std::fs::create_dir_all;

use cosmwasm_schema::{export_schema, remove_schemas, schema_for};

use cw_ibc_queries::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use cw_ibc_queries::state::IbcQueryResultResponse;
use cw_ibc_queries::msg::{ExecuteMsg, InstantiateMsg};

fn main() {
let mut out_dir = current_dir().unwrap();
Expand All @@ -13,7 +12,5 @@ fn main() {
remove_schemas(&out_dir).unwrap();

export_schema(&schema_for!(ExecuteMsg), &out_dir);
export_schema(&schema_for!(IbcQueryResultResponse), &out_dir);
export_schema(&schema_for!(InstantiateMsg), &out_dir);
export_schema(&schema_for!(QueryMsg), &out_dir);
}
31 changes: 8 additions & 23 deletions contracts/cw-ibc-queries/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, QueryRequest,
QueryResponse, Response, StdResult,
entry_point, to_binary, DepsMut, Empty, Env, IbcMsg, MessageInfo, QueryRequest, Response,
StdResult,
};
use cw_ibc_query::PacketMsg;

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{IbcQueryResultResponse, LATEST_QUERIES};
use crate::msg::{ExecuteMsg, InstantiateMsg};

// TODO: make configurable?
/// packets live one hour
Expand Down Expand Up @@ -41,13 +40,16 @@ pub fn execute(
}

pub fn execute_ibc_query(
_deps: DepsMut,
deps: DepsMut,
env: Env,
_info: MessageInfo,
channel_id: String,
msgs: Vec<QueryRequest<Empty>>,
callback: Option<String>,
callback: String,
) -> Result<Response, ContractError> {
// validate callback address
deps.api.addr_validate(&callback)?;

// construct a packet to send
let packet = PacketMsg::IbcQuery { msgs, callback };
let msg = IbcMsg::SendPacket {
Expand All @@ -62,23 +64,6 @@ pub fn execute_ibc_query(
Ok(res)
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
match msg {
QueryMsg::LatestQueryResult { channel_id } => {
to_binary(&query_latest_ibc_query_result(deps, channel_id)?)
}
}
}

fn query_latest_ibc_query_result(
deps: Deps,
channel_id: String,
) -> StdResult<IbcQueryResultResponse> {
let results = LATEST_QUERIES.load(deps.storage, &channel_id)?;
Ok(results.into())
}

#[cfg(test)]
mod tests {
use crate::ibc::{ibc_channel_connect, ibc_channel_open};
Expand Down
55 changes: 20 additions & 35 deletions contracts/cw-ibc-queries/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use cosmwasm_std::{
IbcPacketTimeoutMsg, IbcReceiveResponse, QueryRequest, StdResult, SystemResult, WasmMsg,
};
use cw_ibc_query::{
check_order, check_version, IbcQueryResponse, PacketMsg, ReceiveIbcResponseMsg, StdAck,
IBC_APP_VERSION,
check_order, check_version, IbcQueryResponse, PacketMsg, ReceiveIbcResponseMsg,
ReceiverExecuteMsg, StdAck, IBC_APP_VERSION,
};

use crate::error::ContractError;
use crate::state::{IbcQueryResultResponse, LATEST_QUERIES, PENDING};
use crate::state::PENDING;

// TODO: make configurable?
/// packets live one hour
Expand Down Expand Up @@ -114,13 +114,11 @@ pub fn ibc_packet_ack(
env: Env,
msg: IbcPacketAckMsg,
) -> Result<IbcBasicResponse, ContractError> {
// which local channel was this packet send from
let caller = msg.original_packet.src.channel_id.clone();
// we need to parse the ack based on our request
let original_packet: PacketMsg = from_slice(&msg.original_packet.data)?;

match original_packet {
PacketMsg::IbcQuery { callback, .. } => acknowledge_query(deps, env, caller, callback, msg),
PacketMsg::IbcQuery { callback, .. } => acknowledge_query(deps, env, callback, msg),
}
}

Expand All @@ -134,36 +132,23 @@ pub fn ibc_packet_timeout(
}

fn acknowledge_query(
deps: DepsMut,
env: Env,
channel_id: String,
callback: Option<String>,
_deps: DepsMut,
_env: Env,
callback: String,
msg: IbcPacketAckMsg,
) -> Result<IbcBasicResponse, ContractError> {
// store IBC response for later querying from the smart contract??
LATEST_QUERIES.save(
deps.storage,
&channel_id,
&IbcQueryResultResponse {
last_update_time: env.block.time,
response: msg.clone(),
},
)?;
match callback {
Some(callback) => {
// Send IBC packet ack message to another contract
let msg = WasmMsg::Execute {
contract_addr: callback.clone(),
msg: to_binary(&ReceiveIbcResponseMsg { msg })?,
funds: vec![],
};
Ok(IbcBasicResponse::new()
.add_attribute("action", "acknowledge_ibc_query")
.add_attribute("callback_address", callback)
.add_message(msg))
}
None => Ok(IbcBasicResponse::new().add_attribute("action", "acknowledge_ibc_query")),
}
// Send IBC packet ack message to another contract
let msg = WasmMsg::Execute {
contract_addr: callback.clone(),
msg: to_binary(&ReceiverExecuteMsg::ReceiveIbcResponse(
ReceiveIbcResponseMsg { msg },
))?,
funds: vec![],
};
Ok(IbcBasicResponse::new()
.add_attribute("action", "acknowledge_ibc_query")
.add_attribute("callback_address", callback)
.add_message(msg))
}

#[cfg(test)]
Expand Down Expand Up @@ -199,7 +184,7 @@ mod tests {

let ack = IbcAcknowledgement::new([]);
let ibc_res = mock_ibc_packet_ack(CHANNEL, &InstantiateMsg {}, ack).unwrap();
let res = acknowledge_query(deps.as_mut(), env, CHANNEL.to_string(), None, ibc_res);
let res = acknowledge_query(deps.as_mut(), env, String::from("test"), ibc_res);
assert!(res.is_ok());
}
}
14 changes: 3 additions & 11 deletions contracts/cw-ibc-queries/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,9 @@ pub struct InstantiateMsg {}
pub enum ExecuteMsg {
IbcQuery {
channel_id: String,
// Queries to be executed
msgs: Vec<QueryRequest<Empty>>,
// Optional callback
callback: Option<String>,
// Callback contract address that implements ReceiveIbcResponseMsg
callback: String,
},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
// TODO need a better way of doing this...
// How many query results do we want to store? Zero? Callbacks only?
// Get latest query
LatestQueryResult { channel_id: String },
}
14 changes: 1 addition & 13 deletions contracts/cw-ibc-queries/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::{IbcPacketAckMsg, Timestamp};
use cw_storage_plus::{Item, Map};
use cw_storage_plus::Item;

pub const PENDING: Item<String> = Item::new("pending");

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct IbcQueryResultResponse {
/// last block balance was updated (0 is never)
pub last_update_time: Timestamp,
pub response: IbcPacketAckMsg,
}
pub const LATEST_QUERIES: Map<&str, IbcQueryResultResponse> = Map::new("queries");
5 changes: 5 additions & 0 deletions contracts/cw-ibc-query-receiver/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
wasm-debug = "build --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --example schema"
41 changes: 41 additions & 0 deletions contracts/cw-ibc-query-receiver/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "cw-ibc-query-receiver"
version = "0.1.0"
authors = ["Ethan Frey <[email protected]>", "Jake Hartnell <[email protected]>"]
edition = "2021"
publish = false
license = "Apache-2.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true

[features]
# for quicker tests, cargo test --lib
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]

[dependencies]
cw-ibc-query = { path = "../../packages/cw-ibc-query"}
cosmwasm-std = { version = "1.0.0", features = ["iterator", "ibc3"] }
cw-storage-plus = { version = "0.13.4" }
cw-utils = { version = "0.13.4" }
cw1-whitelist = { version = "0.13.4", features = ["library"]}
schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }

[dev-dependencies]
cosmwasm-schema = { version = "1.0.0" }
7 changes: 7 additions & 0 deletions contracts/cw-ibc-query-receiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# CosmWasm IBC Query Receiver

An example contract illustrating how to recieve and store the result of an IBC query using `ReceiveIbcResponseMsg`.

## Workflow

Requires `cw-ibc-queries` contract to be deployed on the same chain from which it will recieve query results.
21 changes: 21 additions & 0 deletions contracts/cw-ibc-query-receiver/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::env::current_dir;
use std::fs::create_dir_all;

use cosmwasm_schema::{export_schema, remove_schemas, schema_for};

use cw_ibc_query_receiver::{
msg::{ExecuteMsg, InstantiateMsg, QueryMsg},
state::IbcQueryResultResponse,
};

fn main() {
let mut out_dir = current_dir().unwrap();
out_dir.push("schema");
create_dir_all(&out_dir).unwrap();
remove_schemas(&out_dir).unwrap();

export_schema(&schema_for!(ExecuteMsg), &out_dir);
export_schema(&schema_for!(InstantiateMsg), &out_dir);
export_schema(&schema_for!(QueryMsg), &out_dir);
export_schema(&schema_for!(IbcQueryResultResponse), &out_dir);
}
72 changes: 72 additions & 0 deletions contracts/cw-ibc-query-receiver/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Env, IbcPacketAckMsg, MessageInfo, QueryResponse,
Response, StdResult,
};
use cw_ibc_query::ReceiveIbcResponseMsg;

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{IbcQueryResultResponse, LATEST_QUERIES};

#[entry_point]
pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> StdResult<Response> {
// Do nothing for now
Ok(Response::new())
}

#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
cw_utils::nonpayable(&info)?;
match msg {
ExecuteMsg::ReceiveIbcResponse(ReceiveIbcResponseMsg { msg }) => {
execute_receive(deps, env, info, msg)
}
}
}

pub fn execute_receive(
deps: DepsMut,
env: Env,
_info: MessageInfo,
msg: IbcPacketAckMsg,
) -> Result<Response, ContractError> {
// which local channel was this packet send from
let channel_id = msg.original_packet.src.channel_id.clone();
// store IBC response for later querying from the smart contract??
LATEST_QUERIES.save(
deps.storage,
&channel_id,
&IbcQueryResultResponse {
last_update_time: env.block.time,
response: msg,
},
)?;
Ok(Response::default())
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
match msg {
QueryMsg::LatestQueryResult { channel_id } => {
to_binary(&query_latest_ibc_query_result(deps, channel_id)?)
}
}
}

fn query_latest_ibc_query_result(
deps: Deps,
channel_id: String,
) -> StdResult<IbcQueryResultResponse> {
let results = LATEST_QUERIES.load(deps.storage, &channel_id)?;
Ok(results)
}
Loading

0 comments on commit 737233a

Please sign in to comment.