diff --git a/Cargo.lock b/Cargo.lock index 4426d4bc..959791da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,6 +238,7 @@ dependencies = [ name = "babylon-bindings" version = "0.4.0" dependencies = [ + "anybuf", "babylon-apis", "cosmwasm-schema", "cosmwasm-std", @@ -549,6 +550,7 @@ version = "0.11.0" dependencies = [ "babylon-apis", "babylon-bindings", + "babylon-bindings-test", "babylon-bitcoin", "babylon-btcstaking", "babylon-contract", diff --git a/contracts/babylon/benches/main.rs b/contracts/babylon/benches/main.rs index 24987605..80e8ce30 100644 --- a/contracts/babylon/benches/main.rs +++ b/contracts/babylon/benches/main.rs @@ -49,10 +49,6 @@ pub fn setup_instance() -> Instance { btc_confirmation_depth: 10, checkpoint_finalization_timeout: 1, notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: None, - btc_finality_msg: None, admin: None, transfer_info: None, }; diff --git a/contracts/babylon/src/contract.rs b/contracts/babylon/src/contract.rs index 89e56d58..43aec9f8 100644 --- a/contracts/babylon/src/contract.rs +++ b/contracts/babylon/src/contract.rs @@ -1,11 +1,12 @@ +use babylon_bindings::query::{get_babylon_sdk_params, BabylonQuery}; use cosmwasm_std::{ - to_json_binary, to_json_string, Addr, Binary, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, - QueryResponse, Reply, Response, SubMsg, SubMsgResponse, WasmMsg, + to_json_binary, to_json_string, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, QueryResponse, + Response, WasmMsg, }; use cw2::set_contract_version; -use cw_utils::{must_pay, ParseReplyError}; +use cw_utils::must_pay; -use babylon_apis::{btc_staking_api, finality_api, to_bech32_addr, to_module_canonical_addr}; +use babylon_apis::{btc_staking_api, to_bech32_addr, to_module_canonical_addr}; use babylon_bindings::BabylonMsg; use crate::error::ContractError; @@ -18,15 +19,12 @@ use crate::state::config::{Config, CONFIG}; pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -const REPLY_ID_INSTANTIATE_STAKING: u64 = 2; -const REPLY_ID_INSTANTIATE_FINALITY: u64 = 3; - /// When we instantiate the Babylon contract, it will optionally instantiate a BTC staking /// contract – if its code id is provided – to work with it for BTC re-staking support, /// as they both need references to each other. /// The admin of the BTC staking contract is taken as an explicit argument. pub fn instantiate( - deps: DepsMut, + deps: DepsMut, _env: Env, _info: MessageInfo, msg: InstantiateMsg, @@ -41,57 +39,16 @@ pub fn instantiate( btc_confirmation_depth: msg.btc_confirmation_depth, checkpoint_finalization_timeout: msg.checkpoint_finalization_timeout, notify_cosmos_zone: msg.notify_cosmos_zone, - btc_staking: None, // Will be set in `reply` if `btc_staking_code_id` is provided - btc_finality: None, // Will be set in `reply` if `btc_finality_code_id` is provided consumer_name: None, consumer_description: None, denom, }; - let mut res = Response::new().add_attribute("action", "instantiate"); - - if let Some(btc_staking_code_id) = msg.btc_staking_code_id { - // Update config with consumer information - cfg.consumer_name = msg.consumer_name; - cfg.consumer_description = msg.consumer_description; - - // Instantiate BTC staking contract - let init_msg = WasmMsg::Instantiate { - admin: msg.admin.clone(), - code_id: btc_staking_code_id, - msg: msg.btc_staking_msg.unwrap_or(Binary::from(b"{}")), - funds: vec![], - label: "BTC Staking".into(), - }; - let init_msg = SubMsg::reply_on_success(init_msg, REPLY_ID_INSTANTIATE_STAKING); - - // Test code sets a channel, so that we can better approximate IBC in test code - #[cfg(any(test, all(feature = "library", not(target_arch = "wasm32"))))] - { - let channel = cosmwasm_std::testing::mock_ibc_channel( - "channel-123", - cosmwasm_std::IbcOrder::Ordered, - "babylon", - ); - IBC_CHANNEL.save(deps.storage, &channel)?; - } - - res = res.add_submessage(init_msg); - } - - if let Some(btc_finality_code_id) = msg.btc_finality_code_id { - // Instantiate BTC finality contract - let init_msg = WasmMsg::Instantiate { - admin: msg.admin, - code_id: btc_finality_code_id, - msg: msg.btc_finality_msg.unwrap_or(Binary::from(b"{}")), - funds: vec![], - label: "BTC Finality".into(), - }; - let init_msg = SubMsg::reply_on_success(init_msg, REPLY_ID_INSTANTIATE_FINALITY); + let res = Response::new().add_attribute("action", "instantiate"); - res = res.add_submessage(init_msg); - } + // Update config with consumer information + cfg.consumer_name = msg.consumer_name; + cfg.consumer_description = msg.consumer_description; // Save the config after potentially updating it CONFIG.save(deps.storage, &cfg)?; @@ -119,76 +76,11 @@ pub fn instantiate( Ok(res) } -pub fn reply( - deps: DepsMut, +pub fn query( + deps: Deps, _env: Env, - reply: Reply, -) -> Result, ContractError> { - match reply.id { - REPLY_ID_INSTANTIATE_STAKING => reply_init_callback_staking(deps, reply.result.unwrap()), - REPLY_ID_INSTANTIATE_FINALITY => reply_init_finality_callback(deps, reply.result.unwrap()), - _ => Err(ContractError::InvalidReplyId(reply.id)), - } -} - -/// Tries to get contract address from events in reply -fn reply_init_get_contract_address(reply: SubMsgResponse) -> Result { - for event in reply.events { - if event.ty == "instantiate" { - for attr in event.attributes { - if attr.key == "_contract_address" { - return Ok(Addr::unchecked(attr.value)); - } - } - } - } - Err(ContractError::ParseReply(ParseReplyError::ParseFailure( - "Cannot parse contract address".to_string(), - ))) -} - -/// Store BTC staking address -fn reply_init_callback_staking( - deps: DepsMut, - reply: SubMsgResponse, -) -> Result, ContractError> { - // Try to get contract address from events in reply - let addr = reply_init_get_contract_address(reply)?; - CONFIG.update(deps.storage, |mut cfg| { - cfg.btc_staking = Some(addr); - Ok::<_, ContractError>(cfg) - })?; - Ok(Response::new()) -} - -/// Store BTC finality address -fn reply_init_finality_callback( - deps: DepsMut, - reply: SubMsgResponse, -) -> Result, ContractError> { - // Try to get contract address from events in reply - let finality_addr = reply_init_get_contract_address(reply)?; - CONFIG.update(deps.storage, |mut cfg| { - cfg.btc_finality = Some(finality_addr.clone()); - Ok::<_, ContractError>(cfg) - })?; - // Set the BTC staking contract address to the BTC finality contract - let cfg = CONFIG.load(deps.storage)?; - let msg = finality_api::ExecuteMsg::UpdateStaking { - staking: cfg - .btc_staking - .ok_or(ContractError::BtcStakingNotSet {})? - .to_string(), - }; - let wasm_msg = WasmMsg::Execute { - contract_addr: finality_addr.to_string(), - msg: to_json_binary(&msg)?, - funds: vec![], - }; - Ok(Response::new().add_message(wasm_msg)) -} - -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { + msg: QueryMsg, +) -> Result { match msg { QueryMsg::Config {} => Ok(to_json_binary(&queries::config(deps)?)?), QueryMsg::BtcBaseHeader {} => Ok(to_json_binary(&queries::btc_base_header(deps)?)?), @@ -224,7 +116,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result, _env: Env, _msg: Empty, ) -> Result, ContractError> { @@ -232,7 +124,7 @@ pub fn migrate( } pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -250,18 +142,15 @@ pub fn execute( Ok(Response::new()) } ExecuteMsg::Slashing { evidence } => { - // This is an internal routing message from the `btc_finality` contract - let cfg = CONFIG.load(deps.storage)?; // Check sender - let btc_finality = cfg - .btc_finality - .ok_or(ContractError::BtcFinalityNotSet {})?; + let params = get_babylon_sdk_params(&deps.querier)?; + let btc_finality = params.btc_finality_contract_address; if info.sender != btc_finality { return Err(ContractError::Unauthorized {}); } // Send to the staking contract for processing let mut res = Response::new(); - let btc_staking = cfg.btc_staking.ok_or(ContractError::BtcStakingNotSet {})?; + let btc_staking = params.btc_staking_contract_address; // Slashes this finality provider, i.e., sets its slashing height to the block height // and its power to zero let msg = btc_staking_api::ExecuteMsg::Slash { @@ -296,9 +185,7 @@ pub fn execute( // Assert the funds are there must_pay(&info, &cfg.denom)?; // Assert the sender is right - let btc_finality = cfg - .btc_finality - .ok_or(ContractError::BtcFinalityNotSet {})?; + let btc_finality = get_babylon_sdk_params(&deps.querier)?.btc_finality_contract_address; if info.sender != btc_finality { return Err(ContractError::Unauthorized {}); } @@ -342,9 +229,11 @@ pub fn execute( #[cfg(test)] mod tests { use super::*; + use babylon_bindings_test::mock_dependencies; use babylon_bitcoin::BlockHeader; use cosmwasm_std::testing::message_info; - use cosmwasm_std::testing::{mock_dependencies, mock_env}; + use cosmwasm_std::testing::mock_env; + use cosmwasm_std::Binary; const CREATOR: &str = "creator"; @@ -365,10 +254,6 @@ mod tests { btc_confirmation_depth: 10, checkpoint_finalization_timeout: 100, notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: None, - btc_finality_msg: None, admin: None, consumer_name: None, consumer_description: None, @@ -379,77 +264,6 @@ mod tests { assert_eq!(0, res.messages.len()); } - #[test] - fn instantiate_finality_works() { - let mut deps = mock_dependencies(); - let msg = InstantiateMsg { - network: babylon_bitcoin::chain_params::Network::Regtest, - babylon_tag: "01020304".to_string(), - btc_confirmation_depth: 10, - checkpoint_finalization_timeout: 100, - notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: Some(2), - btc_finality_msg: None, - admin: None, - consumer_name: None, - consumer_description: None, - transfer_info: None, - }; - let info = message_info(&deps.api.addr_make(CREATOR), &[]); - let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); - assert_eq!(1, res.messages.len()); - assert_eq!(REPLY_ID_INSTANTIATE_FINALITY, res.messages[0].id); - assert_eq!( - res.messages[0].msg, - WasmMsg::Instantiate { - admin: None, - code_id: 2, - msg: Binary::from(b"{}"), - funds: vec![], - label: "BTC Finality".into(), - } - .into() - ); - } - - #[test] - fn instantiate_finality_params_works() { - let mut deps = mock_dependencies(); - let params = r#"{"params": {"epoch_length": 10}}"#; - let msg = InstantiateMsg { - network: babylon_bitcoin::chain_params::Network::Regtest, - babylon_tag: "01020304".to_string(), - btc_confirmation_depth: 10, - checkpoint_finalization_timeout: 100, - notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: Some(2), - btc_finality_msg: Some(Binary::from(params.as_bytes())), - admin: None, - consumer_name: None, - consumer_description: None, - transfer_info: None, - }; - let info = message_info(&deps.api.addr_make(CREATOR), &[]); - let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); - assert_eq!(1, res.messages.len()); - assert_eq!(REPLY_ID_INSTANTIATE_FINALITY, res.messages[0].id); - assert_eq!( - res.messages[0].msg, - WasmMsg::Instantiate { - admin: None, - code_id: 2, - msg: Binary::from(params.as_bytes()), - funds: vec![], - label: "BTC Finality".into(), - } - .into() - ); - } - #[test] fn test_module_address() { // Example usage diff --git a/contracts/babylon/src/ibc.rs b/contracts/babylon/src/ibc.rs index 5a4f184d..f62318ab 100644 --- a/contracts/babylon/src/ibc.rs +++ b/contracts/babylon/src/ibc.rs @@ -1,5 +1,5 @@ use crate::error::ContractError; -use babylon_bindings::BabylonMsg; +use babylon_bindings::{query::BabylonQuery, BabylonMsg}; use babylon_proto::babylon::zoneconcierge::v1::{ zoneconcierge_packet_data::Packet, BtcTimestamp, ZoneconciergePacketData, }; @@ -35,7 +35,7 @@ pub const IBC_TRANSFER: Item = Item::new("ibc_transfer"); /// In the case of ChannelOpenTry there's a counterparty_version attribute in the message. /// Here we ensure the ordering and version constraints. pub fn ibc_channel_open( - deps: DepsMut, + deps: DepsMut, _env: Env, msg: IbcChannelOpenMsg, ) -> Result { @@ -67,7 +67,7 @@ pub fn ibc_channel_open( /// Second part of the 4-step handshake, i.e. ChannelOpenAck and ChannelOpenConfirm. pub fn ibc_channel_connect( - deps: DepsMut, + deps: DepsMut, _env: Env, msg: IbcChannelConnectMsg, ) -> Result { @@ -102,7 +102,7 @@ pub fn ibc_channel_connect( /// This is invoked on the IBC Channel Close message /// We perform any cleanup related to the channel pub fn ibc_channel_close( - _deps: DepsMut, + _deps: DepsMut, _env: Env, msg: IbcChannelCloseMsg, ) -> StdResult { @@ -126,7 +126,7 @@ pub fn ibc_channel_close( /// That's because we want to send an ACK for the packet regardless if there's an error or not, /// but in the case of an error, we do not want the state to be committed. pub fn ibc_packet_receive( - deps: DepsMut, + deps: DepsMut, _env: Env, msg: IbcPacketReceiveMsg, ) -> Result, Never> { @@ -174,13 +174,14 @@ pub(crate) mod ibc_packet { ActiveBtcDelegation, NewFinalityProvider, UnbondedBtcDelegation, }; use babylon_apis::finality_api::Evidence; + use babylon_bindings::query::get_babylon_sdk_params; use babylon_proto::babylon::btcstaking::v1::BtcStakingIbcPacket; use babylon_proto::babylon::zoneconcierge::v1::zoneconcierge_packet_data::Packet::ConsumerSlashing; use babylon_proto::babylon::zoneconcierge::v1::ConsumerSlashingIbcPacket; use cosmwasm_std::{to_json_binary, IbcChannel, IbcMsg, WasmMsg}; pub fn handle_btc_timestamp( - deps: DepsMut, + deps: DepsMut, _caller: String, btc_ts: &BtcTimestamp, ) -> StdResult> { @@ -209,17 +210,14 @@ pub(crate) mod ibc_packet { } pub fn handle_btc_staking( - deps: DepsMut, + deps: DepsMut, _caller: String, btc_staking: &BtcStakingIbcPacket, ) -> StdResult> { - let storage = deps.storage; - let cfg = CONFIG.load(storage)?; + let params = get_babylon_sdk_params(&deps.querier)?; // Route the packet to the btc-staking contract - let btc_staking_addr = cfg - .btc_staking - .ok_or(StdError::generic_err("btc_staking contract not set"))?; + let btc_staking_addr = params.btc_staking_contract_address; // Build the message to send to the BTC staking contract let msg = babylon_apis::btc_staking_api::ExecuteMsg::BtcStaking { @@ -303,7 +301,7 @@ pub fn packet_timeout(env: &Env) -> IbcTimeout { } pub fn ibc_packet_ack( - _deps: DepsMut, + _deps: DepsMut, _env: Env, _msg: IbcPacketAckMsg, ) -> Result { @@ -311,7 +309,7 @@ pub fn ibc_packet_ack( } pub fn ibc_packet_timeout( - _deps: DepsMut, + _deps: DepsMut, _env: Env, msg: IbcPacketTimeoutMsg, ) -> Result { @@ -328,15 +326,15 @@ mod tests { use crate::contract::instantiate; use crate::msg::contract::InstantiateMsg; use crate::msg::ibc::{IbcTransferInfo, Recipient}; + use babylon_bindings_test::mock_dependencies; use cosmwasm_std::testing::message_info; use cosmwasm_std::testing::{ - mock_dependencies, mock_env, mock_ibc_channel_open_try, MockApi, MockQuerier, MockStorage, + mock_env, mock_ibc_channel_open_try, MockApi, MockQuerier, MockStorage, }; use cosmwasm_std::OwnedDeps; const CREATOR: &str = "creator"; - - fn setup() -> OwnedDeps { + fn setup() -> OwnedDeps, BabylonQuery> { let mut deps = mock_dependencies(); let msg = InstantiateMsg { network: babylon_bitcoin::chain_params::Network::Regtest, @@ -344,10 +342,6 @@ mod tests { btc_confirmation_depth: 10, checkpoint_finalization_timeout: 100, notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: None, - btc_finality_msg: None, admin: None, consumer_name: None, consumer_description: None, diff --git a/contracts/babylon/src/lib.rs b/contracts/babylon/src/lib.rs index dd7414f3..698fb3d9 100644 --- a/contracts/babylon/src/lib.rs +++ b/contracts/babylon/src/lib.rs @@ -3,10 +3,10 @@ use cosmwasm_std::entry_point; use cosmwasm_std::{ Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Reply, Response, StdResult, + IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Response, StdResult, }; -use babylon_bindings::BabylonMsg; +use babylon_bindings::{query::BabylonQuery, BabylonMsg}; use crate::error::ContractError; pub use crate::msg::contract::ExecuteMsg; @@ -25,7 +25,7 @@ mod utils; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: InstantiateMsg, @@ -34,23 +34,26 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(deps: DepsMut, env: Env, reply: Reply) -> Result, ContractError> { - contract::reply(deps, env, reply) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: msg::contract::QueryMsg) -> Result { +pub fn query( + deps: Deps, + env: Env, + msg: msg::contract::QueryMsg, +) -> Result { contract::query(deps, env, msg) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(deps: DepsMut, env: Env, msg: Empty) -> Result, ContractError> { +pub fn migrate( + deps: DepsMut, + env: Env, + msg: Empty, +) -> Result, ContractError> { contract::migrate(deps, env, msg) } #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -60,7 +63,7 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_channel_open( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcChannelOpenMsg, ) -> Result { @@ -69,7 +72,7 @@ pub fn ibc_channel_open( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_channel_connect( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcChannelConnectMsg, ) -> Result { @@ -78,7 +81,7 @@ pub fn ibc_channel_connect( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_channel_close( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcChannelCloseMsg, ) -> StdResult { @@ -87,7 +90,7 @@ pub fn ibc_channel_close( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_packet_receive( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcPacketReceiveMsg, ) -> Result, Never> { @@ -96,7 +99,7 @@ pub fn ibc_packet_receive( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_packet_ack( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcPacketAckMsg, ) -> Result { @@ -105,7 +108,7 @@ pub fn ibc_packet_ack( #[cfg_attr(not(feature = "library"), entry_point)] pub fn ibc_packet_timeout( - deps: DepsMut, + deps: DepsMut, env: Env, msg: IbcPacketTimeoutMsg, ) -> Result { diff --git a/contracts/babylon/src/msg/contract.rs b/contracts/babylon/src/msg/contract.rs index d24b193a..e9f51257 100644 --- a/contracts/babylon/src/msg/contract.rs +++ b/contracts/babylon/src/msg/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::Uint128; -use cosmwasm_std::{Binary, StdError, StdResult}; +use cosmwasm_std::{StdError, StdResult}; use babylon_apis::finality_api::Evidence; @@ -34,18 +34,6 @@ pub struct InstantiateMsg { /// NOTE: If set to true, then the Cosmos zone needs to integrate the corresponding message handler /// as well pub notify_cosmos_zone: bool, - /// If set, this will instantiate a BTC staking contract for BTC re-staking - pub btc_staking_code_id: Option, - /// If set, this will define the instantiation message for the BTC staking contract. - /// This message is opaque to the Babylon contract, and depends on the specific staking contract - /// being instantiated - pub btc_staking_msg: Option, - /// If set, this will instantiate a BTC finality contract - pub btc_finality_code_id: Option, - /// If set, this will define the instantiation message for the BTC finality contract. - /// This message is opaque to the Babylon contract, and depends on the specific finality contract - /// being instantiated - pub btc_finality_msg: Option, /// If set, this will be the Wasm migration / upgrade admin of the BTC staking contract and the /// BTC finality contract pub admin: Option, @@ -68,25 +56,6 @@ impl ContractMsg for InstantiateMsg { } let _ = self.babylon_tag_to_bytes()?; - if self.btc_staking_code_id.is_some() { - if let (Some(consumer_name), Some(consumer_description)) = - (&self.consumer_name, &self.consumer_description) - { - if consumer_name.trim().is_empty() { - return Err(StdError::generic_err("Consumer name cannot be empty")); - } - if consumer_description.trim().is_empty() { - return Err(StdError::generic_err( - "Consumer description cannot be empty", - )); - } - } else { - return Err(StdError::generic_err( - "Consumer name and description are required when btc_staking_code_id is set", - )); - } - } - if let Some(transfer_info) = &self.transfer_info { transfer_info.validate()?; } diff --git a/contracts/babylon/src/multitest.rs b/contracts/babylon/src/multitest.rs index 71b236ed..b8e8f0f6 100644 --- a/contracts/babylon/src/multitest.rs +++ b/contracts/babylon/src/multitest.rs @@ -3,12 +3,6 @@ mod suite; use cosmwasm_std::Addr; use suite::SuiteBuilder; -// Some multi-test default settings -// TODO: Replace these with their address generators -const CONTRACT0_ADDR: &str = "cosmwasm19mfs8tl4s396u7vqw9rrnsmrrtca5r66p7v8jvwdxvjn3shcmllqupdgxu"; -const CONTRACT1_ADDR: &str = "cosmwasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s8jef58"; -const CONTRACT2_ADDR: &str = "cosmwasm1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqt8utkp"; - #[test] fn initialization() { let suite = SuiteBuilder::new().build(); @@ -23,16 +17,8 @@ fn initialization() { assert_eq!(config.btc_confirmation_depth, 1); assert_eq!(config.checkpoint_finalization_timeout, 10); assert!(!config.notify_cosmos_zone); - assert_eq!(config.btc_staking, Some(Addr::unchecked(CONTRACT1_ADDR))); - assert_eq!(config.btc_finality, Some(Addr::unchecked(CONTRACT2_ADDR))); - - // Check that the btc-staking contract was initialized correctly - let btc_staking_config = suite.get_btc_staking_config(); - assert_eq!(btc_staking_config.babylon, Addr::unchecked(CONTRACT0_ADDR)); - - // Check that the btc-finality contract was initialized correctly - let btc_finality_config = suite.get_btc_finality_config(); - assert_eq!(btc_finality_config.babylon, Addr::unchecked(CONTRACT0_ADDR)); + assert!(!suite.btc_staking_contract.to_string().is_empty()); + assert!(!suite.btc_finality_contract.to_string().is_empty()); } mod instantiation { @@ -46,10 +32,9 @@ mod instantiation { let suite = SuiteBuilder::new().build(); // Confirm the btc-staking contract has been instantiated and set - let config = suite.get_config(); - assert_eq!(config.btc_staking, Some(Addr::unchecked(CONTRACT1_ADDR))); + assert!(!suite.btc_staking_contract.to_string().is_empty()); // Confirm the btc-finality contract has been instantiated and set - assert_eq!(config.btc_finality, Some(Addr::unchecked(CONTRACT2_ADDR))); + assert!(!suite.btc_finality_contract.to_string().is_empty()); } #[test] @@ -73,9 +58,6 @@ mod instantiation { // Confirm the btc-staking contract has been instantiated and set let config = suite.get_config(); - assert_eq!(config.btc_staking, Some(Addr::unchecked(CONTRACT1_ADDR))); - // Confirm the btc-finality contract has been instantiated and set - assert_eq!(config.btc_finality, Some(Addr::unchecked(CONTRACT2_ADDR))); } #[test] @@ -97,9 +79,6 @@ mod instantiation { // Confirm the btc-staking contract has been instantiated and set let config = suite.get_config(); - assert_eq!(config.btc_staking, Some(Addr::unchecked(CONTRACT1_ADDR))); - // Confirm the btc-finality contract has been instantiated and set - assert_eq!(config.btc_finality, Some(Addr::unchecked(CONTRACT2_ADDR))); } #[test] diff --git a/contracts/babylon/src/multitest/suite.rs b/contracts/babylon/src/multitest/suite.rs index 44960a76..08de2303 100644 --- a/contracts/babylon/src/multitest/suite.rs +++ b/contracts/babylon/src/multitest/suite.rs @@ -1,6 +1,9 @@ +use crate::msg::contract::{InstantiateMsg, QueryMsg}; use crate::msg::ibc::TransferInfoResponse; use crate::msg::ibc::{IbcTransferInfo, Recipient}; +use crate::state::config::Config; use anyhow::Result as AnyResult; +use babylon_bindings::query::BabylonQuery; use derivative::Derivative; use cosmwasm_std::{Addr, Binary, Empty}; @@ -10,11 +13,7 @@ use babylon_bindings::BabylonMsg; use babylon_bindings_test::BabylonApp; use babylon_bitcoin::chain_params::Network; -use crate::msg::contract::{InstantiateMsg, QueryMsg}; -use crate::multitest::{CONTRACT1_ADDR, CONTRACT2_ADDR}; -use crate::state::config::Config; - -fn contract_btc_staking() -> Box> { +fn contract_btc_staking() -> Box> { let contract = ContractWrapper::new( btc_staking::contract::execute, btc_staking::contract::instantiate, @@ -23,7 +22,7 @@ fn contract_btc_staking() -> Box> { Box::new(contract) } -fn contract_btc_finality() -> Box> { +fn contract_btc_finality() -> Box> { let contract = ContractWrapper::new( btc_finality::contract::execute, btc_finality::contract::instantiate, @@ -32,9 +31,8 @@ fn contract_btc_finality() -> Box> { Box::new(contract) } -fn contract_babylon() -> Box> { +fn contract_babylon() -> Box> { let contract = ContractWrapper::new(crate::execute, crate::instantiate, crate::query) - .with_reply(crate::reply) .with_migrate(crate::migrate); Box::new(contract) } @@ -92,10 +90,7 @@ impl SuiteBuilder { app.init_modules(|_router, _api, _storage| -> AnyResult<()> { Ok(()) }) .unwrap(); - let btc_staking_code_id = - app.store_code_with_creator(owner.clone(), contract_btc_staking()); - let btc_finality_code_id = - app.store_code_with_creator(owner.clone(), contract_btc_finality()); + // Store and instantiate the Babylon contract let contract_code_id = app.store_code_with_creator(owner.clone(), contract_babylon()); let staking_msg = self.staking_msg.map(|msg| Binary::from(msg.as_bytes())); @@ -110,10 +105,6 @@ impl SuiteBuilder { btc_confirmation_depth: 1, checkpoint_finalization_timeout: 10, notify_cosmos_zone: false, - btc_staking_code_id: Some(btc_staking_code_id), - btc_staking_msg: staking_msg, - btc_finality_code_id: Some(btc_finality_code_id), - btc_finality_msg: finality_msg, admin: Some(owner.to_string()), consumer_name: Some("TestConsumer".to_string()), consumer_description: Some("Test Consumer Description".to_string()), @@ -125,10 +116,44 @@ impl SuiteBuilder { ) .unwrap(); + let btc_staking_code_id = + app.store_code_with_creator(owner.clone(), contract_btc_staking()); + let btc_staking_contract = app + .instantiate_contract( + btc_staking_code_id, + owner.clone(), + &btc_staking::msg::InstantiateMsg { + admin: None, + params: None, + }, + &[], + "btc-staking", + Some(owner.to_string()), + ) + .unwrap(); + + let btc_finality_code_id = + app.store_code_with_creator(owner.clone(), contract_btc_finality()); + let btc_finality_contract = app + .instantiate_contract( + btc_finality_code_id, + owner.clone(), + &btc_finality::msg::InstantiateMsg { + admin: None, + params: None, + }, + &[], + "btc-finality", + Some(owner.to_string()), + ) + .unwrap(); + Suite { app, code_id: contract_code_id, - contract, + babylon_contract: contract, + btc_staking_contract: btc_staking_contract, + btc_finality_contract: btc_finality_contract, owner, } } @@ -142,7 +167,11 @@ pub struct Suite { /// The code id of the babylon contract code_id: u64, /// Babylon contract address - pub contract: Addr, + pub babylon_contract: Addr, + /// BTC staking contract address + pub btc_staking_contract: Addr, + /// BTC finality contract address + pub btc_finality_contract: Addr, /// Admin of babylon and btc-staking contracts pub owner: Addr, } @@ -156,7 +185,7 @@ impl Suite { pub fn get_config(&self) -> Config { self.app .wrap() - .query_wasm_smart(self.contract.clone(), &QueryMsg::Config {}) + .query_wasm_smart(self.babylon_contract.clone(), &QueryMsg::Config {}) .unwrap() } @@ -164,7 +193,10 @@ impl Suite { pub fn get_btc_staking_config(&self) -> btc_staking::state::config::Config { self.app .wrap() - .query_wasm_smart(CONTRACT1_ADDR, &btc_staking::msg::QueryMsg::Config {}) + .query_wasm_smart( + self.btc_staking_contract.clone(), + &btc_staking::msg::QueryMsg::Config {}, + ) .unwrap() } @@ -172,7 +204,10 @@ impl Suite { pub fn get_btc_finality_config(&self) -> btc_finality::state::config::Config { self.app .wrap() - .query_wasm_smart(CONTRACT2_ADDR, &btc_finality::msg::QueryMsg::Config {}) + .query_wasm_smart( + self.btc_finality_contract.clone(), + &btc_finality::msg::QueryMsg::Config {}, + ) .unwrap() } @@ -180,14 +215,14 @@ impl Suite { pub fn get_transfer_info(&self) -> TransferInfoResponse { self.app .wrap() - .query_wasm_smart(self.contract.clone(), &QueryMsg::TransferInfo {}) + .query_wasm_smart(self.babylon_contract.clone(), &QueryMsg::TransferInfo {}) .unwrap() } pub fn migrate(&mut self, addr: &str, msg: Empty) -> AnyResult { self.app.migrate_contract( Addr::unchecked(addr), - self.contract.clone(), + self.babylon_contract.clone(), &msg, self.code_id, ) diff --git a/contracts/babylon/src/queries/mod.rs b/contracts/babylon/src/queries/mod.rs index 5181bcf6..c186b434 100644 --- a/contracts/babylon/src/queries/mod.rs +++ b/contracts/babylon/src/queries/mod.rs @@ -14,31 +14,35 @@ use crate::state::btc_light_client::{ }; use crate::state::config::{Config, CONFIG}; use crate::state::cz_header_chain::{get_cz_header, get_last_cz_header}; +use babylon_bindings::query::BabylonQuery; use babylon_bitcoin::BlockHash; use cosmwasm_std::{Deps, StdResult}; use std::str::FromStr; -pub fn config(deps: Deps) -> StdResult { +pub fn config(deps: Deps) -> StdResult { CONFIG.load(deps.storage) } -pub fn btc_base_header(deps: Deps) -> Result { +pub fn btc_base_header(deps: Deps) -> Result { let btc_header_info = get_base_header(deps.storage)?; BtcHeaderResponse::try_from(&btc_header_info) } -pub fn btc_tip_header(_deps: Deps) -> Result { +pub fn btc_tip_header(_deps: Deps) -> Result { let btc_header_info = get_tip(_deps.storage)?; BtcHeaderResponse::try_from(&btc_header_info) } -pub fn btc_header(deps: Deps, height: u32) -> Result { +pub fn btc_header( + deps: Deps, + height: u32, +) -> Result { let btc_header_info = get_header(deps.storage, height)?; BtcHeaderResponse::try_from(&btc_header_info) } pub fn btc_header_by_hash( - deps: Deps, + deps: Deps, hash: &str, ) -> Result { let hash = BlockHash::from_str(hash)?; @@ -47,7 +51,7 @@ pub fn btc_header_by_hash( } pub fn btc_headers( - deps: Deps, + deps: Deps, start_after: Option, limit: Option, reverse: Option, @@ -62,18 +66,22 @@ pub fn btc_headers( }) } -pub fn babylon_base_epoch(deps: Deps) -> Result { +pub fn babylon_base_epoch( + deps: Deps, +) -> Result { let epoch = get_base_epoch(deps.storage)?; Ok(EpochResponse::from(&epoch)) } -pub fn babylon_last_epoch(deps: Deps) -> Result { +pub fn babylon_last_epoch( + deps: Deps, +) -> Result { let epoch = get_last_finalized_epoch(deps.storage)?; Ok(EpochResponse::from(&epoch)) } pub fn babylon_epoch( - deps: Deps, + deps: Deps, epoch_number: u64, ) -> Result { let epoch = get_epoch(deps.storage, epoch_number)?; @@ -81,24 +89,29 @@ pub fn babylon_epoch( } pub fn babylon_checkpoint( - deps: Deps, + deps: Deps, epoch_number: u64, ) -> Result { let raw_checkpoint = get_checkpoint(deps.storage, epoch_number)?; Ok(CheckpointResponse::from(&raw_checkpoint)) } -pub fn cz_last_header(deps: Deps) -> Result { +pub fn cz_last_header(deps: Deps) -> Result { let header = get_last_cz_header(deps.storage)?; Ok(CzHeaderResponse::from(&header)) } -pub(crate) fn cz_header(deps: Deps, height: u64) -> Result { +pub(crate) fn cz_header( + deps: Deps, + height: u64, +) -> Result { let header = get_cz_header(deps.storage, height)?; Ok(CzHeaderResponse::from(&header)) } -pub(crate) fn transfer_info(deps: Deps) -> Result { +pub(crate) fn transfer_info( + deps: Deps, +) -> Result { let transfer_info = IBC_TRANSFER.may_load(deps.storage)?; Ok(transfer_info) } @@ -107,7 +120,7 @@ pub(crate) fn transfer_info(deps: Deps) -> Result = Item::new("config"); @@ -15,10 +14,6 @@ pub struct Config { /// NOTE: if set to true, then the Cosmos zone needs to integrate the corresponding message /// handler as well pub notify_cosmos_zone: bool, - /// If set, this stores a BTC staking contract used for BTC re-staking - pub btc_staking: Option, - /// If set, this stores a BTC finality contract used for BTC finality on the Consumer - pub btc_finality: Option, /// Consumer name pub consumer_name: Option, /// Consumer description diff --git a/contracts/babylon/tests/integration.rs b/contracts/babylon/tests/integration.rs index 42e07d6c..9e9aca42 100644 --- a/contracts/babylon/tests/integration.rs +++ b/contracts/babylon/tests/integration.rs @@ -47,10 +47,6 @@ fn setup() -> Instance { btc_confirmation_depth: 10, checkpoint_finalization_timeout: 99, notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: None, - btc_finality_msg: None, admin: None, transfer_info: None, }; @@ -103,10 +99,6 @@ fn instantiate_works() { btc_confirmation_depth: 10, checkpoint_finalization_timeout: 100, notify_cosmos_zone: false, - btc_staking_code_id: None, - btc_staking_msg: None, - btc_finality_code_id: None, - btc_finality_msg: None, admin: None, transfer_info: None, }; diff --git a/contracts/btc-finality/src/contract.rs b/contracts/btc-finality/src/contract.rs index 2e8e6677..21066434 100644 --- a/contracts/btc-finality/src/contract.rs +++ b/contracts/btc-finality/src/contract.rs @@ -1,4 +1,5 @@ use babylon_apis::finality_api::SudoMsg; +use babylon_bindings::query::{get_babylon_sdk_params, BabylonQuery}; use babylon_bindings::BabylonMsg; use btc_staking::msg::ActivatedHeightResponse; #[cfg(not(feature = "library"))] @@ -26,7 +27,7 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - mut deps: DepsMut, + mut deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg, @@ -39,8 +40,6 @@ pub fn instantiate( let config = Config { denom, blocks_per_year, - babylon: info.sender, - staking: Addr::unchecked("UNSET"), // To be set later, through `UpdateStaking` }; CONFIG.save(deps.storage, &config)?; @@ -57,7 +56,7 @@ pub fn instantiate( } /// Queries the chain's blocks per year using the mint Params Grpc query -fn get_blocks_per_year(deps: &mut DepsMut) -> Result { +fn get_blocks_per_year(deps: &mut DepsMut) -> Result { let blocks_per_year; #[cfg(any(test, all(feature = "library", not(target_arch = "wasm32"))))] { @@ -84,12 +83,16 @@ fn get_blocks_per_year(deps: &mut DepsMut) -> Result { } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(_deps: DepsMut, _env: Env, _reply: Reply) -> StdResult { +pub fn reply(_deps: DepsMut, _env: Env, _reply: Reply) -> StdResult { Ok(Response::default()) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { +pub fn query( + deps: Deps, + _env: Env, + msg: QueryMsg, +) -> Result { match msg { QueryMsg::Config {} => Ok(to_json_binary(&queries::config(deps)?)?), QueryMsg::Params {} => Ok(to_json_binary(&queries::params(deps)?)?), @@ -144,7 +147,7 @@ pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> StdResult { #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -191,7 +194,7 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn sudo( - mut deps: DepsMut, + mut deps: DepsMut, env: Env, msg: SudoMsg, ) -> Result, ContractError> { @@ -205,16 +208,18 @@ pub fn sudo( } fn handle_update_staking( - deps: DepsMut, + deps: DepsMut, info: MessageInfo, staking_addr: String, ) -> Result, ContractError> { - let mut cfg = CONFIG.load(deps.storage)?; - if info.sender != cfg.babylon && !ADMIN.is_admin(deps.as_ref(), &info.sender)? { + let params = get_babylon_sdk_params(&deps.querier)?; + + // ensure the sender is the Babylon contract + if info.sender != params.babylon_contract_address + && !ADMIN.is_admin(deps.as_ref(), &info.sender)? + { return Err(ContractError::Unauthorized {}); } - cfg.staking = deps.api.addr_validate(&staking_addr)?; - CONFIG.save(deps.storage, &cfg)?; let attributes = vec![ attr("action", "update_btc_staking"), @@ -224,7 +229,10 @@ fn handle_update_staking( Ok(Response::new().add_attributes(attributes)) } -fn handle_begin_block(deps: &mut DepsMut, env: Env) -> Result, ContractError> { +fn handle_begin_block( + deps: &mut DepsMut, + env: Env, +) -> Result, ContractError> { // Distribute rewards distribute_rewards(deps, &env)?; @@ -237,7 +245,7 @@ fn handle_begin_block(deps: &mut DepsMut, env: Env) -> Result, env: Env, _hash_hex: &str, app_hash_hex: &str, @@ -246,7 +254,7 @@ fn handle_end_block( // finality provider has voting power, start indexing and tallying blocks let cfg = CONFIG.load(deps.storage)?; let mut res = Response::new(); - let activated_height = get_activated_height(&cfg.staking, &deps.querier)?; + let activated_height = get_activated_height(&deps.querier)?; if activated_height > 0 { // Index the current block let ev = finality::index_block(deps, env.block.height, &hex::decode(app_hash_hex)?)?; @@ -274,7 +282,7 @@ fn handle_end_block( } fn send_rewards_msg( - deps: &mut DepsMut, + deps: &mut DepsMut, rewards: u128, cfg: &Config, ) -> Result { @@ -300,7 +308,9 @@ fn send_rewards_msg( fp_distribution: fp_rewards.clone(), }; let wasm_msg = WasmMsg::Execute { - contract_addr: cfg.babylon.to_string(), + contract_addr: get_babylon_sdk_params(&deps.querier)? + .babylon_contract_address + .to_string(), msg: to_json_binary(&msg)?, funds: coins(rewards, cfg.denom.as_str()), }; @@ -312,10 +322,10 @@ fn send_rewards_msg( Ok(wasm_msg) } -pub fn get_activated_height(staking_addr: &Addr, querier: &QuerierWrapper) -> StdResult { +pub fn get_activated_height(querier: &QuerierWrapper) -> StdResult { // TODO: Use a raw query let query = encode_smart_query( - staking_addr, + &get_babylon_sdk_params(querier)?.btc_staking_contract_address, &btc_staking::msg::QueryMsg::ActivatedHeight {}, )?; let res: ActivatedHeightResponse = querier.query(&query)?; @@ -335,11 +345,15 @@ pub(crate) fn encode_smart_query( #[cfg(test)] pub(crate) mod tests { + + use super::*; + + use babylon_bindings_test::mock_dependencies; use cosmwasm_std::{ from_json, - testing::{message_info, mock_dependencies, mock_env}, + testing::{message_info, mock_env}, }; use cw_controllers::AdminResponse; diff --git a/contracts/btc-finality/src/finality.rs b/contracts/btc-finality/src/finality.rs index 7214b52f..e1b59659 100644 --- a/contracts/btc-finality/src/finality.rs +++ b/contracts/btc-finality/src/finality.rs @@ -9,6 +9,7 @@ use crate::state::public_randomness::{ }; use babylon_apis::btc_staking_api::FinalityProvider; use babylon_apis::finality_api::{Evidence, IndexedBlock, PubRandCommit}; +use babylon_bindings::query::{get_babylon_sdk_params, BabylonQuery}; use babylon_bindings::BabylonMsg; use babylon_merkle::Proof; use btc_staking::msg::{FinalityProviderInfo, FinalityProvidersByPowerResponse}; @@ -25,7 +26,7 @@ use std::collections::HashSet; use std::ops::Mul; pub fn handle_public_randomness_commit( - deps: DepsMut, + deps: DepsMut, fp_pubkey_hex: &str, start_height: u64, num_pub_rand: u64, @@ -39,12 +40,14 @@ pub fn handle_public_randomness_commit( } // TODO: ensure log_2(num_pub_rand) is an integer? + let params = get_babylon_sdk_params(&deps.querier)?; + // Ensure the finality provider is registered // TODO: Use a raw query for performance and cost let _fp: FinalityProvider = deps .querier .query_wasm_smart( - CONFIG.load(deps.storage)?.staking, + ¶ms.btc_staking_contract_address, &btc_staking::msg::QueryMsg::FinalityProvider { btc_pk_hex: fp_pubkey_hex.to_string(), }, @@ -125,7 +128,7 @@ fn verify_commitment_signature( #[allow(clippy::too_many_arguments)] pub fn handle_finality_signature( - mut deps: DepsMut, + mut deps: DepsMut, env: Env, fp_btc_pk_hex: &str, height: u64, @@ -134,10 +137,11 @@ pub fn handle_finality_signature( block_app_hash: &[u8], signature: &[u8], ) -> Result, ContractError> { + let params = get_babylon_sdk_params(&deps.querier)?; + // Ensure the finality provider exists - let staking_addr = CONFIG.load(deps.storage)?.staking; let fp: FinalityProvider = deps.querier.query_wasm_smart( - staking_addr.clone(), + ¶ms.btc_staking_contract_address, &btc_staking::msg::QueryMsg::FinalityProvider { btc_pk_hex: fp_btc_pk_hex.to_string(), }, @@ -171,7 +175,7 @@ pub fn handle_finality_signature( let fp: FinalityProviderInfo = deps .querier .query_wasm_smart( - staking_addr.clone(), + ¶ms.btc_staking_contract_address, &btc_staking::msg::QueryMsg::FinalityProviderInfo { btc_pk_hex: fp_btc_pk_hex.to_string(), height: Some(height), @@ -290,7 +294,7 @@ pub fn handle_finality_signature( /// `slash_finality_provider` slashes a finality provider with the given evidence including setting /// its voting power to zero, extracting its BTC SK, and emitting an event fn slash_finality_provider( - deps: &mut DepsMut, + deps: &mut DepsMut, fp_btc_pk_hex: &str, evidence: &Evidence, ) -> Result<(WasmMsg, Event), ContractError> { @@ -312,7 +316,8 @@ fn slash_finality_provider( evidence: evidence.clone(), }; - let babylon_addr = CONFIG.load(deps.storage)?.babylon; + let params = get_babylon_sdk_params(&deps.querier)?; + let babylon_addr = ¶ms.babylon_contract_address; let wasm_msg = WasmMsg::Execute { contract_addr: babylon_addr.to_string(), @@ -392,7 +397,7 @@ fn msg_to_sign(height: u64, block_hash: &[u8]) -> Vec { } pub fn index_block( - deps: &mut DepsMut, + deps: &mut DepsMut, height: u64, app_hash: &[u8], ) -> Result { @@ -421,7 +426,7 @@ pub fn index_block( /// /// It must be invoked only after the BTC staking protocol is activated. pub fn tally_blocks( - deps: &mut DepsMut, + deps: &mut DepsMut, env: &Env, activated_height: u64, ) -> Result<(Option, Vec), ContractError> { @@ -485,6 +490,8 @@ pub fn tally_blocks( } } + let params = get_babylon_sdk_params(&deps.querier)?; + // Compute block rewards for finalized blocks let msg = if finalized_blocks > 0 { let cfg = CONFIG.load(deps.storage)?; @@ -492,7 +499,7 @@ pub fn tally_blocks( // Assemble mint message let mint_msg = BabylonMsg::MintRewards { amount: rewards, - recipient: env.contract.address.to_string(), + recipient: params.btc_staking_contract_address.into(), }; Some(mint_msg) } else { @@ -539,7 +546,7 @@ fn finalize_block( /// `compute_block_rewards` computes the block rewards for the finality providers fn compute_block_rewards( - deps: &mut DepsMut, + deps: &mut DepsMut, cfg: &Config, finalized_blocks: u64, ) -> Result { @@ -567,13 +574,20 @@ const QUERY_LIMIT: Option = Some(30); /// `compute_active_finality_providers` sorts all finality providers, counts the total voting /// power of top finality providers, and records them in the contract state pub fn compute_active_finality_providers( - deps: &mut DepsMut, + deps: &mut DepsMut, height: u64, max_active_fps: usize, ) -> Result<(), ContractError> { + let params = get_babylon_sdk_params(&deps.querier)?; + let cfg = CONFIG.load(deps.storage)?; // Get all finality providers from the staking contract, filtered - let mut batch = list_fps_by_power(&cfg.staking, &deps.querier, None, QUERY_LIMIT)?; + let mut batch = list_fps_by_power( + ¶ms.btc_staking_contract_address, + &deps.querier, + None, + QUERY_LIMIT, + )?; let mut finality_providers = vec![]; let mut total_power: u64 = 0; @@ -595,7 +609,12 @@ pub fn compute_active_finality_providers( total_power = running_total.last().copied().unwrap_or_default(); // and get the next page - batch = list_fps_by_power(&cfg.staking, &deps.querier, last, QUERY_LIMIT)?; + batch = list_fps_by_power( + ¶ms.btc_staking_contract_address, + &deps.querier, + last, + QUERY_LIMIT, + )?; } // TODO: Online FPs verification @@ -609,7 +628,7 @@ pub fn compute_active_finality_providers( pub fn list_fps_by_power( staking_addr: &Addr, - querier: &QuerierWrapper, + querier: &QuerierWrapper, start_after: Option, limit: Option, ) -> StdResult> { @@ -622,7 +641,10 @@ pub fn list_fps_by_power( } /// `distribute_rewards` distributes rewards to finality providers who are in the active set at `height` -pub fn distribute_rewards(deps: &mut DepsMut, env: &Env) -> Result<(), ContractError> { +pub fn distribute_rewards( + deps: &mut DepsMut, + env: &Env, +) -> Result<(), ContractError> { // Try to use the finality provider set at the previous height let active_fps = FP_SET.may_load(deps.storage, env.block.height - 1)?; // Short-circuit if there are no active finality providers diff --git a/contracts/btc-finality/src/multitest.rs b/contracts/btc-finality/src/multitest.rs index f83f4bec..b36fbba6 100644 --- a/contracts/btc-finality/src/multitest.rs +++ b/contracts/btc-finality/src/multitest.rs @@ -1,6 +1,5 @@ mod suite; -use cosmwasm_std::Addr; use suite::SuiteBuilder; // Some multi-test default settings @@ -20,17 +19,11 @@ mod instantiation { let suite = SuiteBuilder::new().build(); // Confirm the btc-staking contract has been instantiated and set - let config = suite.get_babylon_config(); - assert_eq!(config.btc_staking, Some(Addr::unchecked(CONTRACT1_ADDR))); - // Confirm the btc-finality contract has been instantiated and set - assert_eq!(config.btc_finality, Some(Addr::unchecked(CONTRACT2_ADDR))); + let _config = suite.get_babylon_config(); // Check that the btc-staking contract was initialized correctly - let btc_staking_config = suite.get_btc_staking_config(); - assert_eq!(btc_staking_config.babylon, Addr::unchecked(CONTRACT0_ADDR)); - + let _btc_staking_config = suite.get_btc_staking_config(); // Check that the btc-finality contract was initialized correctly - let btc_finality_config = suite.get_btc_finality_config(); - assert_eq!(btc_finality_config.babylon, Addr::unchecked(CONTRACT0_ADDR)); + let _btc_finality_config = suite.get_btc_finality_config(); } } diff --git a/contracts/btc-finality/src/multitest/suite.rs b/contracts/btc-finality/src/multitest/suite.rs index b7da971a..bb4bdb76 100644 --- a/contracts/btc-finality/src/multitest/suite.rs +++ b/contracts/btc-finality/src/multitest/suite.rs @@ -1,8 +1,9 @@ use anyhow::Result as AnyResult; +use babylon_bindings::query::BabylonQuery; use derivative::Derivative; use hex::ToHex; -use cosmwasm_std::{to_json_binary, Addr, Coin}; +use cosmwasm_std::{Addr, Coin}; use cw_multi_test::{AppResponse, Contract, ContractWrapper, Executor}; @@ -18,7 +19,7 @@ use btc_staking::msg::{ActivatedHeightResponse, FinalityProviderInfo}; use crate::msg::{EvidenceResponse, FinalitySignatureResponse}; use crate::multitest::{CONTRACT1_ADDR, CONTRACT2_ADDR}; -fn contract_btc_staking() -> Box> { +fn contract_btc_staking() -> Box> { let contract = ContractWrapper::new( btc_staking::contract::execute, btc_staking::contract::instantiate, @@ -27,7 +28,7 @@ fn contract_btc_staking() -> Box> { Box::new(contract) } -fn contract_btc_finality() -> Box> { +fn contract_btc_finality() -> Box> { let contract = ContractWrapper::new( crate::contract::execute, crate::contract::instantiate, @@ -37,13 +38,12 @@ fn contract_btc_finality() -> Box> { Box::new(contract) } -fn contract_babylon() -> Box> { +fn contract_babylon() -> Box> { let contract = ContractWrapper::new( babylon_contract::execute, babylon_contract::instantiate, babylon_contract::query, ) - .with_reply(babylon_contract::reply) .with_migrate(babylon_contract::migrate); Box::new(contract) } @@ -68,7 +68,8 @@ impl SuiteBuilder { #[track_caller] pub fn build(self) -> Suite { - let owner = Addr::unchecked("owner"); + let owner = + Addr::unchecked("cosmwasm19mfs8tl4s396u7vqw9rrnsmrrtca5r66p7v8jvwdxvjn3shcmllqupdgxu"); let mut app = BabylonApp::new_at_height(owner.as_str(), self.height.unwrap_or(1)); @@ -84,8 +85,9 @@ impl SuiteBuilder { let btc_finality_code_id = app.store_code_with_creator(owner.clone(), contract_btc_finality()); let contract_code_id = app.store_code_with_creator(owner.clone(), contract_babylon()); - let staking_params = btc_staking::test_utils::staking_params(); - let contract = app + + // instantiate Babylon contract + let babylon_contract_addr = app .instantiate_contract( contract_code_id, owner.clone(), @@ -95,16 +97,6 @@ impl SuiteBuilder { btc_confirmation_depth: 1, checkpoint_finalization_timeout: 10, notify_cosmos_zone: false, - btc_staking_code_id: Some(btc_staking_code_id), - btc_staking_msg: Some( - to_json_binary(&btc_staking::msg::InstantiateMsg { - params: Some(staking_params), - admin: None, - }) - .unwrap(), - ), - btc_finality_code_id: Some(btc_finality_code_id), - btc_finality_msg: None, admin: Some(owner.to_string()), consumer_name: Some("TestConsumer".to_string()), consumer_description: Some("Test Consumer Description".to_string()), @@ -116,12 +108,43 @@ impl SuiteBuilder { ) .unwrap(); + // instantiate BTC Staking contract + let staking_params = btc_staking::test_utils::staking_params(); + let staking_contract_addr = app + .instantiate_contract( + btc_staking_code_id, + owner.clone(), + &btc_staking::msg::InstantiateMsg { + admin: Some(owner.to_string()), + params: Some(staking_params), + }, + &[], + "btc-staking", + Some(owner.to_string()), + ) + .unwrap(); + + // instantiate BTC Finality contract + let finality_contract_addr = app + .instantiate_contract( + btc_finality_code_id, + owner.clone(), + &crate::msg::InstantiateMsg { + admin: Some(owner.to_string()), + params: Some(crate::state::config::Params::default()), + }, + &[], + "btc-finality", + Some(owner.to_string()), + ) + .unwrap(); + Suite { app, code_id: contract_code_id, - babylon: contract, - staking: Addr::unchecked(CONTRACT1_ADDR), - finality: Addr::unchecked(CONTRACT2_ADDR), + babylon: babylon_contract_addr, + staking: staking_contract_addr, + finality: finality_contract_addr, owner, } } diff --git a/contracts/btc-finality/src/queries.rs b/contracts/btc-finality/src/queries.rs index f6774f8e..8f6702bd 100644 --- a/contracts/btc-finality/src/queries.rs +++ b/contracts/btc-finality/src/queries.rs @@ -1,3 +1,4 @@ +use babylon_bindings::query::BabylonQuery; use cosmwasm_std::Order::{Ascending, Descending}; use cosmwasm_std::{Deps, StdResult}; use cw_storage_plus::Bound; @@ -10,11 +11,11 @@ use crate::state::config::{Config, Params}; use crate::state::config::{CONFIG, PARAMS}; use crate::state::finality::{BLOCKS, EVIDENCES, SIGNATURES}; -pub fn config(deps: Deps) -> StdResult { +pub fn config(deps: Deps) -> StdResult { CONFIG.load(deps.storage) } -pub fn params(deps: Deps) -> StdResult { +pub fn params(deps: Deps) -> StdResult { PARAMS.load(deps.storage) } @@ -23,7 +24,7 @@ const MAX_LIMIT: u32 = 30; const DEFAULT_LIMIT: u32 = 10; pub fn finality_signature( - deps: Deps, + deps: Deps, btc_pk_hex: String, height: u64, ) -> StdResult { @@ -35,7 +36,7 @@ pub fn finality_signature( } } -pub fn block(deps: Deps, height: u64) -> StdResult { +pub fn block(deps: Deps, height: u64) -> StdResult { BLOCKS.load(deps.storage, height) } @@ -44,7 +45,7 @@ pub fn block(deps: Deps, height: u64) -> StdResult { /// `finalised`: List only finalised blocks if true, otherwise list all blocks. /// `reverse`: List in descending order if present and true, otherwise in ascending order. pub fn blocks( - deps: Deps, + deps: Deps, start_after: Option, limit: Option, finalised: Option, @@ -73,7 +74,11 @@ pub fn blocks( Ok(BlocksResponse { blocks }) } -pub fn evidence(deps: Deps, btc_pk_hex: String, height: u64) -> StdResult { +pub fn evidence( + deps: Deps, + btc_pk_hex: String, + height: u64, +) -> StdResult { let evidence = EVIDENCES.may_load(deps.storage, (&btc_pk_hex, height))?; Ok(EvidenceResponse { evidence }) } diff --git a/contracts/btc-finality/src/state/config.rs b/contracts/btc-finality/src/state/config.rs index eb6626ed..669bf3ae 100644 --- a/contracts/btc-finality/src/state/config.rs +++ b/contracts/btc-finality/src/state/config.rs @@ -1,7 +1,7 @@ use derivative::Derivative; use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Decimal}; +use cosmwasm_std::Decimal; use cw_controllers::Admin; use cw_storage_plus::Item; @@ -17,8 +17,6 @@ pub(crate) const ADMIN: Admin = Admin::new("admin"); pub struct Config { pub denom: String, pub blocks_per_year: u64, - pub babylon: Addr, - pub staking: Addr, } // TODO: Add / enable param entries as needed diff --git a/contracts/btc-staking/Cargo.toml b/contracts/btc-staking/Cargo.toml index f0e0486d..1932ae0c 100644 --- a/contracts/btc-staking/Cargo.toml +++ b/contracts/btc-staking/Cargo.toml @@ -39,6 +39,7 @@ full-validation = [] [dependencies] babylon-apis = { path = "../../packages/apis" } babylon-bindings = { path = "../../packages/bindings" } +babylon-bindings-test = { path = "../../packages/bindings-test" } babylon-contract = { path = "../babylon", features = [ "library" ] } babylon-merkle = { path = "../../packages/merkle" } babylon-proto = { path = "../../packages/proto" } diff --git a/contracts/btc-staking/src/contract.rs b/contracts/btc-staking/src/contract.rs index 8404279b..87c5e315 100644 --- a/contracts/btc-staking/src/contract.rs +++ b/contracts/btc-staking/src/contract.rs @@ -1,3 +1,4 @@ +use babylon_bindings::query::BabylonQuery; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ @@ -20,15 +21,13 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - mut deps: DepsMut, + mut deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg, ) -> Result, ContractError> { nonpayable(&info)?; - let config = Config { - babylon: info.sender, - }; + let config = Config {}; CONFIG.save(deps.storage, &config)?; let api = deps.api; @@ -43,12 +42,16 @@ pub fn instantiate( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn reply(_deps: DepsMut, _env: Env, _reply: Reply) -> StdResult { +pub fn reply(_deps: DepsMut, _env: Env, _reply: Reply) -> StdResult { Ok(Response::default()) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { +pub fn query( + deps: Deps, + _env: Env, + msg: QueryMsg, +) -> Result { match msg { QueryMsg::Config {} => Ok(to_json_binary(&queries::config(deps)?)?), QueryMsg::Params {} => Ok(to_json_binary(&queries::params(deps)?)?), @@ -90,13 +93,13 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result StdResult { +pub fn migrate(_deps: DepsMut, _env: Env, _msg: Empty) -> StdResult { Ok(Response::default()) } #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -128,9 +131,10 @@ pub fn execute( pub mod tests { use super::*; + use babylon_bindings_test::mock_dependencies; use cosmwasm_std::{ from_json, - testing::{message_info, mock_dependencies, mock_env}, + testing::{message_info, mock_env}, }; use cw_controllers::AdminResponse; diff --git a/contracts/btc-staking/src/queries.rs b/contracts/btc-staking/src/queries.rs index 1cbab505..1a17d02d 100644 --- a/contracts/btc-staking/src/queries.rs +++ b/contracts/btc-staking/src/queries.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use babylon_bindings::query::BabylonQuery; use bitcoin::hashes::Hash; use bitcoin::Txid; @@ -20,15 +21,18 @@ use crate::state::staking::{ fps, BtcDelegation, FinalityProviderState, ACTIVATED_HEIGHT, DELEGATIONS, FPS, FP_DELEGATIONS, }; -pub fn config(deps: Deps) -> StdResult { +pub fn config(deps: Deps) -> StdResult { CONFIG.load(deps.storage) } -pub fn params(deps: Deps) -> StdResult { +pub fn params(deps: Deps) -> StdResult { PARAMS.load(deps.storage) } -pub fn finality_provider(deps: Deps, btc_pk_hex: String) -> StdResult { +pub fn finality_provider( + deps: Deps, + btc_pk_hex: String, +) -> StdResult { FPS.load(deps.storage, &btc_pk_hex) } @@ -37,7 +41,7 @@ const MAX_LIMIT: u32 = 30; const DEFAULT_LIMIT: u32 = 10; pub fn finality_providers( - deps: Deps, + deps: Deps, start_after: Option, limit: Option, ) -> StdResult { @@ -53,7 +57,10 @@ pub fn finality_providers( /// Get the delegation info by staking tx hash. /// `staking_tx_hash_hex`: The (reversed) staking tx hash, in hex -pub fn delegation(deps: Deps, staking_tx_hash_hex: String) -> Result { +pub fn delegation( + deps: Deps, + staking_tx_hash_hex: String, +) -> Result { let staking_tx_hash = Txid::from_str(&staking_tx_hash_hex)?; Ok(DELEGATIONS.load(deps.storage, staking_tx_hash.as_ref())?) } @@ -62,7 +69,7 @@ pub fn delegation(deps: Deps, staking_tx_hash_hex: String) -> Result, start_after: Option, limit: Option, active: Option, @@ -94,7 +101,7 @@ pub fn delegations( /// /// `btc_pk_hex`: The BTC public key of the finality provider, in hex pub fn delegations_by_fp( - deps: Deps, + deps: Deps, btc_pk_hex: String, ) -> Result { let tx_hashes = FP_DELEGATIONS.load(deps.storage, &btc_pk_hex)?; @@ -113,7 +120,7 @@ pub fn delegations_by_fp( /// `btc_pk_hex`: The BTC public key of the finality provider, in hex. /// `active` is a filter to return only active delegations pub fn active_delegations_by_fp( - deps: Deps, + deps: Deps, btc_pk_hex: String, active: bool, ) -> Result { @@ -133,7 +140,7 @@ pub fn active_delegations_by_fp( } pub fn finality_provider_info( - deps: Deps, + deps: Deps, btc_pk_hex: String, height: Option, ) -> Result { @@ -150,7 +157,7 @@ pub fn finality_provider_info( } pub fn finality_providers_by_power( - deps: Deps, + deps: Deps, start_after: Option, limit: Option, ) -> StdResult { @@ -170,7 +177,9 @@ pub fn finality_providers_by_power( Ok(FinalityProvidersByPowerResponse { fps }) } -pub fn activated_height(deps: Deps) -> Result { +pub fn activated_height( + deps: Deps, +) -> Result { let activated_height = ACTIVATED_HEIGHT.may_load(deps.storage)?.unwrap_or_default(); Ok(ActivatedHeightResponse { height: activated_height, @@ -179,9 +188,10 @@ pub fn activated_height(deps: Deps) -> Result, env: Env, info: &MessageInfo, new_fps: &[NewFinalityProvider], @@ -37,8 +38,8 @@ pub fn handle_btc_staking( slashed_delegations: &[SlashedBtcDelegation], unbonded_delegations: &[UnbondedBtcDelegation], ) -> Result, ContractError> { - let config = CONFIG.load(deps.storage)?; - if info.sender != config.babylon && !ADMIN.is_admin(deps.as_ref(), &info.sender)? { + let babylon_addr = get_babylon_sdk_params(&deps.querier)?.babylon_contract_address; + if info.sender != babylon_addr && !ADMIN.is_admin(deps.as_ref(), &info.sender)? { return Err(ContractError::Unauthorized); } @@ -310,13 +311,13 @@ fn handle_slashed_delegation( /// handle_slash_fp handles FP slashing at the staking level pub fn handle_slash_fp( - deps: DepsMut, + deps: DepsMut, env: Env, info: &MessageInfo, fp_btc_pk_hex: &str, ) -> Result, ContractError> { - let config = CONFIG.load(deps.storage)?; - if info.sender != config.babylon && !ADMIN.is_admin(deps.as_ref(), &info.sender)? { + let babylon_addr = get_babylon_sdk_params(&deps.querier)?.babylon_contract_address; + if info.sender != babylon_addr && !ADMIN.is_admin(deps.as_ref(), &info.sender)? { return Err(ContractError::Unauthorized); } slash_finality_provider(deps, env, fp_btc_pk_hex) @@ -348,7 +349,7 @@ fn btc_undelegate( /// `slash_finality_provider` slashes a finality provider with the given PK. /// A slashed finality provider will not have voting power pub(crate) fn slash_finality_provider( - deps: DepsMut, + deps: DepsMut, env: Env, fp_btc_pk_hex: &str, ) -> Result, ContractError> { @@ -388,9 +389,9 @@ pub(crate) fn slash_finality_provider( } /// get_btc_tip_height queries the Babylon contract for the latest BTC tip height -fn get_btc_tip_height(deps: &DepsMut) -> Result { +fn get_btc_tip_height(deps: &DepsMut) -> Result { // Get the BTC tip from the babylon contract through a raw query - let babylon_addr = CONFIG.load(deps.storage)?.babylon; + let babylon_addr = get_babylon_sdk_params(&deps.querier)?.babylon_contract_address; // Query the Babylon contract // TODO: use a raw query for performance / efficiency @@ -404,7 +405,8 @@ fn get_btc_tip_height(deps: &DepsMut) -> Result { pub(crate) mod tests { use super::*; - use cosmwasm_std::testing::{message_info, mock_dependencies, mock_env}; + use babylon_bindings_test::mock_dependencies; + use cosmwasm_std::testing::{message_info, mock_env}; use test_utils::{ create_new_finality_provider, create_new_fp_sk, get_active_btc_delegation, @@ -505,7 +507,8 @@ pub(crate) mod tests { #[test] fn active_delegation_happy_path() { let mut deps = mock_dependencies(); - let info = message_info(&deps.api.addr_make(CREATOR), &[]); + let admin = deps.api.addr_make(CREATOR); + let info = message_info(&admin, &[]); let params = staking_params(); instantiate( @@ -514,7 +517,7 @@ pub(crate) mod tests { info.clone(), InstantiateMsg { params: Some(params), - admin: None, + admin: Some(admin.to_string()), }, ) .unwrap(); @@ -570,7 +573,8 @@ pub(crate) mod tests { #[test] fn undelegation_works() { let mut deps = mock_dependencies(); - let info = message_info(&deps.api.addr_make(CREATOR), &[]); + let admin = deps.api.addr_make(CREATOR); + let info = message_info(&admin, &[]); let params = staking_params(); instantiate( @@ -579,7 +583,7 @@ pub(crate) mod tests { info.clone(), InstantiateMsg { params: Some(params), - admin: None, + admin: Some(admin.to_string()), }, ) .unwrap(); @@ -669,7 +673,8 @@ pub(crate) mod tests { #[test] fn slashed_delegation_works() { let mut deps = mock_dependencies(); - let info = message_info(&deps.api.addr_make(CREATOR), &[]); + let admin = deps.api.addr_make(CREATOR); + let info = message_info(&admin, &[]); let params = staking_params(); instantiate( @@ -678,7 +683,7 @@ pub(crate) mod tests { info.clone(), InstantiateMsg { params: Some(params), - admin: None, + admin: Some(admin.to_string()), }, ) .unwrap(); diff --git a/contracts/btc-staking/src/state/config.rs b/contracts/btc-staking/src/state/config.rs index af2dfe5e..2ac7e65f 100644 --- a/contracts/btc-staking/src/state/config.rs +++ b/contracts/btc-staking/src/state/config.rs @@ -1,6 +1,5 @@ use babylon_bitcoin::chain_params::Network; use cosmwasm_schema::cw_serde; -use cosmwasm_std::Addr; use cw_controllers::Admin; use cw_storage_plus::Item; @@ -14,9 +13,7 @@ pub(crate) const ADMIN: Admin = Admin::new("admin"); /// Config are Babylon-selectable BTC staking configuration // TODO: Add / enable config entries as needed #[cw_serde] -pub struct Config { - pub babylon: Addr, -} +pub struct Config {} /// Params define Consumer-selectable BTC staking parameters // TODO: Add / enable param entries as needed diff --git a/contracts/btc-staking/src/state/fp_index.rs b/contracts/btc-staking/src/state/fp_index.rs index 04fa217c..1bf6ccd1 100644 --- a/contracts/btc-staking/src/state/fp_index.rs +++ b/contracts/btc-staking/src/state/fp_index.rs @@ -8,7 +8,7 @@ pub struct FinalityProviderIndexes<'a> { pub power: MultiIndex<'a, u64, FinalityProviderState, String>, } -impl<'a> IndexList for FinalityProviderIndexes<'a> { +impl IndexList for FinalityProviderIndexes<'_> { fn get_indexes( &'_ self, ) -> Box> + '_> { diff --git a/packages/bindings-test/src/lib.rs b/packages/bindings-test/src/lib.rs index 416def8e..f0c9a365 100644 --- a/packages/bindings-test/src/lib.rs +++ b/packages/bindings-test/src/lib.rs @@ -1,6 +1,43 @@ mod multitest; +use std::marker::PhantomData; + +use babylon_bindings::query::{BabylonQuery, ParamsResponse}; +use cosmwasm_std::{ + testing::{MockApi, MockQuerier, MockStorage}, + to_json_binary, Addr, ContractResult, OwnedDeps, SystemResult, +}; pub use multitest::{ mock_deps_babylon, BabylonApp, BabylonAppWrapped, BabylonDeps, BabylonError, BabylonModule, BLOCK_TIME, }; + +pub fn mock_dependencies( +) -> OwnedDeps, BabylonQuery> { + let custom_querier: MockQuerier = MockQuerier::new(&[("", &[])]) + .with_custom_handler(|query| { + // Handle your custom query type here + match query { + BabylonQuery::Params {} => { + // Return a mock response for the custom query + let response = ParamsResponse { + babylon_contract_address: Addr::unchecked(""), + btc_staking_contract_address: Addr::unchecked(""), + btc_finality_contract_address: Addr::unchecked(""), + babylon_contract_code_id: 0, + btc_staking_contract_code_id: 0, + btc_finality_contract_code_id: 0, + max_gas_begin_blocker: 0, + }; + SystemResult::Ok(ContractResult::Ok(to_json_binary(&response).unwrap())) + } + _ => panic!("Unsupported query type"), + } + }); + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: custom_querier, + custom_query_type: PhantomData, + } +} diff --git a/packages/bindings-test/src/multitest.rs b/packages/bindings-test/src/multitest.rs index 648bf82b..837f7ba0 100644 --- a/packages/bindings-test/src/multitest.rs +++ b/packages/bindings-test/src/multitest.rs @@ -1,4 +1,5 @@ use anyhow::{bail, Result as AnyResult}; +use babylon_bindings::query::ParamsResponse; use schemars::JsonSchema; use serde::de::DeserializeOwned; use std::cmp::max; @@ -7,7 +8,7 @@ use std::ops::{Deref, DerefMut}; use thiserror::Error; use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage}; -use cosmwasm_std::OwnedDeps; +use cosmwasm_std::{to_json_binary, OwnedDeps}; use std::marker::PhantomData; use cosmwasm_std::Order::Ascending; @@ -20,7 +21,7 @@ use cw_multi_test::{ }; use cw_storage_plus::{Item, Map}; -use babylon_bindings::{BabylonMsg, BabylonQuery}; +use babylon_bindings::{msg::BabylonMsg, query::BabylonQuery}; pub struct BabylonModule {} @@ -67,7 +68,7 @@ impl BabylonModule { impl Module for BabylonModule { type ExecT = BabylonMsg; - type QueryT = Empty; + type QueryT = BabylonQuery; type SudoT = Empty; fn execute( @@ -105,9 +106,22 @@ impl Module for BabylonModule { _storage: &dyn Storage, _querier: &dyn Querier, _block: &BlockInfo, - _request: BabylonQuery, + request: BabylonQuery, ) -> anyhow::Result { - bail!("query not implemented for BabylonModule") + match request { + BabylonQuery::Params {} => { + let response = ParamsResponse { + babylon_contract_address: Addr::unchecked(""), + btc_staking_contract_address: Addr::unchecked(""), + btc_finality_contract_address: Addr::unchecked(""), + babylon_contract_code_id: 0, + btc_staking_contract_code_id: 0, + btc_finality_contract_code_id: 0, + max_gas_begin_blocker: 0, + }; + Ok(to_json_binary(&response)?) + } + } } fn sudo( diff --git a/packages/bindings/Cargo.toml b/packages/bindings/Cargo.toml index 8773ef05..5aea99e1 100644 --- a/packages/bindings/Cargo.toml +++ b/packages/bindings/Cargo.toml @@ -9,6 +9,7 @@ homepage = "https://babylonlabs.io" license = "Apache-2.0" [dependencies] +anybuf = { workspace = true } cosmwasm-std = { workspace = true } cosmwasm-schema = { workspace = true } babylon-apis = { workspace = true } \ No newline at end of file diff --git a/packages/bindings/src/lib.rs b/packages/bindings/src/lib.rs index cf7d55ac..35b3591b 100644 --- a/packages/bindings/src/lib.rs +++ b/packages/bindings/src/lib.rs @@ -1,3 +1,4 @@ pub mod msg; +pub mod query; -pub use msg::{BabylonMsg, BabylonQuery, BabylonSudoMsg}; +pub use msg::{BabylonMsg, BabylonSudoMsg}; diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index 3b3c8d39..5438d9ae 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -52,8 +52,8 @@ pub enum BabylonMsg { } pub type BabylonSudoMsg = Empty; -pub type BabylonQuery = Empty; +// make BabylonMsg to implement CosmosMsg::CustomMsg // make BabylonMsg to implement CosmosMsg::CustomMsg impl cosmwasm_std::CustomMsg for BabylonMsg {} diff --git a/packages/bindings/src/query.rs b/packages/bindings/src/query.rs new file mode 100644 index 00000000..8a7a08ce --- /dev/null +++ b/packages/bindings/src/query.rs @@ -0,0 +1,53 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{ + from_json, to_json_binary, Addr, ContractResult, CustomQuery, QuerierWrapper, QueryRequest, + StdError, SystemResult, +}; + +#[cw_serde] +#[derive(QueryResponses)] +pub enum BabylonQuery { + #[returns(ParamsResponse)] + Params {}, +} + +// Implement required traits for BabylonQuery +impl CustomQuery for BabylonQuery {} + +#[cw_serde] +pub struct ParamsResponse { + /// babylon_contract_code_id is the code ID of the Babylon contract + pub babylon_contract_code_id: u64, + /// btc_staking_contract_code_id is the code ID of the BTC staking contract + pub btc_staking_contract_code_id: u64, + /// btc_finality_contract_code_id is the code ID of the BTC finality contract + pub btc_finality_contract_code_id: u64, + /// babylon_contract_address is the address of the Babylon contract + pub babylon_contract_address: Addr, + /// btc_staking_contract_address is the address of the BTC staking contract + pub btc_staking_contract_address: Addr, + /// btc_finality_contract_address is the address of the BTC finality contract + pub btc_finality_contract_address: Addr, + /// max_gas_begin_blocker defines the maximum gas that can be spent in a contract sudo callback + pub max_gas_begin_blocker: u32, +} + +pub fn get_babylon_sdk_params( + querier: &QuerierWrapper, +) -> Result { + let query = QueryRequest::Custom(BabylonQuery::Params {}); + let res = match querier.raw_query(&to_json_binary(&query)?) { + SystemResult::Err(system_err) => Err(StdError::generic_err(format!( + "Querier system error: {}", + system_err + ))), + SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!( + "Querier contract error: {}", + contract_err + ))), + SystemResult::Ok(ContractResult::Ok(value)) => Ok(value), + }?; + let params: ParamsResponse = from_json(&res)?; + + Ok(params) +} diff --git a/packages/proto/src/gen/babylon.zoneconcierge.v1.rs b/packages/proto/src/gen/babylon.zoneconcierge.v1.rs index a8a39e36..866c3383 100644 --- a/packages/proto/src/gen/babylon.zoneconcierge.v1.rs +++ b/packages/proto/src/gen/babylon.zoneconcierge.v1.rs @@ -4,35 +4,35 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct IndexedHeader { /// consumer_id is the unique ID of the consumer - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub consumer_id: ::prost::alloc::string::String, /// hash is the hash of this header - #[prost(bytes="bytes", tag="2")] + #[prost(bytes = "bytes", tag = "2")] pub hash: ::prost::bytes::Bytes, /// height is the height of this header on CZ ledger /// (hash, height) jointly provides the position of the header on CZ ledger - #[prost(uint64, tag="3")] + #[prost(uint64, tag = "3")] pub height: u64, /// time is the timestamp of this header on CZ ledger /// it is needed for CZ to unbond all mature validators/delegations /// before this timestamp when this header is BTC-finalised - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub time: ::core::option::Option<::pbjson_types::Timestamp>, /// babylon_header_hash is the hash of the babylon block that includes this CZ /// header - #[prost(bytes="bytes", tag="5")] + #[prost(bytes = "bytes", tag = "5")] pub babylon_header_hash: ::prost::bytes::Bytes, /// babylon_header_height is the height of the babylon block that includes this CZ /// header - #[prost(uint64, tag="6")] + #[prost(uint64, tag = "6")] pub babylon_header_height: u64, /// epoch is the epoch number of this header on Babylon ledger - #[prost(uint64, tag="7")] + #[prost(uint64, tag = "7")] pub babylon_epoch: u64, /// babylon_tx_hash is the hash of the tx that includes this header /// (babylon_block_height, babylon_tx_hash) jointly provides the position of /// the header on Babylon ledger - #[prost(bytes="bytes", tag="8")] + #[prost(bytes = "bytes", tag = "8")] pub babylon_tx_hash: ::prost::bytes::Bytes, } /// Forks is a list of non-canonical `IndexedHeader`s at the same height. @@ -53,7 +53,7 @@ pub struct IndexedHeader { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Forks { /// blocks is the list of non-canonical indexed headers at the same height - #[prost(message, repeated, tag="3")] + #[prost(message, repeated, tag = "3")] pub headers: ::prost::alloc::vec::Vec, } /// ChainInfo is the information of a CZ @@ -61,18 +61,18 @@ pub struct Forks { #[derive(Clone, PartialEq, ::prost::Message)] pub struct ChainInfo { /// consumer_id is the ID of the consumer - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub consumer_id: ::prost::alloc::string::String, /// latest_header is the latest header in CZ's canonical chain - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub latest_header: ::core::option::Option, /// latest_forks is the latest forks, formed as a series of IndexedHeader (from /// low to high) - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub latest_forks: ::core::option::Option, /// timestamped_headers_count is the number of timestamped headers in CZ's /// canonical chain - #[prost(uint64, tag="4")] + #[prost(uint64, tag = "4")] pub timestamped_headers_count: u64, } /// FinalizedChainInfo is the information of a CZ that is BTC-finalised @@ -80,23 +80,23 @@ pub struct ChainInfo { #[derive(Clone, PartialEq, ::prost::Message)] pub struct FinalizedChainInfo { /// consumer_id is the ID of the consumer - #[prost(string, tag="1")] + #[prost(string, tag = "1")] pub consumer_id: ::prost::alloc::string::String, /// finalized_chain_info is the info of the CZ - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub finalized_chain_info: ::core::option::Option, /// epoch_info is the metadata of the last BTC-finalised epoch - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub epoch_info: ::core::option::Option, /// raw_checkpoint is the raw checkpoint of this epoch - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub raw_checkpoint: ::core::option::Option, /// btc_submission_key is position of two BTC txs that include the raw /// checkpoint of this epoch - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub btc_submission_key: ::core::option::Option, /// proof is the proof that the chain info is finalized - #[prost(message, optional, tag="6")] + #[prost(message, optional, tag = "6")] pub proof: ::core::option::Option, } /// ProofEpochSealed is the proof that an epoch is sealed by the sealer header, @@ -115,15 +115,16 @@ pub struct ProofEpochSealed { /// validator_set is the validator set of the sealed epoch /// This validator set has generated a BLS multisig on `app_hash` of /// the sealer header - #[prost(message, repeated, tag="1")] - pub validator_set: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "1")] + pub validator_set: + ::prost::alloc::vec::Vec, /// proof_epoch_info is the Merkle proof that the epoch's metadata is committed /// to `app_hash` of the sealer header - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub proof_epoch_info: ::core::option::Option, /// proof_epoch_info is the Merkle proof that the epoch's validator set is /// committed to `app_hash` of the sealer header - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub proof_epoch_val_set: ::core::option::Option, } /// ProofFinalizedChainInfo is a set of proofs that attest a chain info is @@ -137,16 +138,17 @@ pub struct ProofEpochSealed { pub struct ProofFinalizedChainInfo { /// proof_cz_header_in_epoch is the proof that the CZ header is timestamped /// within a certain epoch - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub proof_cz_header_in_epoch: ::core::option::Option, /// proof_epoch_sealed is the proof that the epoch is sealed - #[prost(message, optional, tag="2")] + #[prost(message, optional, tag = "2")] pub proof_epoch_sealed: ::core::option::Option, /// proof_epoch_submitted is the proof that the epoch's checkpoint is included /// in BTC ledger It is the two TransactionInfo in the best (i.e., earliest) /// checkpoint submission - #[prost(message, repeated, tag="3")] - pub proof_epoch_submitted: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub proof_epoch_submitted: + ::prost::alloc::vec::Vec, } /// ZoneconciergePacketData is the message that defines the IBC packets of /// ZoneConcierge @@ -154,23 +156,25 @@ pub struct ProofFinalizedChainInfo { #[derive(Clone, PartialEq, ::prost::Message)] pub struct ZoneconciergePacketData { /// packet is the actual message carried in the IBC packet - #[prost(oneof="zoneconcierge_packet_data::Packet", tags="1, 2, 3, 4")] + #[prost(oneof = "zoneconcierge_packet_data::Packet", tags = "1, 2, 3, 4")] pub packet: ::core::option::Option, } /// Nested message and enum types in `ZoneconciergePacketData`. pub mod zoneconcierge_packet_data { /// packet is the actual message carried in the IBC packet #[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Packet { - #[prost(message, tag="1")] + #[prost(message, tag = "1")] BtcTimestamp(super::BtcTimestamp), - #[prost(message, tag="2")] + #[prost(message, tag = "2")] BtcStaking(super::super::super::btcstaking::v1::BtcStakingIbcPacket), - #[prost(message, tag="3")] + #[prost(message, tag = "3")] ConsumerSlashing(super::ConsumerSlashingIbcPacket), - #[prost(message, tag="4")] - ConsumerFpDistribution(cosmos_sdk_proto::ibc::applications::transfer::v2::FungibleTokenPacketData), + #[prost(message, tag = "4")] + ConsumerFpDistribution( + cosmos_sdk_proto::ibc::applications::transfer::v2::FungibleTokenPacketData, + ), } } /// BTCTimestamp is a BTC timestamp that carries information of a BTC-finalised epoch @@ -182,32 +186,30 @@ pub mod zoneconcierge_packet_data { #[derive(Clone, PartialEq, ::prost::Message)] pub struct BtcTimestamp { /// header is the last CZ header in the finalized Babylon epoch - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub header: ::core::option::Option, // // Data for BTC light client - /// btc_headers is BTC headers between /// - the block AFTER the common ancestor of BTC tip at epoch `lastFinalizedEpoch-1` and BTC tip at epoch `lastFinalizedEpoch` /// - BTC tip at epoch `lastFinalizedEpoch` /// where `lastFinalizedEpoch` is the last finalised epoch in Babylon - #[prost(message, repeated, tag="2")] + #[prost(message, repeated, tag = "2")] pub btc_headers: ::prost::alloc::vec::Vec, // // Data for Babylon epoch chain - /// epoch_info is the metadata of the sealed epoch - #[prost(message, optional, tag="3")] + #[prost(message, optional, tag = "3")] pub epoch_info: ::core::option::Option, /// raw_checkpoint is the raw checkpoint that seals this epoch - #[prost(message, optional, tag="4")] + #[prost(message, optional, tag = "4")] pub raw_checkpoint: ::core::option::Option, /// btc_submission_key is position of two BTC txs that include the raw checkpoint of this epoch - #[prost(message, optional, tag="5")] + #[prost(message, optional, tag = "5")] pub btc_submission_key: ::core::option::Option, /// /// Proofs that the header is finalized - #[prost(message, optional, tag="6")] + #[prost(message, optional, tag = "6")] pub proof: ::core::option::Option, } /// ConsumerSlashingIBCPacket defines the slashing information that a Consumer sends to Babylon's ZoneConcierge upon a @@ -217,7 +219,7 @@ pub struct BtcTimestamp { #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConsumerSlashingIbcPacket { /// / evidence is the FP slashing evidence that the Consumer sends to Babylon - #[prost(message, optional, tag="1")] + #[prost(message, optional, tag = "1")] pub evidence: ::core::option::Option, } /// QueryFinalizedChainsInfoResponse is response type for the @@ -225,7 +227,7 @@ pub struct ConsumerSlashingIbcPacket { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryFinalizedChainsInfoResponse { - #[prost(message, repeated, tag="1")] + #[prost(message, repeated, tag = "1")] pub finalized_chains_info: ::prost::alloc::vec::Vec, } // @@protoc_insertion_point(module)