diff --git a/Cargo.lock b/Cargo.lock index fd2e8edf..8793a47e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -721,6 +721,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "drop-lazy-staking" +version = "1.0.0" +dependencies = [ + "cosmos-sdk-proto", + "cosmwasm-schema", + "cosmwasm-std", + "cw-ownable", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "drop-helpers", + "drop-staking-base", + "neutron-sdk", + "semver", + "thiserror", +] + [[package]] name = "drop-lsm-share-bond-provider" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 2fc167b5..f4edcbc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "contracts/pump", "contracts/puppeteer", "contracts/puppeteer-initia", + "contracts/lazy-staking", # "contracts/puppeteer-authz", "contracts/rewards-manager", "contracts/strategy", diff --git a/contracts/factory/src/bin/drop-factory-schema.rs b/contracts/factory/src/bin/drop-factory-schema.rs index 5e026829..ed4e59a0 100644 --- a/contracts/factory/src/bin/drop-factory-schema.rs +++ b/contracts/factory/src/bin/drop-factory-schema.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::write_api; -use drop_factory::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use drop_staking_base::msg::factory::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; fn main() { write_api! { diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 451a01d2..78019227 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,17 +1,17 @@ -use crate::{ - error::ContractResult, - msg::{ - ExecuteMsg, InstantiateMsg, MigrateMsg, ProxyMsg, QueryMsg, UpdateConfigMsg, - ValidatorSetMsg, - }, - state::{State, STATE}, -}; +use crate::error::ContractResult; use cosmwasm_std::{ attr, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg, Deps, DepsMut, Env, HexBinary, MessageInfo, Response, StdResult, Uint128, WasmMsg, }; use drop_helpers::answer::response; use drop_staking_base::state::splitter::Config as SplitterConfig; +use drop_staking_base::{ + msg::factory::{ + ExecuteMsg, InstantiateMsg, MigrateMsg, ProxyMsg, QueryMsg, UpdateConfigMsg, + ValidatorSetMsg, + }, + state::factory::{State, STATE}, +}; use drop_staking_base::{ msg::{ core::{InstantiateMsg as CoreInstantiateMsg, QueryMsg as CoreQueryMsg}, @@ -462,7 +462,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult) -> StdResult { let state = STATE.load(deps.storage)?; - to_json_binary(&crate::state::PauseInfoResponse { + to_json_binary(&drop_staking_base::state::factory::PauseInfoResponse { core: deps .querier .query_wasm_smart(state.core_contract, &CoreQueryMsg::Pause {})?, @@ -670,7 +670,7 @@ pub fn migrate( } fn get_splitter_receivers( - fee_params: Option, + fee_params: Option, bond_provider_address: String, ) -> ContractResult> { match fee_params { diff --git a/contracts/factory/src/lib.rs b/contracts/factory/src/lib.rs index ce584245..19b07e61 100644 --- a/contracts/factory/src/lib.rs +++ b/contracts/factory/src/lib.rs @@ -1,6 +1,4 @@ pub mod contract; pub mod error; -pub mod msg; -pub mod state; #[cfg(test)] pub mod tests; diff --git a/contracts/factory/src/tests.rs b/contracts/factory/src/tests.rs index 780bafe5..d8f02027 100644 --- a/contracts/factory/src/tests.rs +++ b/contracts/factory/src/tests.rs @@ -1,17 +1,17 @@ -use crate::{ - contract::{execute, instantiate, query}, - msg::{ - CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, - QueryMsg, UpdateConfigMsg, ValidatorSetMsg, - }, - state::{CodeIds, RemoteOpts, State, Timeout, STATE}, -}; +use crate::contract::{execute, instantiate, query}; use cosmwasm_std::{ attr, from_json, testing::{mock_env, mock_info}, to_json_binary, BankMsg, Uint128, }; use drop_helpers::testing::{mock_dependencies, mock_dependencies_with_api}; +use drop_staking_base::{ + msg::factory::{ + CoreParams, ExecuteMsg, FeeParams, InstantiateMsg, LsmShareBondParams, NativeBondParams, + QueryMsg, UpdateConfigMsg, ValidatorSetMsg, + }, + state::factory::{CodeIds, RemoteOpts, State, Timeout, STATE}, +}; use drop_staking_base::{ msg::{ core::{ExecuteMsg as CoreExecuteMsg, InstantiateMsg as CoreInstantiateMsg}, @@ -707,7 +707,7 @@ fn test_proxy_validators_set_update_validators_unauthorized() { deps.as_mut().into_empty(), mock_env(), mock_info("not_an_owner", &[]), - ExecuteMsg::Proxy(crate::msg::ProxyMsg::ValidatorSet( + ExecuteMsg::Proxy(drop_staking_base::msg::factory::ProxyMsg::ValidatorSet( ValidatorSetMsg::UpdateValidators { validators: vec![ drop_staking_base::msg::validatorset::ValidatorData { @@ -744,7 +744,7 @@ fn test_proxy_validators_set_update_validators() { deps.as_mut().into_empty(), mock_env(), mock_info("owner", &[]), - ExecuteMsg::Proxy(crate::msg::ProxyMsg::ValidatorSet( + ExecuteMsg::Proxy(drop_staking_base::msg::factory::ProxyMsg::ValidatorSet( ValidatorSetMsg::UpdateValidators { validators: vec![ drop_staking_base::msg::validatorset::ValidatorData { @@ -1091,7 +1091,7 @@ fn test_query_state() { STATE .save(deps.as_mut().storage, &get_default_factory_state()) .unwrap(); - let query_res: crate::state::State = + let query_res: drop_staking_base::state::factory::State = from_json(query(deps.as_ref(), mock_env(), QueryMsg::State {}).unwrap()).unwrap(); assert_eq!(query_res, get_default_factory_state()); } @@ -1121,11 +1121,11 @@ fn test_query_pause_info() { STATE .save(deps.as_mut().storage, &get_default_factory_state()) .unwrap(); - let query_res: crate::state::PauseInfoResponse = + let query_res: drop_staking_base::state::factory::PauseInfoResponse = from_json(query(deps.as_ref(), mock_env(), QueryMsg::PauseInfo {}).unwrap()).unwrap(); assert_eq!( query_res, - crate::state::PauseInfoResponse { + drop_staking_base::state::factory::PauseInfoResponse { core: CorePause { tick: true, bond: false, @@ -1146,7 +1146,7 @@ fn test_query_ownership() { query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Ownership {}, + drop_staking_base::msg::factory::QueryMsg::Ownership {}, ) .unwrap(), ) @@ -1187,7 +1187,7 @@ fn test_transfer_ownership() { query( deps.as_ref(), mock_env(), - crate::msg::QueryMsg::Ownership {}, + drop_staking_base::msg::factory::QueryMsg::Ownership {}, ) .unwrap(), ) diff --git a/contracts/lazy-staking/Cargo.toml b/contracts/lazy-staking/Cargo.toml new file mode 100644 index 00000000..85327949 --- /dev/null +++ b/contracts/lazy-staking/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["Vladislav Vasilev "] +description = "Contract to mint lazy token" +edition = "2021" +name = "drop-lazy-staking" +version = "1.0.0" + +exclude = [ + "contract.wasm", + "hash.txt", +] + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +backtraces = ["cosmwasm-std/backtraces"] +library = [] + +[dependencies] +cw2 = { workspace = true } +neutron-sdk = { workspace = true } +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-ownable = { workspace = true } +thiserror = { workspace = true } +cw-utils = { workspace = true } +cw-storage-plus = { workspace = true } +semver = { workspace = true } +cosmos-sdk-proto = { workspace = true } +drop-helpers = { workspace = true } +drop-staking-base = { workspace = true } \ No newline at end of file diff --git a/contracts/lazy-staking/README.md b/contracts/lazy-staking/README.md new file mode 100644 index 00000000..69859814 --- /dev/null +++ b/contracts/lazy-staking/README.md @@ -0,0 +1 @@ +# Drop Lazy Staking diff --git a/contracts/lazy-staking/src/bin/drop-lazy-staking-schema.rs b/contracts/lazy-staking/src/bin/drop-lazy-staking-schema.rs new file mode 100644 index 00000000..ea1e60c9 --- /dev/null +++ b/contracts/lazy-staking/src/bin/drop-lazy-staking-schema.rs @@ -0,0 +1,11 @@ +use cosmwasm_schema::write_api; +use drop_lazy_staking::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + query: QueryMsg, + execute: ExecuteMsg, + migrate: MigrateMsg + } +} diff --git a/contracts/lazy-staking/src/contract.rs b/contracts/lazy-staking/src/contract.rs new file mode 100644 index 00000000..7bb67273 --- /dev/null +++ b/contracts/lazy-staking/src/contract.rs @@ -0,0 +1,179 @@ +use crate::{ + error::{ContractError, ContractResult}, + msg::{ExecuteMsg, InstantiateMsg, QueryMsg}, + state::{CONFIG, CREATE_DENOM_REPLY_ID, DENOM, EXCHANGE_RATE, EXPONENT, TOKEN_METADATA}, +}; +use cosmos_sdk_proto::cosmos::bank::v1beta1::{DenomUnit, Metadata}; +use cosmwasm_std::{ + attr, entry_point, to_json_binary, Attribute, Binary, CosmosMsg, Decimal, DenomMetadata, Deps, + DepsMut, Env, MessageInfo, Reply, Response, StdResult, SubMsg, +}; +use drop_helpers::answer::response; +use drop_staking_base::{ + msg::{core::QueryMsg as CoreQueryMsg, factory::QueryMsg as FactoryQueryMsg}, + state::factory::State as FactoryState, +}; +use neutron_sdk::{ + bindings::{msg::NeutronMsg, query::NeutronQuery}, + query::token_factory::query_full_denom, + stargate::aux::create_stargate_msg, +}; + +const CONTRACT_NAME: &str = concat!("crates.io:drop-helper__", env!("CARGO_PKG_NAME")); +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> ContractResult> { + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + cw_ownable::initialize_owner(deps.storage, deps.api, Some(info.sender.as_str()))?; + msg.config.validate_base_denom(deps.as_ref())?; + msg.config.validate_splitting_targets(deps.as_ref())?; + msg.config.validate_factory_addr(deps.as_ref())?; + + CONFIG.save(deps.storage, &msg.config)?; + EXCHANGE_RATE.save(deps.storage, &Decimal::one())?; + DENOM.save(deps.storage, &msg.subdenom)?; + EXPONENT.save(deps.storage, &msg.exponent)?; + TOKEN_METADATA.save(deps.storage, &msg.token_metadata)?; + + let create_denom_submsg = SubMsg::reply_on_success( + NeutronMsg::submit_create_denom(msg.subdenom), + CREATE_DENOM_REPLY_ID, + ); + Ok( + response("instantiate", CONTRACT_NAME, Vec::::new()) + .add_submessage(create_denom_submsg), + ) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::Ownership {} => Ok(to_json_binary( + &cw_ownable::get_ownership(deps.storage)?.owner, + )?), + } +} + +fn query_core_exchange_rate(deps: Deps) -> StdResult { + let config = CONFIG.load(deps.storage)?; + let factory_addr = config.factory_addr; + let factory_state: FactoryState = deps + .querier + .query_wasm_smart(factory_addr, &FactoryQueryMsg::State {})?; + let core_addr = factory_state.core_contract; + let core_exchange_rate: Decimal = deps + .querier + .query_wasm_smart(core_addr, &CoreQueryMsg::ExchangeRate {})?; + + Ok(core_exchange_rate) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> ContractResult> { + match msg { + ExecuteMsg::UpdateOwnership(action) => { + cw_ownable::update_ownership(deps.into_empty(), &env.block, &info.sender, action)?; + Ok(response::<(&str, &str), _>( + "execute-update-ownership", + CONTRACT_NAME, + [], + )) + } + ExecuteMsg::Bond => execute_bond(deps, info), + } +} + +fn execute_bond(deps: DepsMut, info: MessageInfo) -> ContractResult> { + let config = CONFIG.load(deps.storage)?; + let lazy_denom = DENOM.load(deps.storage)?; + + let core_exchange_rate = query_core_exchange_rate(deps.as_ref())?; + let sent_amount = cw_utils::must_pay(&info, &config.base_denom)?; + let issue_amount = sent_amount * core_exchange_rate; + + let attrs = vec![ + attr("action", "bond"), + attr("sent_amount", sent_amount.to_string()), + attr("exchange_rate", core_exchange_rate.to_string()), + attr("issue_amount", issue_amount.to_string()), + attr("receiver", info.sender.clone()), + ]; + let msg = NeutronMsg::submit_mint_tokens(lazy_denom, issue_amount, info.sender); + Ok(response("execute-bond", CONTRACT_NAME, attrs).add_message(msg)) +} + +#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)] +pub fn reply( + deps: DepsMut, + env: Env, + msg: Reply, +) -> ContractResult> { + match msg.id { + CREATE_DENOM_REPLY_ID => { + let subdenom = DENOM.load(deps.storage)?; + let full_denom = query_full_denom(deps.as_ref(), &env.contract.address, subdenom)?; + let token_metadata = TOKEN_METADATA.load(deps.storage)?; + let exponent = EXPONENT.load(deps.storage)?; + let msg = create_set_denom_metadata_msg( + env.contract.address.into_string(), + full_denom.denom.clone(), + token_metadata.clone(), + exponent, + ); + deps.api + .debug(&format!("WASMDEBUG: msg: {:?}", token_metadata)); + DENOM.save(deps.storage, &full_denom.denom)?; + TOKEN_METADATA.remove(deps.storage); + Ok(Response::new() + .add_attribute("full_denom", full_denom.denom) + .add_message(msg)) + } + id => Err(ContractError::UnknownReplyId { id }), + } +} + +fn create_set_denom_metadata_msg( + contract_address: String, + denom: String, + token_metadata: DenomMetadata, + exponent: u32, +) -> CosmosMsg { + create_stargate_msg( + "/osmosis.tokenfactory.v1beta1.MsgSetDenomMetadata", + neutron_sdk::proto_types::osmosis::tokenfactory::v1beta1::MsgSetDenomMetadata { + sender: contract_address, + metadata: Some(Metadata { + denom_units: vec![ + DenomUnit { + denom: denom.clone(), + exponent: 0, + aliases: vec![], + }, + DenomUnit { + denom: token_metadata.display.clone(), + exponent, + aliases: vec![], + }, + ], + base: denom, + display: token_metadata.display, + name: token_metadata.name, + description: token_metadata.description, + symbol: token_metadata.symbol, + uri: token_metadata.uri, + uri_hash: token_metadata.uri_hash, + }), + }, + ) +} diff --git a/contracts/lazy-staking/src/error.rs b/contracts/lazy-staking/src/error.rs new file mode 100644 index 00000000..116d72cc --- /dev/null +++ b/contracts/lazy-staking/src/error.rs @@ -0,0 +1,37 @@ +use cosmwasm_std::{OverflowError, StdError}; +use cw_ownable::OwnershipError; +use cw_utils::PaymentError; +use neutron_sdk::NeutronError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + #[error("{0}")] + NeutronError(#[from] NeutronError), + #[error("{0}")] + OwnershipError(#[from] OwnershipError), + #[error("Semver parsing error: {0}")] + SemVer(String), + #[error("Unauthorized")] + Unauthorized {}, + #[error("Base denom doesn't exist on chaining")] + BaseDenomError {}, + #[error("Invalid Address Given")] + InvalidAddressProvided {}, + #[error("{0}")] + OverflowError(#[from] OverflowError), + #[error("Unknown reply id {id}")] + UnknownReplyId { id: u64 }, + #[error("{0}")] + PaymentError(#[from] PaymentError), +} + +impl From for ContractError { + fn from(err: semver::Error) -> Self { + Self::SemVer(err.to_string()) + } +} + +pub type ContractResult = Result; diff --git a/contracts/lazy-staking/src/lib.rs b/contracts/lazy-staking/src/lib.rs new file mode 100644 index 00000000..f0e2fd34 --- /dev/null +++ b/contracts/lazy-staking/src/lib.rs @@ -0,0 +1,7 @@ +pub mod contract; +pub mod error; +pub mod msg; +pub mod state; + +#[cfg(test)] +mod tests; diff --git a/contracts/lazy-staking/src/msg.rs b/contracts/lazy-staking/src/msg.rs new file mode 100644 index 00000000..fa7c9166 --- /dev/null +++ b/contracts/lazy-staking/src/msg.rs @@ -0,0 +1,25 @@ +use crate::state::Config; +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::DenomMetadata; + +#[cw_serde] +pub struct InstantiateMsg { + pub config: Config, + pub token_metadata: DenomMetadata, + pub subdenom: String, + pub exponent: u32, +} + +#[cw_ownable::cw_ownable_query] +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg {} + +#[cw_ownable::cw_ownable_execute] +#[cw_serde] +pub enum ExecuteMsg { + Bond, +} + +#[cw_serde] +pub struct MigrateMsg {} diff --git a/contracts/lazy-staking/src/state.rs b/contracts/lazy-staking/src/state.rs new file mode 100644 index 00000000..9f466880 --- /dev/null +++ b/contracts/lazy-staking/src/state.rs @@ -0,0 +1,71 @@ +use crate::error::ContractError; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Addr, Decimal, DenomMetadata, Deps, Uint128}; +use cw_storage_plus::Item; + +#[cw_serde] +pub struct SplittingTarget { + pub addr: Addr, + pub unbonding_weight: Uint128, +} + +#[cw_serde] +pub struct Config { + pub factory_addr: Addr, + pub base_denom: String, + pub splitting_targets: Vec, +} + +impl Config { + pub fn new( + factory_addr: Addr, + base_denom: String, + splitting_targets: Vec, + ) -> Self { + Self { + factory_addr, + base_denom, + splitting_targets, + } + } + + pub fn validate_base_denom(&self, deps: Deps) -> Result<(), ContractError> { + let total_supply = deps.querier.query_supply(self.base_denom.clone()); + if total_supply.is_err() || total_supply.unwrap().amount.is_zero() { + return Ok(()); + } + return Err(ContractError::BaseDenomError {}); + } + + pub fn validate_splitting_targets(&self, deps: Deps) -> Result<(), ContractError> { + let mut accum: Uint128 = Uint128::zero(); + for target in self.splitting_targets.iter() { + let checked_add = accum.checked_add(target.unbonding_weight); + if checked_add.is_err() { + return Err(ContractError::OverflowError(checked_add.unwrap_err())); + } + accum = checked_add.unwrap(); + + if deps.api.addr_validate(target.addr.as_str()).is_err() { + return Err(ContractError::InvalidAddressProvided {}); + } + } + return Ok(()); + } + + pub fn validate_factory_addr(&self, deps: Deps) -> Result<(), ContractError> { + if deps.api.addr_validate(self.factory_addr.as_str()).is_err() { + return Err(ContractError::InvalidAddressProvided {}); + } + return Ok(()); + } +} + +pub const CREATE_DENOM_REPLY_ID: u64 = 1; + +pub const CONFIG: Item = Item::new("config"); +pub const EXCHANGE_RATE: Item = Item::new("exchange_rate"); + +pub const TOKEN_METADATA: Item = Item::new("token_metadata"); +pub const DENOM: Item = Item::new("denom"); +pub const EXPONENT: Item = Item::new("exponent"); diff --git a/contracts/lazy-staking/src/tests.rs b/contracts/lazy-staking/src/tests.rs new file mode 100644 index 00000000..e69de29b diff --git a/contracts/factory/src/msg.rs b/packages/base/src/msg/factory.rs similarity index 82% rename from contracts/factory/src/msg.rs rename to packages/base/src/msg/factory.rs index 2b82588d..9661d19d 100644 --- a/contracts/factory/src/msg.rs +++ b/packages/base/src/msg/factory.rs @@ -1,9 +1,9 @@ -use crate::state::{CodeIds, RemoteOpts}; +use crate::msg::token::DenomMetadata; +use crate::state::factory::{CodeIds, RemoteOpts}; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{CosmosMsg, Decimal, Uint128}; use cw_ownable::cw_ownable_execute; use drop_macros::pausable; -use drop_staking_base::msg::token::DenomMetadata; use neutron_sdk::bindings::msg::NeutronMsg; #[cw_serde] @@ -53,8 +53,8 @@ pub struct LsmShareBondParams { #[cw_serde] pub enum UpdateConfigMsg { - Core(Box), - ValidatorsSet(drop_staking_base::state::validatorset::ConfigOptional), + Core(Box), + ValidatorsSet(crate::state::validatorset::ConfigOptional), } #[cw_serde] @@ -65,7 +65,7 @@ pub enum ProxyMsg { #[cw_serde] pub enum ValidatorSetMsg { UpdateValidators { - validators: Vec, + validators: Vec, }, } @@ -84,8 +84,8 @@ pub struct MigrateMsg {} #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { - #[returns(crate::state::State)] + #[returns(crate::state::factory::State)] State {}, - #[returns(crate::state::PauseInfoResponse)] + #[returns(crate::state::factory::PauseInfoResponse)] PauseInfo {}, } diff --git a/packages/base/src/msg/mod.rs b/packages/base/src/msg/mod.rs index b4e1197d..7eca191e 100644 --- a/packages/base/src/msg/mod.rs +++ b/packages/base/src/msg/mod.rs @@ -2,6 +2,7 @@ pub mod astroport_exchange_handler; pub mod bond_provider; pub mod core; pub mod distribution; +pub mod factory; pub mod hook_tester; pub mod lsm_share_bond_provider; pub mod mirror; diff --git a/contracts/factory/src/state.rs b/packages/base/src/state/factory.rs similarity index 96% rename from contracts/factory/src/state.rs rename to packages/base/src/state/factory.rs index 21755c81..9e759cd8 100644 --- a/contracts/factory/src/state.rs +++ b/packages/base/src/state/factory.rs @@ -55,7 +55,7 @@ pub struct State { #[cw_serde] pub struct PauseInfoResponse { pub withdrawal_manager: drop_helpers::pause::PauseInfoResponse, - pub core: drop_staking_base::state::core::Pause, + pub core: crate::state::core::Pause, pub rewards_manager: drop_helpers::pause::PauseInfoResponse, } diff --git a/packages/base/src/state/mod.rs b/packages/base/src/state/mod.rs index 3170f923..057f7a99 100644 --- a/packages/base/src/state/mod.rs +++ b/packages/base/src/state/mod.rs @@ -1,6 +1,7 @@ pub mod astroport_exchange_handler; pub mod bond_providers; pub mod core; +pub mod factory; pub mod hook_tester; pub mod lsm_share_bond_provider; pub mod mirror;