diff --git a/contracts/ibc2/schema/raw/query.json b/contracts/ibc2/schema/raw/query.json index 60e28f8dde..57f0db2569 100644 --- a/contracts/ibc2/schema/raw/query.json +++ b/contracts/ibc2/schema/raw/query.json @@ -14,6 +14,19 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "query_timeout_counter" + ], + "properties": { + "query_timeout_counter": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false } ] } diff --git a/contracts/ibc2/src/contract.rs b/contracts/ibc2/src/contract.rs index b935466d53..a403f9ad8d 100644 --- a/contracts/ibc2/src/contract.rs +++ b/contracts/ibc2/src/contract.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct State { ibc2_packet_receive_counter: u32, + ibc2_timeout_counter: u32, } #[cw_serde] @@ -16,6 +17,8 @@ pub struct State { pub enum QueryMsg { #[returns(State)] QueryState {}, + #[returns(u32)] + QueryTimeoutCounter {}, } const STATE_KEY: &[u8] = b"state"; @@ -43,6 +46,14 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { .ok_or_else(|| StdError::generic_err("State not found."))?; Ok(Binary::from(data)) } + QueryMsg::QueryTimeoutCounter {} => { + let data = deps + .storage + .get(STATE_KEY) + .ok_or_else(|| StdError::generic_err("State not found."))?; + let state: State = from_json(data)?; + Ok(to_json_vec(&state.ibc2_timeout_counter)?.into()) + } } } @@ -61,6 +72,29 @@ pub fn ibc2_packet_receive( STATE_KEY, &to_json_vec(&State { ibc2_packet_receive_counter: state.ibc2_packet_receive_counter + 1, + ibc2_timeout_counter: state.ibc2_timeout_counter, + })?, + ); + + Ok(IbcReceiveResponse::new([1, 2, 3])) +} + +#[entry_point] +pub fn ibc2_timeout( + deps: DepsMut, + _env: Env, + _msg: Ibc2PacketReceiveMsg, +) -> StdResult { + let data = deps + .storage + .get(STATE_KEY) + .ok_or_else(|| StdError::generic_err("State not found."))?; + let state: State = from_json(data)?; + deps.storage.set( + STATE_KEY, + &to_json_vec(&State { + ibc2_packet_receive_counter: state.ibc2_packet_receive_counter, + ibc2_timeout_counter: state.ibc2_timeout_counter + 1, })?, ); diff --git a/contracts/ibc2/tests/integration.rs b/contracts/ibc2/tests/integration.rs index 8b13789179..3b9b915e2a 100644 --- a/contracts/ibc2/tests/integration.rs +++ b/contracts/ibc2/tests/integration.rs @@ -1 +1,32 @@ +use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; +use cosmwasm_std::{ + from_binary, Empty, Ibc2PacketReceiveMsg, IbcReceiveResponse, Response, StdError, +}; +use crate::contract::{ibc2_packet_receive, ibc2_timeout, instantiate, query}; +use crate::contract::{QueryMsg, State}; + +#[test] +fn test_ibc2_timeout() { + let mut deps = mock_dependencies(); + let env = mock_env(); + let info = mock_info("sender", &[]); + + // Instantiate the contract + let msg = Empty {}; + let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); + assert_eq!(res, Response::new()); + + // Call ibc2_timeout multiple times and verify the timeout counter increments correctly + let msg = Ibc2PacketReceiveMsg::default(); + for i in 1..=3 { + let res: IbcReceiveResponse = + ibc2_timeout(deps.as_mut(), env.clone(), msg.clone()).unwrap(); + assert_eq!(res, IbcReceiveResponse::new([1, 2, 3])); + + let query_msg = QueryMsg::QueryTimeoutCounter {}; + let query_res = query(deps.as_ref(), env.clone(), query_msg).unwrap(); + let timeout_counter: u32 = from_binary(&query_res).unwrap(); + assert_eq!(timeout_counter, i); + } +}