From 590a7368ece1aae0397b057d5726e63f4813e952 Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 25 Oct 2023 17:37:17 +0400 Subject: [PATCH 1/4] fix: explicitly expect one message in timelock execute_execute_proposal --- .../src/contract.rs | 24 ++++++++++++------- .../cwd-subdao-timelock-single/src/error.rs | 5 +++- .../src/testing/tests.rs | 20 +++++++++++++++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs index 58b083b3..eed8d574 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs @@ -176,17 +176,25 @@ pub fn execute_execute_proposal( .querier .query_wasm_smart(proposal_module, &ProposalQueryMsg::Config {})?; + // expect exactly one `ExecuteMsg::ExecuteTimelockedMsgs` message + if proposal.msgs.len() != 1 { + return Err( + ContractError::CanOnlyExecuteProposalsWithExactlyOneMessage { + len: proposal.msgs.len(), + }, + ); + } + let msg: &CosmosMsg = proposal.msgs.first().ok_or( + ContractError::CanOnlyExecuteProposalsWithExactlyOneMessage { + len: proposal.msgs.len(), + }, + )?; + match proposal_config.close_proposal_on_execution_failure { true => { - let msgs: Vec> = proposal - .msgs - .iter() - .map(|msg| SubMsg::reply_on_error(msg.clone(), proposal_id)) - .collect(); - - Response::default().add_submessages(msgs) + Response::default().add_submessage(SubMsg::reply_on_error(msg.clone(), proposal_id)) } - false => Response::default().add_messages(proposal.msgs), + false => Response::default().add_message(msg.clone()), } }; diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs index 7d508820..f4e894a8 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs @@ -18,9 +18,12 @@ pub enum ContractError { #[error("Wrong proposal status ({status})")] WrongStatus { status: String }, - #[error("no such proposal ({id})")] + #[error("No such proposal ({id})")] NoSuchProposal { id: u64 }, #[error("Can not create overrule proposal for main DAO")] CantCreateOverrule {}, + + #[error("Can only execute proposals with exactly one message. Got {len} messages.")] + CanOnlyExecuteProposalsWithExactlyOneMessage { len: usize }, } diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs index c4e2191e..0aef757c 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs @@ -227,6 +227,24 @@ fn test_execute_proposal() { let updated_prop = PROPOSALS.load(deps.as_mut().storage, 10).unwrap(); assert_eq!(ProposalStatus::Executed, updated_prop.status); + // check that execution fails when there not exactly one message in proposal + let proposal = SingleChoiceProposal { + id: 10, + msgs: vec![ + NeutronMsg::remove_interchain_query(1).into(), + NeutronMsg::remove_interchain_query(2).into(), + ], + status: ProposalStatus::Timelocked, + }; + PROPOSALS + .save(deps.as_mut().storage, proposal.id, &proposal) + .unwrap(); + let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); + assert_eq!( + "Can only execute proposals with exactly one message. Got 2 messages.", + res.unwrap_err().to_string() + ); + // check proposal execution close_proposal_on_execution_failure = false deps.querier.set_close_proposal_on_execution_failure(false); let proposal2 = SingleChoiceProposal { @@ -542,7 +560,7 @@ fn test_reply() { result: SubMsgResult::Err("error".to_string()), }; let err = reply(deps.as_mut(), mock_env(), msg.clone()).unwrap_err(); - assert_eq!("no such proposal (10)", err.to_string()); + assert_eq!("No such proposal (10)", err.to_string()); let prop = SingleChoiceProposal { id: 10, From 42e837bdb4433fed5489748d3212bd23b71735b6 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 26 Oct 2023 16:02:22 +0400 Subject: [PATCH 2/4] added check for type of message in timelock --- .../src/contract.rs | 58 +++++++++++++------ .../cwd-subdao-timelock-single/src/error.rs | 7 ++- .../src/testing/tests.rs | 57 ++++++++++++++++-- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs index eed8d574..9b8f0715 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, - StdResult, SubMsg, WasmMsg, + from_binary, to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Reply, + Response, StdError, StdResult, SubMsg, WasmMsg, }; use cw2::set_contract_version; use cw_storage_plus::Bound; @@ -16,6 +16,7 @@ use neutron_dao_pre_propose_overrule::msg::{ QueryExt as OverruleQueryExt, QueryMsg as OverruleQueryMsg, }; use neutron_sdk::bindings::msg::NeutronMsg; +use neutron_subdao_core::msg::ExecuteMsg as CoreExecuteMsg; use neutron_subdao_core::msg::QueryMsg as SubdaoQuery; use neutron_subdao_pre_propose_single::msg::QueryMsg as PreProposeQuery; use neutron_subdao_proposal_single::msg::QueryMsg as ProposalQueryMsg; @@ -176,25 +177,12 @@ pub fn execute_execute_proposal( .querier .query_wasm_smart(proposal_module, &ProposalQueryMsg::Config {})?; - // expect exactly one `ExecuteMsg::ExecuteTimelockedMsgs` message - if proposal.msgs.len() != 1 { - return Err( - ContractError::CanOnlyExecuteProposalsWithExactlyOneMessage { - len: proposal.msgs.len(), - }, - ); - } - let msg: &CosmosMsg = proposal.msgs.first().ok_or( - ContractError::CanOnlyExecuteProposalsWithExactlyOneMessage { - len: proposal.msgs.len(), - }, - )?; + // We expect only one specific message `ExecuteMsg::ExecuteTimelockedMsgs` inside + let msg = unpack_execute_msg(proposal.msgs)?; match proposal_config.close_proposal_on_execution_failure { - true => { - Response::default().add_submessage(SubMsg::reply_on_error(msg.clone(), proposal_id)) - } - false => Response::default().add_message(msg.clone()), + true => Response::default().add_submessage(SubMsg::reply_on_error(msg, proposal_id)), + false => Response::default().add_message(msg), } }; @@ -206,6 +194,38 @@ pub fn execute_execute_proposal( .add_attribute("proposal_id", proposal_id.to_string())) } +fn unpack_execute_msg( + msgs: Vec>, +) -> Result, ContractError> { + let msgs_len = msgs.len(); + // Expect exactly one message + if msgs_len != 1 { + return Err(ContractError::CanOnlyExecuteOneMsg { len: msgs_len }); + } + let msg: CosmosMsg = msgs + .into_iter() + .next() + .ok_or(ContractError::CanOnlyExecuteOneMsg { len: msgs_len })?; + + // Expect only `ExecuteMsg::ExecuteTimelockedMsgs` + match &msg { + &CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: _, + funds: _, + ref msg, + }) => { + let unwrap_res: StdResult = from_binary(msg); + match unwrap_res { + Ok(CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: _ }) => {} + _ => return Err(ContractError::CanOnlyExecuteExecuteTimelockedMsgs {}), + } + } + _ => return Err(ContractError::CanOnlyExecuteExecuteTimelockedMsgs {}), + } + + Ok(msg) +} + pub fn execute_overrule_proposal( deps: DepsMut, info: MessageInfo, diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs index f4e894a8..efcac1f2 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/error.rs @@ -24,6 +24,9 @@ pub enum ContractError { #[error("Can not create overrule proposal for main DAO")] CantCreateOverrule {}, - #[error("Can only execute proposals with exactly one message. Got {len} messages.")] - CanOnlyExecuteProposalsWithExactlyOneMessage { len: usize }, + #[error("Can only execute proposals with exactly one message that of ExecuteTimelockedMsgs type. Got {len} messages.")] + CanOnlyExecuteOneMsg { len: usize }, + + #[error("Can only execute msg of ExecuteTimelockedMsgs type")] + CanOnlyExecuteExecuteTimelockedMsgs {}, } diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs index 0aef757c..992c1055 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs @@ -7,6 +7,7 @@ use cosmwasm_std::{ }; use cwd_voting::status::Status; use neutron_sdk::bindings::msg::NeutronMsg; +use neutron_subdao_core::msg::ExecuteMsg as CoreExecuteMsg; use neutron_subdao_timelock_single::{ msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, types::{Config, ProposalListResponse, ProposalStatus, SingleChoiceProposal}, @@ -197,7 +198,11 @@ fn test_execute_proposal() { deps.querier.set_close_proposal_on_execution_failure(true); let proposal = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "".to_string(), + msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), + funds: vec![], + })], status: ProposalStatus::Timelocked, }; PROPOSALS @@ -231,8 +236,16 @@ fn test_execute_proposal() { let proposal = SingleChoiceProposal { id: 10, msgs: vec![ - NeutronMsg::remove_interchain_query(1).into(), - NeutronMsg::remove_interchain_query(2).into(), + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "".to_string(), + msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), + funds: vec![], + }), + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "".to_string(), + msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), + funds: vec![], + }), ], status: ProposalStatus::Timelocked, }; @@ -241,7 +254,37 @@ fn test_execute_proposal() { .unwrap(); let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); assert_eq!( - "Can only execute proposals with exactly one message. Got 2 messages.", + "Can only execute proposals with exactly one message that of ExecuteTimelockedMsgs type. Got 2 messages.", + res.unwrap_err().to_string() + ); + + // check that execution fails when there is a wrong type of message inside + let proposal = SingleChoiceProposal { + id: 10, + msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + status: ProposalStatus::Timelocked, + }; + PROPOSALS + .save(deps.as_mut().storage, proposal.id, &proposal) + .unwrap(); + let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); + assert_eq!( + "Can only execute msg of ExecuteTimelockedMsgs type", + res.unwrap_err().to_string() + ); + + // check that execution fails when there are no messages inside + let proposal = SingleChoiceProposal { + id: 10, + msgs: vec![], + status: ProposalStatus::Timelocked, + }; + PROPOSALS + .save(deps.as_mut().storage, proposal.id, &proposal) + .unwrap(); + let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); + assert_eq!( + "Can only execute proposals with exactly one message that of ExecuteTimelockedMsgs type. Got 0 messages.", res.unwrap_err().to_string() ); @@ -249,7 +292,11 @@ fn test_execute_proposal() { deps.querier.set_close_proposal_on_execution_failure(false); let proposal2 = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "".to_string(), + msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), + funds: vec![], + })], status: ProposalStatus::Timelocked, }; PROPOSALS From 6e5ef183ec9b725f5745a0c0aa4585494260e19f Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 26 Oct 2023 19:22:42 +0400 Subject: [PATCH 3/4] rename unpack_execute_msg -> verify_msg, add comment and small cleanup --- .../src/contract.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs index 9b8f0715..b3a002b8 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs @@ -178,7 +178,7 @@ pub fn execute_execute_proposal( .query_wasm_smart(proposal_module, &ProposalQueryMsg::Config {})?; // We expect only one specific message `ExecuteMsg::ExecuteTimelockedMsgs` inside - let msg = unpack_execute_msg(proposal.msgs)?; + let msg = verify_msg(proposal.msgs)?; match proposal_config.close_proposal_on_execution_failure { true => Response::default().add_submessage(SubMsg::reply_on_error(msg, proposal_id)), @@ -194,9 +194,9 @@ pub fn execute_execute_proposal( .add_attribute("proposal_id", proposal_id.to_string())) } -fn unpack_execute_msg( - msgs: Vec>, -) -> Result, ContractError> { +/// `verify_msg` checks that there is only one message inside `msgs` +/// and verifies type inside of `CoreExecuteMsg::ExecuteTimelockedMsgs` +fn verify_msg(msgs: Vec>) -> Result, ContractError> { let msgs_len = msgs.len(); // Expect exactly one message if msgs_len != 1 { @@ -210,16 +210,13 @@ fn unpack_execute_msg( // Expect only `ExecuteMsg::ExecuteTimelockedMsgs` match &msg { &CosmosMsg::Wasm(WasmMsg::Execute { + msg: ref core_execute_msg, contract_addr: _, funds: _, - ref msg, - }) => { - let unwrap_res: StdResult = from_binary(msg); - match unwrap_res { - Ok(CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: _ }) => {} - _ => return Err(ContractError::CanOnlyExecuteExecuteTimelockedMsgs {}), - } - } + }) => match from_binary::(core_execute_msg) { + Ok(CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: _ }) => {} + _ => return Err(ContractError::CanOnlyExecuteExecuteTimelockedMsgs {}), + }, _ => return Err(ContractError::CanOnlyExecuteExecuteTimelockedMsgs {}), } From dc53523f9ed10cef5b65f91ae91d814104503130 Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 1 Nov 2023 14:52:57 +0400 Subject: [PATCH 4/4] change messages to correct ones for timelock proposal tests; add verify check for execute_timelock_proposal as well --- .../src/contract.rs | 5 +- .../src/testing/tests.rs | 111 +++++++++++------- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs index b3a002b8..0d629d83 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/contract.rs @@ -110,9 +110,12 @@ pub fn execute_timelock_proposal( return Err(ContractError::Unauthorized {}); } + // We expect only one specific message `ExecuteMsg::ExecuteTimelockedMsgs` inside + let msg = verify_msg(msgs)?; + let proposal = SingleChoiceProposal { id: proposal_id, - msgs, + msgs: vec![msg], status: ProposalStatus::Timelocked, }; diff --git a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs index 992c1055..c44da723 100644 --- a/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs +++ b/contracts/subdaos/cwd-subdao-timelock-single/src/testing/tests.rs @@ -91,12 +91,17 @@ fn test_execute_timelock_proposal() { let env = mock_env(); let info = mock_info("neutron1unknownsender", &[]); - let msg = ExecuteMsg::TimelockProposal { + // No config set case + let correct_msg = ExecuteMsg::TimelockProposal { proposal_id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], }; - - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); + let res = execute( + deps.as_mut(), + env.clone(), + info.clone(), + correct_msg.clone(), + ); assert_eq!( "neutron_subdao_timelock_single::types::Config not found", res.unwrap_err().to_string() @@ -108,11 +113,48 @@ fn test_execute_timelock_proposal() { subdao: Addr::unchecked(MOCK_SUBDAO_CORE_ADDR), }; CONFIG.save(deps.as_mut().storage, &config).unwrap(); - let res = execute(deps.as_mut(), env.clone(), info, msg.clone()); + + // Unauthorized case + let res = execute(deps.as_mut(), env.clone(), info, correct_msg.clone()); assert_eq!("Unauthorized", res.unwrap_err().to_string()); let info = mock_info(MOCK_SUBDAO_CORE_ADDR, &[]); - let res_ok = execute(deps.as_mut(), env, info, msg).unwrap(); + + // check that execution fails when there is a wrong type of message inside + let incorrect_type_msg = ExecuteMsg::TimelockProposal { + proposal_id: 10, + msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + }; + let res = execute(deps.as_mut(), env.clone(), info.clone(), incorrect_type_msg); + assert_eq!( + "Can only execute msg of ExecuteTimelockedMsgs type", + res.unwrap_err().to_string() + ); + + // check that execution fails when there are no messages inside + let empty_msgs_msg = ExecuteMsg::TimelockProposal { + proposal_id: 10, + msgs: vec![], + }; + let res = execute(deps.as_mut(), env.clone(), info.clone(), empty_msgs_msg); + assert_eq!( + "Can only execute proposals with exactly one message that of ExecuteTimelockedMsgs type. Got 0 messages.", + res.unwrap_err().to_string() + ); + + // check that execution fails when there are 2 messages inside + let too_many_msgs_msg = ExecuteMsg::TimelockProposal { + proposal_id: 10, + msgs: vec![correct_proposal_msg(), correct_proposal_msg()], + }; + let res = execute(deps.as_mut(), env.clone(), info.clone(), too_many_msgs_msg); + assert_eq!( + "Can only execute proposals with exactly one message that of ExecuteTimelockedMsgs type. Got 2 messages.", + res.unwrap_err().to_string() + ); + + // successful case + let res_ok = execute(deps.as_mut(), env, info, correct_msg).unwrap(); let expected_attributes = vec![ Attribute::new("action", "timelock_proposal"), Attribute::new("sender", MOCK_SUBDAO_CORE_ADDR), @@ -139,7 +181,7 @@ fn test_execute_timelock_proposal() { let expected_proposal = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; let prop = PROPOSALS.load(deps.as_mut().storage, 10u64).unwrap(); @@ -181,7 +223,7 @@ fn test_execute_proposal() { for s in wrong_prop_statuses { let proposal = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], status: s, }; PROPOSALS @@ -198,11 +240,7 @@ fn test_execute_proposal() { deps.querier.set_close_proposal_on_execution_failure(true); let proposal = SingleChoiceProposal { id: 10, - msgs: vec![CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "".to_string(), - msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), - funds: vec![], - })], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; PROPOSALS @@ -235,18 +273,7 @@ fn test_execute_proposal() { // check that execution fails when there not exactly one message in proposal let proposal = SingleChoiceProposal { id: 10, - msgs: vec![ - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "".to_string(), - msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), - funds: vec![], - }), - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "".to_string(), - msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), - funds: vec![], - }), - ], + msgs: vec![correct_proposal_msg(), correct_proposal_msg()], status: ProposalStatus::Timelocked, }; PROPOSALS @@ -292,11 +319,7 @@ fn test_execute_proposal() { deps.querier.set_close_proposal_on_execution_failure(false); let proposal2 = SingleChoiceProposal { id: 10, - msgs: vec![CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "".to_string(), - msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), - funds: vec![], - })], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; PROPOSALS @@ -354,7 +377,7 @@ fn test_overrule_proposal() { for s in wrong_prop_statuses { let proposal = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], status: s, }; PROPOSALS @@ -369,7 +392,7 @@ fn test_overrule_proposal() { let proposal = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; PROPOSALS @@ -500,7 +523,7 @@ fn test_query_proposals() { for i in 1..=100 { let prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; PROPOSALS.save(deps.as_mut().storage, i, &prop).unwrap(); @@ -511,7 +534,7 @@ fn test_query_proposals() { let queried_prop: SingleChoiceProposal = from_binary(&res).unwrap(); let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, queried_prop) @@ -526,7 +549,7 @@ fn test_query_proposals() { for (p, i) in queried_props.proposals.iter().zip(1..) { let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, *p); @@ -542,7 +565,7 @@ fn test_query_proposals() { for (p, i) in queried_props.proposals.iter().zip(1..) { let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, *p); @@ -558,7 +581,7 @@ fn test_query_proposals() { for (p, i) in queried_props.proposals.iter().zip(1..) { let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, *p); @@ -574,7 +597,7 @@ fn test_query_proposals() { for (p, i) in queried_props.proposals.iter().zip(51..) { let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, *p); @@ -590,7 +613,7 @@ fn test_query_proposals() { for (p, i) in queried_props.proposals.iter().zip(91..) { let expected_prop = SingleChoiceProposal { id: i, - msgs: vec![NeutronMsg::remove_interchain_query(i).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; assert_eq!(expected_prop, *p); @@ -611,7 +634,7 @@ fn test_reply() { let prop = SingleChoiceProposal { id: 10, - msgs: vec![NeutronMsg::remove_interchain_query(1).into()], + msgs: vec![correct_proposal_msg()], status: ProposalStatus::Timelocked, }; let env = mock_env(); @@ -625,3 +648,11 @@ fn test_reply() { let error: Option = from_binary(&query_res).unwrap(); assert_eq!(error, Some("error".to_string())); } + +fn correct_proposal_msg() -> CosmosMsg { + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "".to_string(), + msg: to_binary(&CoreExecuteMsg::ExecuteTimelockedMsgs { msgs: vec![] }).unwrap(), + funds: vec![], + }) +}