From 41db6dcb822b5aae7db64d7ab7d7e2da02a8bdd2 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Tue, 27 Feb 2024 21:51:23 +0200 Subject: [PATCH 01/10] Add fee collection support --- contracts/core/src/contract.rs | 85 ++++++++++++++++++++++++++------- packages/base/src/state/core.rs | 8 ++-- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 1cb00c1d..6c20763b 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -248,8 +248,10 @@ fn execute_tick_idle( let mut messages = vec![]; if env.block.time.seconds() - last_idle_call < config.idle_min_interval { //process non-native rewards - if let Some(transfer_msg) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? { - messages.push(transfer_msg); + if let Some(transfer_msgs) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? + { + messages.push(transfer_msgs.0); + messages.push(transfer_msgs.1); } else { //return error if none return Err(ContractError::IdleMinIntervalIsNotReached {}); @@ -392,11 +394,14 @@ fn execute_tick_transfering( ) -> ContractResult> { let _response_msg = get_received_puppeteer_response(deps.as_ref())?; LAST_PUPPETEER_RESPONSE.remove(deps.storage); - let mut attrs = vec![attr("action", "tick_transfering")]; - FSM.go_to(deps.storage, ContractState::Staking)?; - attrs.push(attr("state", "staking")); let message = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; - Ok(response("execute-tick_transfering", CONTRACT_NAME, attrs).add_message(message)) + FSM.go_to(deps.storage, ContractState::Staking)?; + Ok(response( + "execute-tick_transfering", + CONTRACT_NAME, + vec![attr("action", "tick_transfering"), attr("state", "staking")], + ) + .add_message(message)) } fn execute_tick_staking( @@ -788,7 +793,7 @@ fn get_stake_msg( env: &Env, config: &Config, funds: Vec, -) -> ContractResult> { +) -> ContractResult<(CosmosMsg, CosmosMsg)> { let (balance, balance_height) = get_ica_balance_by_denom( deps, &config.puppeteer_contract, @@ -804,12 +809,18 @@ fn get_stake_msg( puppeteer_height: balance_height } ); + let fee = config.fee * balance; + let deposit_amount = balance - fee; + let to_delegate: Vec = deps.querier.query_wasm_smart( &config.strategy_contract, - &lido_staking_base::msg::strategy::QueryMsg::CalcDeposit { deposit: balance }, + &lido_staking_base::msg::strategy::QueryMsg::CalcDeposit { + deposit: deposit_amount, + }, )?; - Ok(CosmosMsg::Wasm(WasmMsg::Execute { + + let delegate_msg = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract.to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { items: to_delegate @@ -820,7 +831,27 @@ fn get_stake_msg( reply_to: env.contract.address.to_string(), })?, funds, - })) + }); + + let fee_item = vec![( + &config.fee_address, + cosmwasm_std::Coin { + denom: config.remote_denom, + amount: fee, + }, + )]; + + let fee_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract, + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: fee_item, + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: vec![], + }); + + Ok((delegate_msg, fee_msg)) } fn get_received_puppeteer_response( @@ -899,10 +930,11 @@ fn get_non_native_rewards_transfer_msg( deps: Deps, info: MessageInfo, env: Env, -) -> ContractResult>> { +) -> ContractResult, CosmosMsg)>> { let config = CONFIG.load(deps.storage)?; let non_native_rewards_receivers = NON_NATIVE_REWARDS_CONFIG.load(deps.storage)?; let mut items = vec![]; + let mut fees = vec![]; let rewards: lido_staking_base::msg::puppeteer::BalancesResponse = deps.querier.query_wasm_smart( config.puppeteer_contract.to_string(), @@ -920,27 +952,48 @@ fn get_non_native_rewards_transfer_msg( for item in non_native_rewards_receivers { let amount = rewards_map.get(&item.denom).unwrap_or(&default_amount); if amount > &item.min_amount { + let fee = item.fee * *amount; + let amount = *amount - fee; items.push(( item.address, + cosmwasm_std::Coin { + denom: item.denom.clone(), + amount, + }, + )); + + fees.push(( + item.fee_address, cosmwasm_std::Coin { denom: item.denom, - amount: *amount, + amount: fee, }, )); } } - if items.is_empty() { + if items.is_empty() || fees.is_empty() { return Ok(None); } - Ok(Some(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract, + + let transfer_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract.clone(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { items, timeout: Some(config.puppeteer_timeout), reply_to: env.contract.address.to_string(), })?, funds: info.funds, - }))) + }); + let fee_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract, + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: fees, + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: vec![], + }); + Ok(Some((transfer_msg, fee_msg))) } mod check_denom { diff --git a/packages/base/src/state/core.rs b/packages/base/src/state/core.rs index 215c5af7..39c77e03 100644 --- a/packages/base/src/state/core.rs +++ b/packages/base/src/state/core.rs @@ -25,6 +25,8 @@ pub struct Config { pub owner: String, pub channel: String, pub ld_denom: Option, + pub fee: Decimal, + pub fee_address: String, } pub const CONFIG: Item = Item::new("config"); @@ -88,10 +90,6 @@ const TRANSITIONS: &[Transition] = &[ from: ContractState::Idle, to: ContractState::Transfering, }, - Transition { - from: ContractState::Idle, - to: ContractState::Claiming, - }, Transition { from: ContractState::Claiming, to: ContractState::Transfering, @@ -123,6 +121,8 @@ pub struct NonNativeRewardsItem { pub denom: String, pub address: String, pub min_amount: Uint128, + pub fee_address: String, + pub fee: Decimal, } pub const FSM: Fsm = Fsm::new("machine_state", TRANSITIONS); From ab7ea0334c5c90ed0994ce788f290c2aec0d4dc6 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Tue, 27 Feb 2024 22:36:19 +0200 Subject: [PATCH 02/10] Fix errors --- contracts/core/src/contract.rs | 19 ++++++++++++------- contracts/factory/src/contract.rs | 2 ++ contracts/factory/src/msg.rs | 2 +- packages/base/src/msg/core.rs | 6 +++++- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 6c20763b..3484c98a 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -316,7 +316,9 @@ fn execute_tick_idle( PENDING_TRANSFER.save(deps.storage, &pending_amount)?; messages.push(transfer_msg); } else { - messages.push(get_stake_msg(deps.as_ref(), &env, config, info.funds)?); + let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + messages.push(all_msgs.0); + messages.push(all_msgs.1); FSM.go_to(deps.storage, ContractState::Staking)?; } } else { @@ -379,7 +381,9 @@ fn execute_tick_claiming( PENDING_TRANSFER.save(deps.storage, &pending_amount)?; messages.push(transfer_msg); } else { - messages.push(get_stake_msg(deps.as_ref(), &env, config, info.funds)?); + let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + messages.push(all_msgs.0); + messages.push(all_msgs.1); FSM.go_to(deps.storage, ContractState::Staking)?; } attrs.push(attr("state", "unbonding")); @@ -394,14 +398,15 @@ fn execute_tick_transfering( ) -> ContractResult> { let _response_msg = get_received_puppeteer_response(deps.as_ref())?; LAST_PUPPETEER_RESPONSE.remove(deps.storage); - let message = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + let messages = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; FSM.go_to(deps.storage, ContractState::Staking)?; Ok(response( "execute-tick_transfering", CONTRACT_NAME, vec![attr("action", "tick_transfering"), attr("state", "staking")], ) - .add_message(message)) + .add_message(messages.0) + .add_message(messages.1)) } fn execute_tick_staking( @@ -834,15 +839,15 @@ fn get_stake_msg( }); let fee_item = vec![( - &config.fee_address, + config.fee_address.to_string(), cosmwasm_std::Coin { - denom: config.remote_denom, + denom: config.remote_denom.to_owned(), amount: fee, }, )]; let fee_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract, + contract_addr: config.puppeteer_contract.to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { items: fee_item, timeout: Some(config.puppeteer_timeout), diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 9c76b4f1..062ba22f 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -427,6 +427,8 @@ fn execute_init( idle_min_interval: core_params.idle_min_interval, channel: core_params.channel, owner: env.contract.address.to_string(), + fee: core_params.fee, + fee_address: core_params.fee_address, })?, funds: vec![], salt: Binary::from(salt), diff --git a/contracts/factory/src/msg.rs b/contracts/factory/src/msg.rs index e681cc26..521c79b4 100644 --- a/contracts/factory/src/msg.rs +++ b/contracts/factory/src/msg.rs @@ -1,6 +1,6 @@ use crate::state::{CodeIds, RemoteOpts}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Binary, Uint128}; +use cosmwasm_std::{Binary, Decimal, Uint128}; use lido_staking_base::msg::token::DenomMetadata; #[cw_serde] diff --git a/packages/base/src/msg/core.rs b/packages/base/src/msg/core.rs index 11dcbbc5..53f8bf7a 100644 --- a/packages/base/src/msg/core.rs +++ b/packages/base/src/msg/core.rs @@ -1,6 +1,6 @@ use crate::state::core::{Config, ConfigOptional, NonNativeRewardsItem}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Uint128; +use cosmwasm_std::{Decimal, Uint128}; use cw_ownable::cw_ownable_execute; use lido_puppeteer_base::msg::ResponseHookMsg; @@ -22,6 +22,8 @@ pub struct InstantiateMsg { pub pump_address: Option, pub channel: String, pub owner: String, + pub fee: Decimal, + pub fee_address: String, } #[cw_serde] @@ -86,6 +88,8 @@ impl From for Config { pump_address: val.pump_address, validators_set_contract: val.validators_set_contract, unbond_batch_switch_time: val.unbond_batch_switch_time, + fee: val.fee, + fee_address: val.fee_address, } } } From 24e219ba5e8f7b14f26d3b5c32b6a7b9b1b97ed3 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Wed, 28 Feb 2024 21:21:42 +0200 Subject: [PATCH 03/10] testing with custom querier --- contracts/core/src/contract.rs | 152 ++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 2 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 3484c98a..b26935d5 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -793,7 +793,7 @@ fn get_transfer_pending_balance( ))) } -fn get_stake_msg( +pub fn get_stake_msg( deps: Deps, env: &Env, config: &Config, @@ -931,7 +931,7 @@ fn new_unbond(now: u64) -> lido_staking_base::state::core::UnbondBatch { } } -fn get_non_native_rewards_transfer_msg( +pub fn get_non_native_rewards_transfer_msg( deps: Deps, info: MessageInfo, env: Env, @@ -947,6 +947,7 @@ fn get_non_native_rewards_transfer_msg( msg: lido_staking_base::msg::puppeteer::QueryExtMsg::NonNativeRewardsBalances {}, }, )?; + println!("rewards {:?}", rewards); let rewards_map = rewards .0 .coins @@ -954,7 +955,12 @@ fn get_non_native_rewards_transfer_msg( .map(|c| (c.denom.clone(), c.amount)) .collect::>(); let default_amount = Uint128::zero(); + println!( + "non_native_rewards_receivers {:?}", + non_native_rewards_receivers + ); for item in non_native_rewards_receivers { + println!("item {:?}", item); let amount = rewards_map.get(&item.denom).unwrap_or(&default_amount); if amount > &item.min_amount { let fee = item.fee * *amount; @@ -976,6 +982,7 @@ fn get_non_native_rewards_transfer_msg( )); } } + println!("items {:?}, fees {:?}", items, fees); if items.is_empty() || fees.is_empty() { return Ok(None); } @@ -1083,5 +1090,146 @@ mod check_denom { } Ok(DenomType::LsmShare) +#[cfg(test)] +mod tests { + use std::marker::PhantomData; + + use cosmwasm_std::{ + from_json, + testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}, + Coin, ContractResult, Empty, OwnedDeps, Querier, QuerierResult, QueryRequest, SystemError, + SystemResult, WasmQuery, + }; + + use lido_puppeteer_base::msg::QueryMsg as PuppeteerBaseQueryMsg; + use lido_staking_base::msg::puppeteer::{MultiBalances, QueryExtMsg}; + + use super::*; + + pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; + + fn mock_dependencies( + ) -> OwnedDeps { + let custom_querier = WasmMockQuerier::new(MockQuerier::new(&[])); + + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: custom_querier, + custom_query_type: PhantomData, + } + } + + pub struct WasmMockQuerier { + base: MockQuerier, + } + + impl Querier for WasmMockQuerier { + fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { + let request: QueryRequest = match from_json(bin_request) { + Ok(v) => v, + Err(e) => { + return QuerierResult::Err(SystemError::InvalidRequest { + error: format!("Parsing query request: {}", e), + request: bin_request.into(), + }); + } + }; + self.handle_query(&request) + } + } + + impl WasmMockQuerier { + pub fn handle_query(&self, request: &QueryRequest) -> QuerierResult { + match &request { + QueryRequest::Wasm(WasmQuery::Smart { contract_addr, msg }) => { + if contract_addr == MOCK_PUPPETEER_CONTRACT_ADDR { + let q: PuppeteerBaseQueryMsg = from_json(msg).unwrap(); + let reply = match q { + PuppeteerBaseQueryMsg::Extention { msg } => match msg { + QueryExtMsg::NonNativeRewardsBalances {} => { + let data = ( + MultiBalances { + coins: vec![Coin { + denom: "denom".to_string(), + amount: Uint128::new(150), + }], + }, + 10, + ); + to_json_binary(&(data.0, data.1)) + } + _ => todo!(), + }, + _ => todo!(), + }; + return SystemResult::Ok(ContractResult::from(reply)); + } + SystemResult::Err(SystemError::NoSuchContract { + addr: contract_addr.to_string(), + }) + } + _ => self.base.handle_query(request), + } + } + } + + impl WasmMockQuerier { + pub fn new(base: MockQuerier) -> WasmMockQuerier { + WasmMockQuerier { base } + } + } + + #[test] + fn get_non_native_rewards_transfer_msg_success() { + let mut deps = mock_dependencies::(); + + CONFIG + .save( + deps.as_mut().storage, + &Config { + token_contract: "token_contract".to_string(), + puppeteer_contract: "puppeteer_contract".to_string(), + puppeteer_timeout: 60, + strategy_contract: "strategy_contract".to_string(), + withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), + withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), + validators_set_contract: "validators_set_contract".to_string(), + base_denom: "base_denom".to_string(), + remote_denom: "remote_denom".to_string(), + idle_min_interval: 1, + unbonding_period: 60, + unbonding_safe_period: 10, + unbond_batch_switch_time: 6000, + pump_address: None, + owner: "owner".to_string(), + ld_denom: None, + fee: Decimal::from_atomics(1u32, 1).unwrap(), + fee_address: "fee_address".to_string(), + }, + ) + .unwrap(); + + NON_NATIVE_REWARDS_CONFIG + .save( + deps.as_mut().storage, + &vec![NonNativeRewardsItem { + address: "address".to_string(), + denom: "denom".to_string(), + min_amount: Uint128::new(100), + fee: Decimal::from_atomics(1u32, 1).unwrap(), + fee_address: "fee_address".to_string(), + }], + ) + .unwrap(); + + let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); + + let result: (CosmosMsg, CosmosMsg) = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + .unwrap() + .unwrap(); + + println!("{:?}", result); } } From 9b6824943a803926fe829e5a0a5caa45a5e9d03b Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Thu, 29 Feb 2024 14:53:53 +0200 Subject: [PATCH 04/10] Fix integration tests and unit tests --- .../astroport-exchange-handler/src/tests.rs | 8 - contracts/core/src/contract.rs | 404 ++++++++++++++---- contracts/factory/src/contract.rs | 4 +- contracts/factory/src/msg.rs | 2 +- contracts/rewards-manager/src/tests.rs | 3 - .../src/generated/contractLib/lidoCore.ts | 299 ++++++++++--- .../src/generated/contractLib/lidoFactory.ts | 159 +++++-- packages/base/src/msg/core.rs | 4 +- packages/base/src/state/core.rs | 4 +- 9 files changed, 691 insertions(+), 196 deletions(-) diff --git a/contracts/astroport-exchange-handler/src/tests.rs b/contracts/astroport-exchange-handler/src/tests.rs index 1c56b333..e6569117 100644 --- a/contracts/astroport-exchange-handler/src/tests.rs +++ b/contracts/astroport-exchange-handler/src/tests.rs @@ -51,8 +51,6 @@ fn pair_contract() -> Box> { to, } => { if !info.funds.is_empty() { - println!("received funds {:?}", info.funds); - let asset_denom = match offer_asset.info { AssetInfo::NativeToken { denom } => denom, _ => { @@ -86,8 +84,6 @@ fn pair_contract() -> Box> { } } - println!("handler contract execute"); - Err(StdError::generic_err("Wrong execution call")) }, |_, _, _, _: Empty| Ok(Response::new()), @@ -112,8 +108,6 @@ fn router_contract() -> Box> { to, } => { if !info.funds.is_empty() { - println!("received funds {:?}", info.funds); - return Ok(response( "router_contract_execute", "router_mock", @@ -146,8 +140,6 @@ fn router_contract() -> Box> { } } - println!("handler contract execute"); - Err(StdError::generic_err("Wrong execution call")) }, |_, _, _, _: Empty| Ok(Response::new()), diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index b26935d5..3c4b7d70 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -29,6 +29,8 @@ use prost::Message; use std::str::FromStr; use std::vec; +pub type MessageWithFeeResponse = (CosmosMsg, Option>); + const CONTRACT_NAME: &str = concat!("crates.io:lido-staking__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -251,7 +253,9 @@ fn execute_tick_idle( if let Some(transfer_msgs) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? { messages.push(transfer_msgs.0); - messages.push(transfer_msgs.1); + if let Some(fee_msg) = transfer_msgs.1 { + messages.push(fee_msg); + } } else { //return error if none return Err(ContractError::IdleMinIntervalIsNotReached {}); @@ -318,7 +322,9 @@ fn execute_tick_idle( } else { let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; messages.push(all_msgs.0); - messages.push(all_msgs.1); + if let Some(fee_msg) = all_msgs.1 { + messages.push(fee_msg); + } FSM.go_to(deps.storage, ContractState::Staking)?; } } else { @@ -383,7 +389,9 @@ fn execute_tick_claiming( } else { let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; messages.push(all_msgs.0); - messages.push(all_msgs.1); + if let Some(fee_msg) = all_msgs.1 { + messages.push(fee_msg); + } FSM.go_to(deps.storage, ContractState::Staking)?; } attrs.push(attr("state", "unbonding")); @@ -398,15 +406,20 @@ fn execute_tick_transfering( ) -> ContractResult> { let _response_msg = get_received_puppeteer_response(deps.as_ref())?; LAST_PUPPETEER_RESPONSE.remove(deps.storage); - let messages = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + let stake_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; FSM.go_to(deps.storage, ContractState::Staking)?; + let mut messages = vec![]; + messages.push(stake_msgs.0); + if let Some(fee_msg) = stake_msgs.1 { + messages.push(fee_msg); + } + Ok(response( "execute-tick_transfering", CONTRACT_NAME, vec![attr("action", "tick_transfering"), attr("state", "staking")], ) - .add_message(messages.0) - .add_message(messages.1)) + .add_messages(messages)) } fn execute_tick_staking( @@ -659,6 +672,15 @@ fn execute_update_config( attrs.push(attr("channel", &channel)); config.channel = channel; } + if let Some(fee) = new_config.fee { + attrs.push(attr("fee", fee.to_string())); + config.fee = Some(fee); + } + if let Some(fee_address) = new_config.fee_address { + attrs.push(attr("fee_address", &fee_address)); + config.fee_address = Some(fee_address); + } + CONFIG.save(deps.storage, &config)?; Ok(response("execute-update_config", CONTRACT_NAME, attrs)) @@ -798,13 +820,14 @@ pub fn get_stake_msg( env: &Env, config: &Config, funds: Vec, -) -> ContractResult<(CosmosMsg, CosmosMsg)> { +) -> ContractResult> { let (balance, balance_height) = get_ica_balance_by_denom( deps, &config.puppeteer_contract, &config.remote_denom, false, )?; + ensure_ne!(balance, Uint128::zero(), ContractError::ICABalanceZero {}); let last_ica_balance_change_height = LAST_ICA_BALANCE_CHANGE_HEIGHT.load(deps.storage)?; ensure!( @@ -814,7 +837,7 @@ pub fn get_stake_msg( puppeteer_height: balance_height } ); - let fee = config.fee * balance; + let fee = config.fee.unwrap_or(Decimal::zero()) * balance; let deposit_amount = balance - fee; let to_delegate: Vec = @@ -838,23 +861,25 @@ pub fn get_stake_msg( funds, }); - let fee_item = vec![( - config.fee_address.to_string(), - cosmwasm_std::Coin { - denom: config.remote_denom.to_owned(), - amount: fee, - }, - )]; - - let fee_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: fee_item, - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: vec![], - }); + let fee_msg = if fee > Uint128::zero() && config.fee_address.is_some() { + Some(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract.to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + config.fee_address.clone().unwrap().to_string(), + cosmwasm_std::Coin { + denom: config.remote_denom.to_owned(), + amount: fee, + }, + )], + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: vec![], + })) + } else { + None + }; Ok((delegate_msg, fee_msg)) } @@ -901,6 +926,7 @@ fn get_ica_balance_by_denom( msg: lido_staking_base::msg::puppeteer::QueryExtMsg::Balances {}, }, )?; + let balance = ica_balances.coins.iter().find_map(|c| { if c.denom == remote_denom { Some(c.amount) @@ -935,7 +961,7 @@ pub fn get_non_native_rewards_transfer_msg( deps: Deps, info: MessageInfo, env: Env, -) -> ContractResult, CosmosMsg)>> { +) -> ContractResult>> { let config = CONFIG.load(deps.storage)?; let non_native_rewards_receivers = NON_NATIVE_REWARDS_CONFIG.load(deps.storage)?; let mut items = vec![]; @@ -947,7 +973,7 @@ pub fn get_non_native_rewards_transfer_msg( msg: lido_staking_base::msg::puppeteer::QueryExtMsg::NonNativeRewardsBalances {}, }, )?; - println!("rewards {:?}", rewards); + let rewards_map = rewards .0 .coins @@ -955,12 +981,8 @@ pub fn get_non_native_rewards_transfer_msg( .map(|c| (c.denom.clone(), c.amount)) .collect::>(); let default_amount = Uint128::zero(); - println!( - "non_native_rewards_receivers {:?}", - non_native_rewards_receivers - ); + for item in non_native_rewards_receivers { - println!("item {:?}", item); let amount = rewards_map.get(&item.denom).unwrap_or(&default_amount); if amount > &item.min_amount { let fee = item.fee * *amount; @@ -973,17 +995,19 @@ pub fn get_non_native_rewards_transfer_msg( }, )); - fees.push(( - item.fee_address, - cosmwasm_std::Coin { - denom: item.denom, - amount: fee, - }, - )); + if (item.fee > Decimal::zero()) && (fee > Uint128::zero()) { + fees.push(( + item.fee_address, + cosmwasm_std::Coin { + denom: item.denom, + amount: fee, + }, + )); + } } } - println!("items {:?}, fees {:?}", items, fees); - if items.is_empty() || fees.is_empty() { + + if items.is_empty() { return Ok(None); } @@ -996,15 +1020,20 @@ pub fn get_non_native_rewards_transfer_msg( })?, funds: info.funds, }); - let fee_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract, - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: fees, - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: vec![], - }); + let fee_msg = if !fees.is_empty() { + Some(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract, + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: fees, + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: vec![], + })) + } else { + None + }; + Ok(Some((transfer_msg, fee_msg))) } @@ -1103,13 +1132,15 @@ mod tests { use lido_puppeteer_base::msg::QueryMsg as PuppeteerBaseQueryMsg; use lido_staking_base::msg::puppeteer::{MultiBalances, QueryExtMsg}; + use lido_staking_base::msg::strategy::QueryMsg as StategyQueryMsg; + use neutron_sdk::interchain_queries::v045::types::Balances; use super::*; pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; + pub const MOCK_STRATEGY_CONTRACT_ADDR: &str = "strategy_contract"; - fn mock_dependencies( - ) -> OwnedDeps { + fn mock_dependencies() -> OwnedDeps { let custom_querier = WasmMockQuerier::new(MockQuerier::new(&[])); OwnedDeps { @@ -1159,12 +1190,40 @@ mod tests { ); to_json_binary(&(data.0, data.1)) } + QueryExtMsg::Balances {} => { + let data = ( + Balances { + coins: vec![Coin { + denom: "remote_denom".to_string(), + amount: Uint128::new(200), + }], + }, + 10, + ); + to_json_binary(&(data.0, data.1)) + } _ => todo!(), }, _ => todo!(), }; return SystemResult::Ok(ContractResult::from(reply)); } + if contract_addr == MOCK_STRATEGY_CONTRACT_ADDR { + let q: StategyQueryMsg = from_json(msg).unwrap(); + let reply = match q { + StategyQueryMsg::CalcDeposit { deposit } => to_json_binary(&vec![ + lido_staking_base::msg::distribution::IdealDelegation { + valoper_address: "valoper_address".to_string(), + stake_change: deposit, + ideal_stake: deposit, + current_stake: deposit, + weight: 1u64, + }, + ]), + _ => todo!(), + }; + return SystemResult::Ok(ContractResult::from(reply)); + } SystemResult::Err(SystemError::NoSuchContract { addr: contract_addr.to_string(), }) @@ -1180,36 +1239,114 @@ mod tests { } } + fn get_default_config(fee: Option) -> Config { + Config { + token_contract: "token_contract".to_string(), + puppeteer_contract: MOCK_PUPPETEER_CONTRACT_ADDR.to_string(), + puppeteer_timeout: 60, + strategy_contract: MOCK_STRATEGY_CONTRACT_ADDR.to_string(), + withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), + withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), + validators_set_contract: "validators_set_contract".to_string(), + base_denom: "base_denom".to_string(), + remote_denom: "remote_denom".to_string(), + idle_min_interval: 1, + unbonding_period: 60, + unbonding_safe_period: 10, + unbond_batch_switch_time: 6000, + pump_address: None, + owner: "owner".to_string(), + ld_denom: None, + fee, + fee_address: Some("fee_address".to_string()), + } + } + + fn setup_config(deps: &mut OwnedDeps) { + CONFIG + .save( + deps.as_mut().storage, + &get_default_config(Decimal::from_atomics(1u32, 1).ok()), + ) + .unwrap(); + } + #[test] fn get_non_native_rewards_transfer_msg_success() { - let mut deps = mock_dependencies::(); + let mut deps = mock_dependencies(); - CONFIG + setup_config(&mut deps); + + NON_NATIVE_REWARDS_CONFIG .save( deps.as_mut().storage, - &Config { - token_contract: "token_contract".to_string(), - puppeteer_contract: "puppeteer_contract".to_string(), - puppeteer_timeout: 60, - strategy_contract: "strategy_contract".to_string(), - withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), - withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), - validators_set_contract: "validators_set_contract".to_string(), - base_denom: "base_denom".to_string(), - remote_denom: "remote_denom".to_string(), - idle_min_interval: 1, - unbonding_period: 60, - unbonding_safe_period: 10, - unbond_batch_switch_time: 6000, - pump_address: None, - owner: "owner".to_string(), - ld_denom: None, + &vec![NonNativeRewardsItem { + address: "address".to_string(), + denom: "denom".to_string(), + min_amount: Uint128::new(100), fee: Decimal::from_atomics(1u32, 1).unwrap(), fee_address: "fee_address".to_string(), - }, + }], ) .unwrap(); + let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); + + let result: (CosmosMsg, Option>) = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + .unwrap() + .unwrap(); + + let first_tx = result.0; + let second_tx = result.1; + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(135) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![Coin::new(1000, "untrn")] + }) + ); + + assert_eq!( + second_tx.unwrap(), + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "fee_address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(15) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![] + }) + ); + } + + #[test] + fn get_non_native_rewards_transfer_msg_zero_fee() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + NON_NATIVE_REWARDS_CONFIG .save( deps.as_mut().storage, @@ -1217,7 +1354,7 @@ mod tests { address: "address".to_string(), denom: "denom".to_string(), min_amount: Uint128::new(100), - fee: Decimal::from_atomics(1u32, 1).unwrap(), + fee: Decimal::zero(), fee_address: "fee_address".to_string(), }], ) @@ -1225,11 +1362,128 @@ mod tests { let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); - let result: (CosmosMsg, CosmosMsg) = + let result: (CosmosMsg, Option>) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) .unwrap() .unwrap(); - println!("{:?}", result); + let first_tx = result.0; + let second_tx = result.1; + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(150) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![Coin::new(1000, "untrn")] + }) + ); + + assert!(second_tx.is_none()); + } + + #[test] + fn get_stake_msg_success() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + LAST_ICA_BALANCE_CHANGE_HEIGHT + .save(deps.as_mut().storage, &1) + .unwrap(); + + let result: (CosmosMsg, Option>) = get_stake_msg( + deps.as_ref(), + &mock_env(), + &get_default_config(Decimal::from_atomics(1u32, 1).ok()), + vec![], + ) + .unwrap(); + + let first_tx = result.0; + let second_tx = result.1; + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { + items: vec![("valoper_address".to_string(), Uint128::new(180))], + timeout: Some(60), + reply_to: "cosmos2contract".to_string(), + }) + .unwrap(), + funds: vec![], + }) + ); + + assert_eq!( + second_tx.unwrap(), + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "fee_address".to_string(), + Coin { + denom: "remote_denom".to_string(), + amount: Uint128::new(20) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![] + }) + ); + } + + #[test] + fn get_stake_msg_zero_fee() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + LAST_ICA_BALANCE_CHANGE_HEIGHT + .save(deps.as_mut().storage, &1) + .unwrap(); + + let result: (CosmosMsg, Option>) = get_stake_msg( + deps.as_ref(), + &mock_env(), + &get_default_config(None), + vec![], + ) + .unwrap(); + + let first_tx = result.0; + let second_tx = result.1; + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { + items: vec![("valoper_address".to_string(), Uint128::new(200))], + timeout: Some(60), + reply_to: "cosmos2contract".to_string(), + }) + .unwrap(), + funds: vec![], + }) + ); + + assert!(second_tx.is_none()); } } diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 062ba22f..21779e2a 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -427,8 +427,8 @@ fn execute_init( idle_min_interval: core_params.idle_min_interval, channel: core_params.channel, owner: env.contract.address.to_string(), - fee: core_params.fee, - fee_address: core_params.fee_address, + fee: None, + fee_address: None, })?, funds: vec![], salt: Binary::from(salt), diff --git a/contracts/factory/src/msg.rs b/contracts/factory/src/msg.rs index 521c79b4..e681cc26 100644 --- a/contracts/factory/src/msg.rs +++ b/contracts/factory/src/msg.rs @@ -1,6 +1,6 @@ use crate::state::{CodeIds, RemoteOpts}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Binary, Decimal, Uint128}; +use cosmwasm_std::{Binary, Uint128}; use lido_staking_base::msg::token::DenomMetadata; #[cw_serde] diff --git a/contracts/rewards-manager/src/tests.rs b/contracts/rewards-manager/src/tests.rs index 754d3a5a..ebd9a11b 100644 --- a/contracts/rewards-manager/src/tests.rs +++ b/contracts/rewards-manager/src/tests.rs @@ -39,7 +39,6 @@ fn handler_contract() -> Box> { match msg { HandlerExecuteMsg::Exchange {} => { if !info.funds.is_empty() { - println!("received funds {:?}", info.funds); return Ok(response( "handler_contract_execute", "handler_mock", @@ -56,8 +55,6 @@ fn handler_contract() -> Box> { } } - println!("handler contract execute"); - Err(StdError::generic_err("Wrong execution call")) }, |_, _, _, _: Empty| Ok(Response::new()), diff --git a/integration_tests/src/generated/contractLib/lidoCore.ts b/integration_tests/src/generated/contractLib/lidoCore.ts index dee528e3..7d98d184 100644 --- a/integration_tests/src/generated/contractLib/lidoCore.ts +++ b/integration_tests/src/generated/contractLib/lidoCore.ts @@ -1,8 +1,21 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; +import { + CosmWasmClient, + SigningCosmWasmClient, + ExecuteResult, + InstantiateResult, +} from '@cosmjs/cosmwasm-stargate'; +import { StdFee } from '@cosmjs/amino'; +/** + * A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 + * + * The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) + */ +export type Decimal = string; + export interface InstantiateMsg { base_denom: string; - channel: string; + fee?: Decimal | null; + fee_address?: string | null; idle_min_interval: number; owner: string; pump_address?: string | null; @@ -18,13 +31,24 @@ export interface InstantiateMsg { withdrawal_manager_contract: string; withdrawal_voucher_contract: string; } -export type ContractState = "idle" | "claiming" | "unbonding" | "staking" | "transfering"; /** * A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 * * The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) */ export type Decimal = string; +export type ContractState = + | 'idle' + | 'claiming' + | 'unbonding' + | 'staking' + | 'transfering'; +/** + * A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 + * + * The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) + */ +export type Decimal1 = string; export type ResponseHookMsg = | { success: ResponseHookSuccessMsg; @@ -149,13 +173,13 @@ export type Transaction = }; }; export type ArrayOfNonNativeRewardsItem = NonNativeRewardsItem[]; -/** - * A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 - * - * The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) - */ -export type Decimal1 = string; -export type UnbondBatchStatus = "new" | "unbond_requested" | "unbond_failed" | "unbonding" | "unbonded" | "withdrawn"; +export type UnbondBatchStatus = + | 'new' + | 'unbond_requested' + | 'unbond_failed' + | 'unbonding' + | 'unbonded' + | 'withdrawn'; export type PuppeteerHookArgs = | { success: ResponseHookSuccessMsg; @@ -173,8 +197,8 @@ export type UpdateOwnershipArgs = new_owner: string; }; } - | "accept_ownership" - | "renounce_ownership"; + | 'accept_ownership' + | 'renounce_ownership'; /** * Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future) */ @@ -214,7 +238,13 @@ export type Timestamp2 = Uint64; export type Uint64 = string; export interface LidoCoreSchema { - responses: Config | ContractState | Decimal | ResponseHookMsg | ArrayOfNonNativeRewardsItem | UnbondBatch; + responses: + | Config + | ContractState + | Decimal1 + | ResponseHookMsg + | ArrayOfNonNativeRewardsItem + | UnbondBatch; query: UnbondBatchArgs; execute: | BondArgs @@ -227,7 +257,8 @@ export interface LidoCoreSchema { } export interface Config { base_denom: string; - channel: string; + fee?: Decimal | null; + fee_address?: string | null; idle_min_interval: number; ld_denom?: string | null; owner: string; @@ -307,13 +338,15 @@ export interface ResponseHookErrorMsg { export interface NonNativeRewardsItem { address: string; denom: string; + fee: Decimal; + fee_address: string; min_amount: Uint128; } export interface UnbondBatch { created: number; expected_amount: Uint128; expected_release: number; - slashing_effect?: Decimal1 | null; + slashing_effect?: Decimal | null; status: UnbondBatchStatus; total_amount: Uint128; unbond_items: UnbondItem[]; @@ -336,7 +369,8 @@ export interface UpdateConfigArgs { } export interface ConfigOptional { base_denom?: string | null; - channel?: string | null; + fee?: Decimal | null; + fee_address?: string | null; idle_min_interval?: number | null; ld_denom?: string | null; owner?: string | null; @@ -361,9 +395,8 @@ export interface FakeProcessBatchArgs { unbonded_amount: Uint128; } - function isSigningCosmWasmClient( - client: CosmWasmClient | SigningCosmWasmClient + client: CosmWasmClient | SigningCosmWasmClient, ): client is SigningCosmWasmClient { return 'execute' in client; } @@ -371,12 +404,15 @@ function isSigningCosmWasmClient( export class Client { private readonly client: CosmWasmClient | SigningCosmWasmClient; contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string) { + constructor( + client: CosmWasmClient | SigningCosmWasmClient, + contractAddress: string, + ) { this.client = client; this.contractAddress = contractAddress; } mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); + return new Error('This client is not a SigningCosmWasmClient'); } static async instantiate( client: SigningCosmWasmClient, @@ -392,54 +428,175 @@ export class Client { }); return res; } - queryConfig = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { config: {} }); - } - queryExchangeRate = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { exchange_rate: {} }); - } - queryUnbondBatch = async(args: UnbondBatchArgs): Promise => { - return this.client.queryContractSmart(this.contractAddress, { unbond_batch: args }); - } - queryContractState = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { contract_state: {} }); - } - queryLastPuppeteerResponse = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { last_puppeteer_response: {} }); - } - queryNonNativeRewardsReceivers = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { non_native_rewards_receivers: {} }); - } - bond = async(sender:string, args: BondArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { bond: args }, fee || "auto", memo, funds); - } - unbond = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { unbond: {} }, fee || "auto", memo, funds); - } - updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - } - updateNonNativeRewardsReceivers = async(sender:string, args: UpdateNonNativeRewardsReceiversArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_non_native_rewards_receivers: args }, fee || "auto", memo, funds); - } - fakeProcessBatch = async(sender:string, args: FakeProcessBatchArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { fake_process_batch: args }, fee || "auto", memo, funds); - } - tick = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { tick: {} }, fee || "auto", memo, funds); - } - puppeteerHook = async(sender:string, args: PuppeteerHookArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { puppeteer_hook: args }, fee || "auto", memo, funds); - } - updateOwnership = async(sender:string, args: UpdateOwnershipArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_ownership: args }, fee || "auto", memo, funds); - } + queryConfig = async (): Promise => + this.client.queryContractSmart(this.contractAddress, { config: {} }); + queryExchangeRate = async (): Promise => + this.client.queryContractSmart(this.contractAddress, { exchange_rate: {} }); + queryUnbondBatch = async (args: UnbondBatchArgs): Promise => + this.client.queryContractSmart(this.contractAddress, { + unbond_batch: args, + }); + queryContractState = async (): Promise => + this.client.queryContractSmart(this.contractAddress, { + contract_state: {}, + }); + queryLastPuppeteerResponse = async (): Promise => + this.client.queryContractSmart(this.contractAddress, { + last_puppeteer_response: {}, + }); + queryNonNativeRewardsReceivers = + async (): Promise => + this.client.queryContractSmart(this.contractAddress, { + non_native_rewards_receivers: {}, + }); + bond = async ( + sender: string, + args: BondArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { bond: args }, + fee || 'auto', + memo, + funds, + ); + }; + unbond = async ( + sender: string, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { unbond: {} }, + fee || 'auto', + memo, + funds, + ); + }; + updateConfig = async ( + sender: string, + args: UpdateConfigArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { update_config: args }, + fee || 'auto', + memo, + funds, + ); + }; + updateNonNativeRewardsReceivers = async ( + sender: string, + args: UpdateNonNativeRewardsReceiversArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { update_non_native_rewards_receivers: args }, + fee || 'auto', + memo, + funds, + ); + }; + fakeProcessBatch = async ( + sender: string, + args: FakeProcessBatchArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { fake_process_batch: args }, + fee || 'auto', + memo, + funds, + ); + }; + tick = async ( + sender: string, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { tick: {} }, + fee || 'auto', + memo, + funds, + ); + }; + puppeteerHook = async ( + sender: string, + args: PuppeteerHookArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { puppeteer_hook: args }, + fee || 'auto', + memo, + funds, + ); + }; + updateOwnership = async ( + sender: string, + args: UpdateOwnershipArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { update_ownership: args }, + fee || 'auto', + memo, + funds, + ); + }; } diff --git a/integration_tests/src/generated/contractLib/lidoFactory.ts b/integration_tests/src/generated/contractLib/lidoFactory.ts index 24c151d1..f3130d9d 100644 --- a/integration_tests/src/generated/contractLib/lidoFactory.ts +++ b/integration_tests/src/generated/contractLib/lidoFactory.ts @@ -1,6 +1,11 @@ -import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult, InstantiateResult } from "@cosmjs/cosmwasm-stargate"; -import { StdFee } from "@cosmjs/amino"; -import { Coin } from "@cosmjs/amino"; +import { + CosmWasmClient, + SigningCosmWasmClient, + ExecuteResult, + InstantiateResult, +} from '@cosmjs/cosmwasm-stargate'; +import { StdFee } from '@cosmjs/amino'; +import { Coin } from '@cosmjs/amino'; export interface InstantiateMsg { code_ids: CodeIds; remote_opts: RemoteOpts; @@ -69,6 +74,12 @@ export type UpdateConfigArgs = | { puppeteer_fees: FeesMsg; }; +/** + * A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 + * + * The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) + */ +export type Decimal = string; /** * A human readable address. * @@ -125,7 +136,12 @@ export type Binary = string; export interface LidoFactorySchema { responses: State; - execute: InitArgs | CallbackArgs | UpdateConfigArgs | ProxyArgs | AdminExecuteArgs; + execute: + | InitArgs + | CallbackArgs + | UpdateConfigArgs + | ProxyArgs + | AdminExecuteArgs; [k: string]: unknown; } export interface State { @@ -153,7 +169,8 @@ export interface CoreParams { } export interface ConfigOptional { base_denom?: string | null; - channel?: string | null; + fee?: Decimal | null; + fee_address?: string | null; idle_min_interval?: number | null; ld_denom?: string | null; owner?: string | null; @@ -188,6 +205,8 @@ export interface ValidatorData { export interface NonNativeRewardsItem { address: string; denom: string; + fee: Decimal; + fee_address: string; min_amount: Uint128; } export interface AdminExecuteArgs { @@ -195,9 +214,8 @@ export interface AdminExecuteArgs { msg: Binary; } - function isSigningCosmWasmClient( - client: CosmWasmClient | SigningCosmWasmClient + client: CosmWasmClient | SigningCosmWasmClient, ): client is SigningCosmWasmClient { return 'execute' in client; } @@ -205,12 +223,15 @@ function isSigningCosmWasmClient( export class Client { private readonly client: CosmWasmClient | SigningCosmWasmClient; contractAddress: string; - constructor(client: CosmWasmClient | SigningCosmWasmClient, contractAddress: string) { + constructor( + client: CosmWasmClient | SigningCosmWasmClient, + contractAddress: string, + ) { this.client = client; this.contractAddress = contractAddress; } mustBeSigningClient() { - return new Error("This client is not a SigningCosmWasmClient"); + return new Error('This client is not a SigningCosmWasmClient'); } static async instantiate( client: SigningCosmWasmClient, @@ -226,27 +247,101 @@ export class Client { }); return res; } - queryState = async(): Promise => { - return this.client.queryContractSmart(this.contractAddress, { state: {} }); - } - init = async(sender:string, args: InitArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { init: args }, fee || "auto", memo, funds); - } - callback = async(sender:string, args: CallbackArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { callback: args }, fee || "auto", memo, funds); - } - updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { update_config: args }, fee || "auto", memo, funds); - } - proxy = async(sender:string, args: ProxyArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { proxy: args }, fee || "auto", memo, funds); - } - adminExecute = async(sender:string, args: AdminExecuteArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise => { - if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); } - return this.client.execute(sender, this.contractAddress, { admin_execute: args }, fee || "auto", memo, funds); - } + queryState = async (): Promise => + this.client.queryContractSmart(this.contractAddress, { state: {} }); + init = async ( + sender: string, + args: InitArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { init: args }, + fee || 'auto', + memo, + funds, + ); + }; + callback = async ( + sender: string, + args: CallbackArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { callback: args }, + fee || 'auto', + memo, + funds, + ); + }; + updateConfig = async ( + sender: string, + args: UpdateConfigArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { update_config: args }, + fee || 'auto', + memo, + funds, + ); + }; + proxy = async ( + sender: string, + args: ProxyArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { proxy: args }, + fee || 'auto', + memo, + funds, + ); + }; + adminExecute = async ( + sender: string, + args: AdminExecuteArgs, + fee?: number | StdFee | 'auto', + memo?: string, + funds?: Coin[], + ): Promise => { + if (!isSigningCosmWasmClient(this.client)) { + throw this.mustBeSigningClient(); + } + return this.client.execute( + sender, + this.contractAddress, + { admin_execute: args }, + fee || 'auto', + memo, + funds, + ); + }; } diff --git a/packages/base/src/msg/core.rs b/packages/base/src/msg/core.rs index 53f8bf7a..4d7ccbb4 100644 --- a/packages/base/src/msg/core.rs +++ b/packages/base/src/msg/core.rs @@ -22,8 +22,8 @@ pub struct InstantiateMsg { pub pump_address: Option, pub channel: String, pub owner: String, - pub fee: Decimal, - pub fee_address: String, + pub fee: Option, + pub fee_address: Option, } #[cw_serde] diff --git a/packages/base/src/state/core.rs b/packages/base/src/state/core.rs index 39c77e03..63be5296 100644 --- a/packages/base/src/state/core.rs +++ b/packages/base/src/state/core.rs @@ -25,8 +25,8 @@ pub struct Config { pub owner: String, pub channel: String, pub ld_denom: Option, - pub fee: Decimal, - pub fee_address: String, + pub fee: Option, + pub fee_address: Option, } pub const CONFIG: Item = Item::new("config"); From f36b37f019636c7be86ba874010049cd5bc56a15 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Thu, 29 Feb 2024 15:58:32 +0200 Subject: [PATCH 05/10] fix after rebase --- contracts/core/src/contract.rs | 3 +++ integration_tests/src/testcases/core.fsm.test.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 3c4b7d70..dde14e2b 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -1119,6 +1119,8 @@ mod check_denom { } Ok(DenomType::LsmShare) + } +} #[cfg(test)] mod tests { use std::marker::PhantomData; @@ -1257,6 +1259,7 @@ mod tests { pump_address: None, owner: "owner".to_string(), ld_denom: None, + channel: "channel".to_string(), fee, fee_address: Some("fee_address".to_string()), } diff --git a/integration_tests/src/testcases/core.fsm.test.ts b/integration_tests/src/testcases/core.fsm.test.ts index d990516c..32e343bd 100644 --- a/integration_tests/src/testcases/core.fsm.test.ts +++ b/integration_tests/src/testcases/core.fsm.test.ts @@ -1081,6 +1081,8 @@ describe('Core', () => { denom, address: context.gaiaUserAddress, min_amount: '10000', + fee: '0', + fee_address: 'fee_address', })), }, }, From 4e9a394df789d64bc10e6c20aef61966f21cb0dc Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Fri, 1 Mar 2024 13:49:54 +0200 Subject: [PATCH 06/10] Refactor code --- contracts/core/src/contract.rs | 449 +++------------------------------ contracts/core/src/lib.rs | 3 + contracts/core/src/tests.rs | 366 +++++++++++++++++++++++++++ 3 files changed, 401 insertions(+), 417 deletions(-) create mode 100644 contracts/core/src/tests.rs diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index dde14e2b..cb7ff408 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -250,12 +250,9 @@ fn execute_tick_idle( let mut messages = vec![]; if env.block.time.seconds() - last_idle_call < config.idle_min_interval { //process non-native rewards - if let Some(transfer_msgs) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? - { - messages.push(transfer_msgs.0); - if let Some(fee_msg) = transfer_msgs.1 { - messages.push(fee_msg); - } + let transfer_msgs = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)?; + if !transfer_msgs.is_empty() { + messages.extend(transfer_msgs); } else { //return error if none return Err(ContractError::IdleMinIntervalIsNotReached {}); @@ -321,10 +318,7 @@ fn execute_tick_idle( messages.push(transfer_msg); } else { let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; - messages.push(all_msgs.0); - if let Some(fee_msg) = all_msgs.1 { - messages.push(fee_msg); - } + messages.extend(all_msgs); FSM.go_to(deps.storage, ContractState::Staking)?; } } else { @@ -388,10 +382,7 @@ fn execute_tick_claiming( messages.push(transfer_msg); } else { let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; - messages.push(all_msgs.0); - if let Some(fee_msg) = all_msgs.1 { - messages.push(fee_msg); - } + messages.extend(all_msgs); FSM.go_to(deps.storage, ContractState::Staking)?; } attrs.push(attr("state", "unbonding")); @@ -406,13 +397,8 @@ fn execute_tick_transfering( ) -> ContractResult> { let _response_msg = get_received_puppeteer_response(deps.as_ref())?; LAST_PUPPETEER_RESPONSE.remove(deps.storage); - let stake_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + let messages = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; FSM.go_to(deps.storage, ContractState::Staking)?; - let mut messages = vec![]; - messages.push(stake_msgs.0); - if let Some(fee_msg) = stake_msgs.1 { - messages.push(fee_msg); - } Ok(response( "execute-tick_transfering", @@ -820,7 +806,7 @@ pub fn get_stake_msg( env: &Env, config: &Config, funds: Vec, -) -> ContractResult> { +) -> ContractResult>> { let (balance, balance_height) = get_ica_balance_by_denom( deps, &config.puppeteer_contract, @@ -848,7 +834,9 @@ pub fn get_stake_msg( }, )?; - let delegate_msg = CosmosMsg::Wasm(WasmMsg::Execute { + let mut messages = vec![]; + + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract.to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { items: to_delegate @@ -859,10 +847,10 @@ pub fn get_stake_msg( reply_to: env.contract.address.to_string(), })?, funds, - }); + })); - let fee_msg = if fee > Uint128::zero() && config.fee_address.is_some() { - Some(CosmosMsg::Wasm(WasmMsg::Execute { + if fee > Uint128::zero() && config.fee_address.is_some() { + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract.to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { items: vec![( @@ -876,12 +864,10 @@ pub fn get_stake_msg( reply_to: env.contract.address.to_string(), })?, funds: vec![], - })) - } else { - None - }; + })); + } - Ok((delegate_msg, fee_msg)) + Ok(messages) } fn get_received_puppeteer_response( @@ -961,7 +947,7 @@ pub fn get_non_native_rewards_transfer_msg( deps: Deps, info: MessageInfo, env: Env, -) -> ContractResult>> { +) -> ContractResult>> { let config = CONFIG.load(deps.storage)?; let non_native_rewards_receivers = NON_NATIVE_REWARDS_CONFIG.load(deps.storage)?; let mut items = vec![]; @@ -1007,21 +993,21 @@ pub fn get_non_native_rewards_transfer_msg( } } - if items.is_empty() { - return Ok(None); + let mut messages = vec![]; + if !items.is_empty() { + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract.clone(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items, + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: info.funds, + })) } - let transfer_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.clone(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items, - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: info.funds, - }); - let fee_msg = if !fees.is_empty() { - Some(CosmosMsg::Wasm(WasmMsg::Execute { + if !fees.is_empty() { + messages.push(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract, msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { items: fees, @@ -1030,11 +1016,9 @@ pub fn get_non_native_rewards_transfer_msg( })?, funds: vec![], })) - } else { - None - }; + } - Ok(Some((transfer_msg, fee_msg))) + Ok(messages) } mod check_denom { @@ -1121,372 +1105,3 @@ mod check_denom { Ok(DenomType::LsmShare) } } -#[cfg(test)] -mod tests { - use std::marker::PhantomData; - - use cosmwasm_std::{ - from_json, - testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}, - Coin, ContractResult, Empty, OwnedDeps, Querier, QuerierResult, QueryRequest, SystemError, - SystemResult, WasmQuery, - }; - - use lido_puppeteer_base::msg::QueryMsg as PuppeteerBaseQueryMsg; - use lido_staking_base::msg::puppeteer::{MultiBalances, QueryExtMsg}; - use lido_staking_base::msg::strategy::QueryMsg as StategyQueryMsg; - use neutron_sdk::interchain_queries::v045::types::Balances; - - use super::*; - - pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; - pub const MOCK_STRATEGY_CONTRACT_ADDR: &str = "strategy_contract"; - - fn mock_dependencies() -> OwnedDeps { - let custom_querier = WasmMockQuerier::new(MockQuerier::new(&[])); - - OwnedDeps { - storage: MockStorage::default(), - api: MockApi::default(), - querier: custom_querier, - custom_query_type: PhantomData, - } - } - - pub struct WasmMockQuerier { - base: MockQuerier, - } - - impl Querier for WasmMockQuerier { - fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { - let request: QueryRequest = match from_json(bin_request) { - Ok(v) => v, - Err(e) => { - return QuerierResult::Err(SystemError::InvalidRequest { - error: format!("Parsing query request: {}", e), - request: bin_request.into(), - }); - } - }; - self.handle_query(&request) - } - } - - impl WasmMockQuerier { - pub fn handle_query(&self, request: &QueryRequest) -> QuerierResult { - match &request { - QueryRequest::Wasm(WasmQuery::Smart { contract_addr, msg }) => { - if contract_addr == MOCK_PUPPETEER_CONTRACT_ADDR { - let q: PuppeteerBaseQueryMsg = from_json(msg).unwrap(); - let reply = match q { - PuppeteerBaseQueryMsg::Extention { msg } => match msg { - QueryExtMsg::NonNativeRewardsBalances {} => { - let data = ( - MultiBalances { - coins: vec![Coin { - denom: "denom".to_string(), - amount: Uint128::new(150), - }], - }, - 10, - ); - to_json_binary(&(data.0, data.1)) - } - QueryExtMsg::Balances {} => { - let data = ( - Balances { - coins: vec![Coin { - denom: "remote_denom".to_string(), - amount: Uint128::new(200), - }], - }, - 10, - ); - to_json_binary(&(data.0, data.1)) - } - _ => todo!(), - }, - _ => todo!(), - }; - return SystemResult::Ok(ContractResult::from(reply)); - } - if contract_addr == MOCK_STRATEGY_CONTRACT_ADDR { - let q: StategyQueryMsg = from_json(msg).unwrap(); - let reply = match q { - StategyQueryMsg::CalcDeposit { deposit } => to_json_binary(&vec![ - lido_staking_base::msg::distribution::IdealDelegation { - valoper_address: "valoper_address".to_string(), - stake_change: deposit, - ideal_stake: deposit, - current_stake: deposit, - weight: 1u64, - }, - ]), - _ => todo!(), - }; - return SystemResult::Ok(ContractResult::from(reply)); - } - SystemResult::Err(SystemError::NoSuchContract { - addr: contract_addr.to_string(), - }) - } - _ => self.base.handle_query(request), - } - } - } - - impl WasmMockQuerier { - pub fn new(base: MockQuerier) -> WasmMockQuerier { - WasmMockQuerier { base } - } - } - - fn get_default_config(fee: Option) -> Config { - Config { - token_contract: "token_contract".to_string(), - puppeteer_contract: MOCK_PUPPETEER_CONTRACT_ADDR.to_string(), - puppeteer_timeout: 60, - strategy_contract: MOCK_STRATEGY_CONTRACT_ADDR.to_string(), - withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), - withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), - validators_set_contract: "validators_set_contract".to_string(), - base_denom: "base_denom".to_string(), - remote_denom: "remote_denom".to_string(), - idle_min_interval: 1, - unbonding_period: 60, - unbonding_safe_period: 10, - unbond_batch_switch_time: 6000, - pump_address: None, - owner: "owner".to_string(), - ld_denom: None, - channel: "channel".to_string(), - fee, - fee_address: Some("fee_address".to_string()), - } - } - - fn setup_config(deps: &mut OwnedDeps) { - CONFIG - .save( - deps.as_mut().storage, - &get_default_config(Decimal::from_atomics(1u32, 1).ok()), - ) - .unwrap(); - } - - #[test] - fn get_non_native_rewards_transfer_msg_success() { - let mut deps = mock_dependencies(); - - setup_config(&mut deps); - - NON_NATIVE_REWARDS_CONFIG - .save( - deps.as_mut().storage, - &vec![NonNativeRewardsItem { - address: "address".to_string(), - denom: "denom".to_string(), - min_amount: Uint128::new(100), - fee: Decimal::from_atomics(1u32, 1).unwrap(), - fee_address: "fee_address".to_string(), - }], - ) - .unwrap(); - - let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); - - let result: (CosmosMsg, Option>) = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) - .unwrap() - .unwrap(); - - let first_tx = result.0; - let second_tx = result.1; - - assert_eq!( - first_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "address".to_string(), - Coin { - denom: "denom".to_string(), - amount: Uint128::new(135) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![Coin::new(1000, "untrn")] - }) - ); - - assert_eq!( - second_tx.unwrap(), - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "fee_address".to_string(), - Coin { - denom: "denom".to_string(), - amount: Uint128::new(15) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![] - }) - ); - } - - #[test] - fn get_non_native_rewards_transfer_msg_zero_fee() { - let mut deps = mock_dependencies(); - - setup_config(&mut deps); - - NON_NATIVE_REWARDS_CONFIG - .save( - deps.as_mut().storage, - &vec![NonNativeRewardsItem { - address: "address".to_string(), - denom: "denom".to_string(), - min_amount: Uint128::new(100), - fee: Decimal::zero(), - fee_address: "fee_address".to_string(), - }], - ) - .unwrap(); - - let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); - - let result: (CosmosMsg, Option>) = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) - .unwrap() - .unwrap(); - - let first_tx = result.0; - let second_tx = result.1; - - assert_eq!( - first_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "address".to_string(), - Coin { - denom: "denom".to_string(), - amount: Uint128::new(150) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![Coin::new(1000, "untrn")] - }) - ); - - assert!(second_tx.is_none()); - } - - #[test] - fn get_stake_msg_success() { - let mut deps = mock_dependencies(); - - setup_config(&mut deps); - - LAST_ICA_BALANCE_CHANGE_HEIGHT - .save(deps.as_mut().storage, &1) - .unwrap(); - - let result: (CosmosMsg, Option>) = get_stake_msg( - deps.as_ref(), - &mock_env(), - &get_default_config(Decimal::from_atomics(1u32, 1).ok()), - vec![], - ) - .unwrap(); - - let first_tx = result.0; - let second_tx = result.1; - - assert_eq!( - first_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { - items: vec![("valoper_address".to_string(), Uint128::new(180))], - timeout: Some(60), - reply_to: "cosmos2contract".to_string(), - }) - .unwrap(), - funds: vec![], - }) - ); - - assert_eq!( - second_tx.unwrap(), - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "fee_address".to_string(), - Coin { - denom: "remote_denom".to_string(), - amount: Uint128::new(20) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![] - }) - ); - } - - #[test] - fn get_stake_msg_zero_fee() { - let mut deps = mock_dependencies(); - - setup_config(&mut deps); - - LAST_ICA_BALANCE_CHANGE_HEIGHT - .save(deps.as_mut().storage, &1) - .unwrap(); - - let result: (CosmosMsg, Option>) = get_stake_msg( - deps.as_ref(), - &mock_env(), - &get_default_config(None), - vec![], - ) - .unwrap(); - - let first_tx = result.0; - let second_tx = result.1; - - assert_eq!( - first_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { - items: vec![("valoper_address".to_string(), Uint128::new(200))], - timeout: Some(60), - reply_to: "cosmos2contract".to_string(), - }) - .unwrap(), - funds: vec![], - }) - ); - - assert!(second_tx.is_none()); - } -} diff --git a/contracts/core/src/lib.rs b/contracts/core/src/lib.rs index ed729875..eacc6df2 100644 --- a/contracts/core/src/lib.rs +++ b/contracts/core/src/lib.rs @@ -1,2 +1,5 @@ pub mod contract; pub mod error; + +#[cfg(test)] +mod tests; diff --git a/contracts/core/src/tests.rs b/contracts/core/src/tests.rs new file mode 100644 index 00000000..ad5bd6cd --- /dev/null +++ b/contracts/core/src/tests.rs @@ -0,0 +1,366 @@ +use std::marker::PhantomData; + +use cosmwasm_std::{ + from_json, + testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}, + to_json_binary, Coin, ContractResult, CosmosMsg, Decimal, Empty, OwnedDeps, Querier, + QuerierResult, QueryRequest, SystemError, SystemResult, Uint128, WasmMsg, WasmQuery, +}; + +use lido_puppeteer_base::msg::QueryMsg as PuppeteerBaseQueryMsg; +use lido_staking_base::{ + msg::puppeteer::{MultiBalances, QueryExtMsg}, + state::core::{ + Config, NonNativeRewardsItem, LAST_ICA_BALANCE_CHANGE_HEIGHT, NON_NATIVE_REWARDS_CONFIG, + }, +}; +use lido_staking_base::{msg::strategy::QueryMsg as StategyQueryMsg, state::core::CONFIG}; +use neutron_sdk::{ + bindings::{msg::NeutronMsg, query::NeutronQuery}, + interchain_queries::v045::types::Balances, +}; + +use crate::contract::{get_non_native_rewards_transfer_msg, get_stake_msg}; + +pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; +pub const MOCK_STRATEGY_CONTRACT_ADDR: &str = "strategy_contract"; + +fn mock_dependencies() -> OwnedDeps { + let custom_querier = WasmMockQuerier::new(MockQuerier::new(&[])); + + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: custom_querier, + custom_query_type: PhantomData, + } +} + +pub struct WasmMockQuerier { + base: MockQuerier, +} + +impl Querier for WasmMockQuerier { + fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { + let request: QueryRequest = match from_json(bin_request) { + Ok(v) => v, + Err(e) => { + return QuerierResult::Err(SystemError::InvalidRequest { + error: format!("Parsing query request: {}", e), + request: bin_request.into(), + }); + } + }; + self.handle_query(&request) + } +} + +impl WasmMockQuerier { + pub fn handle_query(&self, request: &QueryRequest) -> QuerierResult { + match &request { + QueryRequest::Wasm(WasmQuery::Smart { contract_addr, msg }) => { + if contract_addr == MOCK_PUPPETEER_CONTRACT_ADDR { + let q: PuppeteerBaseQueryMsg = from_json(msg).unwrap(); + let reply = match q { + PuppeteerBaseQueryMsg::Extention { msg } => match msg { + QueryExtMsg::NonNativeRewardsBalances {} => { + let data = ( + MultiBalances { + coins: vec![Coin { + denom: "denom".to_string(), + amount: Uint128::new(150), + }], + }, + 10, + ); + to_json_binary(&(data.0, data.1)) + } + QueryExtMsg::Balances {} => { + let data = ( + Balances { + coins: vec![Coin { + denom: "remote_denom".to_string(), + amount: Uint128::new(200), + }], + }, + 10, + ); + to_json_binary(&(data.0, data.1)) + } + _ => todo!(), + }, + _ => todo!(), + }; + return SystemResult::Ok(ContractResult::from(reply)); + } + if contract_addr == MOCK_STRATEGY_CONTRACT_ADDR { + let q: StategyQueryMsg = from_json(msg).unwrap(); + let reply = match q { + StategyQueryMsg::CalcDeposit { deposit } => to_json_binary(&vec![ + lido_staking_base::msg::distribution::IdealDelegation { + valoper_address: "valoper_address".to_string(), + stake_change: deposit, + ideal_stake: deposit, + current_stake: deposit, + weight: 1u64, + }, + ]), + _ => todo!(), + }; + return SystemResult::Ok(ContractResult::from(reply)); + } + SystemResult::Err(SystemError::NoSuchContract { + addr: contract_addr.to_string(), + }) + } + _ => self.base.handle_query(request), + } + } +} + +impl WasmMockQuerier { + pub fn new(base: MockQuerier) -> WasmMockQuerier { + WasmMockQuerier { base } + } +} + +fn get_default_config(fee: Option) -> Config { + Config { + token_contract: "token_contract".to_string(), + puppeteer_contract: MOCK_PUPPETEER_CONTRACT_ADDR.to_string(), + puppeteer_timeout: 60, + strategy_contract: MOCK_STRATEGY_CONTRACT_ADDR.to_string(), + withdrawal_voucher_contract: "withdrawal_voucher_contract".to_string(), + withdrawal_manager_contract: "withdrawal_manager_contract".to_string(), + validators_set_contract: "validators_set_contract".to_string(), + base_denom: "base_denom".to_string(), + remote_denom: "remote_denom".to_string(), + idle_min_interval: 1, + unbonding_period: 60, + unbonding_safe_period: 10, + unbond_batch_switch_time: 6000, + pump_address: None, + owner: "owner".to_string(), + ld_denom: None, + channel: "channel".to_string(), + fee, + fee_address: Some("fee_address".to_string()), + } +} + +fn setup_config(deps: &mut OwnedDeps) { + CONFIG + .save( + deps.as_mut().storage, + &get_default_config(Decimal::from_atomics(1u32, 1).ok()), + ) + .unwrap(); +} + +#[test] +fn get_non_native_rewards_transfer_msg_success() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + NON_NATIVE_REWARDS_CONFIG + .save( + deps.as_mut().storage, + &vec![NonNativeRewardsItem { + address: "address".to_string(), + denom: "denom".to_string(), + min_amount: Uint128::new(100), + fee: Decimal::from_atomics(1u32, 1).unwrap(), + fee_address: "fee_address".to_string(), + }], + ) + .unwrap(); + + let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); + + let result: Vec> = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()).unwrap(); + + let first_tx = result[0].clone(); + let second_tx = result[1].clone(); + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(135) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![Coin::new(1000, "untrn")] + }) + ); + + assert_eq!( + second_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "fee_address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(15) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![] + }) + ); +} + +#[test] +fn get_non_native_rewards_transfer_msg_zero_fee() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + NON_NATIVE_REWARDS_CONFIG + .save( + deps.as_mut().storage, + &vec![NonNativeRewardsItem { + address: "address".to_string(), + denom: "denom".to_string(), + min_amount: Uint128::new(100), + fee: Decimal::zero(), + fee_address: "fee_address".to_string(), + }], + ) + .unwrap(); + + let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); + + let result: Vec> = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()).unwrap(); + + assert_eq!(result.len(), 1); + let first_tx: CosmosMsg = result[0].clone(); + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(150) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![Coin::new(1000, "untrn")] + }) + ); +} + +#[test] +fn get_stake_msg_success() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + LAST_ICA_BALANCE_CHANGE_HEIGHT + .save(deps.as_mut().storage, &1) + .unwrap(); + + let result: Vec> = get_stake_msg( + deps.as_ref(), + &mock_env(), + &get_default_config(Decimal::from_atomics(1u32, 1).ok()), + vec![], + ) + .unwrap(); + + let first_tx = result[0].clone(); + let second_tx = result[1].clone(); + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { + items: vec![("valoper_address".to_string(), Uint128::new(180))], + timeout: Some(60), + reply_to: "cosmos2contract".to_string(), + }) + .unwrap(), + funds: vec![], + }) + ); + + assert_eq!( + second_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items: vec![( + "fee_address".to_string(), + Coin { + denom: "remote_denom".to_string(), + amount: Uint128::new(20) + } + )], + timeout: Some(60), + reply_to: "cosmos2contract".to_string() + }) + .unwrap(), + funds: vec![] + }) + ); +} + +#[test] +fn get_stake_msg_zero_fee() { + let mut deps = mock_dependencies(); + + setup_config(&mut deps); + + LAST_ICA_BALANCE_CHANGE_HEIGHT + .save(deps.as_mut().storage, &1) + .unwrap(); + + let result: Vec> = get_stake_msg( + deps.as_ref(), + &mock_env(), + &get_default_config(None), + vec![], + ) + .unwrap(); + + assert_eq!(result.len(), 1); + let first_tx = result[0].clone(); + + assert_eq!( + first_tx, + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: "puppeteer_contract".to_string(), + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { + items: vec![("valoper_address".to_string(), Uint128::new(200))], + timeout: Some(60), + reply_to: "cosmos2contract".to_string(), + }) + .unwrap(), + funds: vec![], + }) + ); +} From 73d85ebd7bd13113283e1583c1ec2bcbe489e03d Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Mon, 4 Mar 2024 23:10:20 +0200 Subject: [PATCH 07/10] fixes after tests --- contracts/core/src/contract.rs | 74 +++++++++++-------- contracts/core/src/tests.rs | 65 +++++++--------- contracts/puppeteer/src/contract.rs | 1 + .../src/testcases/core.fsm.test.ts | 15 +++- packages/puppeteer-base/src/execute.rs | 4 + 5 files changed, 89 insertions(+), 70 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index cb7ff408..4de3ac73 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -245,19 +245,23 @@ fn execute_tick_idle( info: MessageInfo, config: &Config, ) -> ContractResult> { + deps.api.debug("WASMDEBUG: tick idle, start"); let mut attrs = vec![attr("action", "tick_idle")]; let last_idle_call = LAST_IDLE_CALL.load(deps.storage)?; let mut messages = vec![]; if env.block.time.seconds() - last_idle_call < config.idle_min_interval { + deps.api.debug("WASMDEBUG: tick idle, 1"); //process non-native rewards - let transfer_msgs = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)?; - if !transfer_msgs.is_empty() { - messages.extend(transfer_msgs); + deps.api.debug("WASMDEBUG: tick idle, 1.1"); + if let Some(transfer_msg) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? { + messages.push(transfer_msg); } else { //return error if none return Err(ContractError::IdleMinIntervalIsNotReached {}); } + deps.api.debug("WASMDEBUG: tick idle, 1.2"); } else { + deps.api.debug("WASMDEBUG: tick idle, 2"); ensure!( !is_unbonding_time_close( deps.as_ref(), @@ -266,6 +270,7 @@ fn execute_tick_idle( )?, ContractError::UnbondingTimeIsClose {} ); + deps.api.debug("WASMDEBUG: tick idle, 3"); let pump_address = config .pump_address .clone() @@ -282,6 +287,7 @@ fn execute_tick_idle( }), None => None, }; + deps.api.debug("WASMDEBUG: tick idle, 4"); let validators: Vec = deps.querier.query_wasm_smart( config.validators_set_contract.to_string(), @@ -308,6 +314,7 @@ fn execute_tick_idle( .map(|d| d.validator.clone()) .collect::>(); FSM.go_to(deps.storage, ContractState::Claiming)?; + deps.api.debug("WASMDEBUG: tick idle, set claiming state"); if validators_to_claim.is_empty() { attrs.push(attr("validators_to_claim", "empty")); if let Some((transfer_msg, pending_amount)) = @@ -317,6 +324,8 @@ fn execute_tick_idle( PENDING_TRANSFER.save(deps.storage, &pending_amount)?; messages.push(transfer_msg); } else { + deps.api.debug("WASMDEBUG: tick idle, get_stake_msg"); + let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; messages.extend(all_msgs); FSM.go_to(deps.storage, ContractState::Staking)?; @@ -339,6 +348,7 @@ fn execute_tick_idle( attrs.push(attr("state", "claiming")); LAST_IDLE_CALL.save(deps.storage, &env.block.time.seconds())?; } + deps.api.debug("WASMDEBUG: tick idle, 5"); Ok(response("execute-tick_idle", CONTRACT_NAME, attrs).add_messages(messages)) } @@ -947,11 +957,12 @@ pub fn get_non_native_rewards_transfer_msg( deps: Deps, info: MessageInfo, env: Env, -) -> ContractResult>> { +) -> ContractResult>> { + deps.api + .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, start"); let config = CONFIG.load(deps.storage)?; let non_native_rewards_receivers = NON_NATIVE_REWARDS_CONFIG.load(deps.storage)?; let mut items = vec![]; - let mut fees = vec![]; let rewards: lido_staking_base::msg::puppeteer::BalancesResponse = deps.querier.query_wasm_smart( config.puppeteer_contract.to_string(), @@ -959,6 +970,8 @@ pub fn get_non_native_rewards_transfer_msg( msg: lido_staking_base::msg::puppeteer::QueryExtMsg::NonNativeRewardsBalances {}, }, )?; + deps.api + .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 1"); let rewards_map = rewards .0 @@ -968,6 +981,14 @@ pub fn get_non_native_rewards_transfer_msg( .collect::>(); let default_amount = Uint128::zero(); + deps.api + .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 2"); + + deps.api.debug(&format!( + "WASMDEBUG: non_native_rewards_receivers: {:?}, rewards: {:?}", + non_native_rewards_receivers, rewards + )); + for item in non_native_rewards_receivers { let amount = rewards_map.get(&item.denom).unwrap_or(&default_amount); if amount > &item.min_amount { @@ -982,7 +1003,7 @@ pub fn get_non_native_rewards_transfer_msg( )); if (item.fee > Decimal::zero()) && (fee > Uint128::zero()) { - fees.push(( + items.push(( item.fee_address, cosmwasm_std::Coin { denom: item.denom, @@ -993,32 +1014,27 @@ pub fn get_non_native_rewards_transfer_msg( } } - let mut messages = vec![]; - if !items.is_empty() { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.clone(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items, - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: info.funds, - })) - } + deps.api + .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 3"); - if !fees.is_empty() { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract, - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: fees, - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: vec![], - })) + deps.api.debug(&format!("WASMDEBUG: items: {:?}", items)); + + if items.is_empty() { + return Ok(None); } - Ok(messages) + deps.api + .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 4"); + + Ok(Some(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: config.puppeteer_contract, + msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { + items, + timeout: Some(config.puppeteer_timeout), + reply_to: env.contract.address.to_string(), + })?, + funds: info.funds, + }))) } mod check_denom { diff --git a/contracts/core/src/tests.rs b/contracts/core/src/tests.rs index ad5bd6cd..906591f9 100644 --- a/contracts/core/src/tests.rs +++ b/contracts/core/src/tests.rs @@ -178,24 +178,32 @@ fn get_non_native_rewards_transfer_msg_success() { let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); - let result: Vec> = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()).unwrap(); - - let first_tx = result[0].clone(); - let second_tx = result[1].clone(); + let result: CosmosMsg = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + .unwrap() + .unwrap(); assert_eq!( - first_tx, + result, CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: "puppeteer_contract".to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "address".to_string(), - Coin { - denom: "denom".to_string(), - amount: Uint128::new(135) - } - )], + items: vec![ + ( + "address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(135) + } + ), + ( + "fee_address".to_string(), + Coin { + denom: "denom".to_string(), + amount: Uint128::new(15) + } + ) + ], timeout: Some(60), reply_to: "cosmos2contract".to_string() }) @@ -203,26 +211,6 @@ fn get_non_native_rewards_transfer_msg_success() { funds: vec![Coin::new(1000, "untrn")] }) ); - - assert_eq!( - second_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "fee_address".to_string(), - Coin { - denom: "denom".to_string(), - amount: Uint128::new(15) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![] - }) - ); } #[test] @@ -246,14 +234,13 @@ fn get_non_native_rewards_transfer_msg_zero_fee() { let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); - let result: Vec> = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()).unwrap(); - - assert_eq!(result.len(), 1); - let first_tx: CosmosMsg = result[0].clone(); + let result: CosmosMsg = + get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + .unwrap() + .unwrap(); assert_eq!( - first_tx, + result, CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: "puppeteer_contract".to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { diff --git a/contracts/puppeteer/src/contract.rs b/contracts/puppeteer/src/contract.rs index da088730..9c502211 100644 --- a/contracts/puppeteer/src/contract.rs +++ b/contracts/puppeteer/src/contract.rs @@ -482,6 +482,7 @@ fn execute_transfer( deps.api.addr_validate(&reply_to)?; let config: Config = puppeteer_base.config.load(deps.storage)?; validate_sender(&config, &info.sender)?; + deps.api.debug("WASMDEBUG: tranexecute_transfer: 1"); puppeteer_base.validate_tx_idle_state(deps.as_ref())?; let ica = puppeteer_base.ica.get_address(deps.storage)?; let mut any_msgs = vec![]; diff --git a/integration_tests/src/testcases/core.fsm.test.ts b/integration_tests/src/testcases/core.fsm.test.ts index 32e343bd..ce5d03ea 100644 --- a/integration_tests/src/testcases/core.fsm.test.ts +++ b/integration_tests/src/testcases/core.fsm.test.ts @@ -52,6 +52,7 @@ describe('Core', () => { contractAddress?: string; wallet?: DirectSecp256k1HdWallet; gaiaWallet?: DirectSecp256k1HdWallet; + gaiaWallet2?: DirectSecp256k1HdWallet; factoryContractClient?: InstanceType; coreContractClient?: InstanceType; strategyContractClient?: InstanceType; @@ -68,6 +69,7 @@ describe('Core', () => { client?: SigningCosmWasmClient; gaiaClient?: SigningStargateClient; gaiaUserAddress?: string; + gaiaUserAddress2?: string; gaiaQueryClient?: QueryClient & StakingExtension & BankExtension; neutronClient?: InstanceType; neutronUserAddress?: string; @@ -106,6 +108,12 @@ describe('Core', () => { prefix: 'cosmos', }, ); + context.gaiaWallet2 = await DirectSecp256k1HdWallet.fromMnemonic( + context.park.config.wallets.demo1.mnemonic, + { + prefix: 'cosmos', + }, + ); context.account = (await context.wallet.getAccounts())[0]; context.neutronClient = new NeutronClient({ apiURL: `http://127.0.0.1:${context.park.ports.neutron.rest}`, @@ -303,6 +311,9 @@ describe('Core', () => { context.gaiaUserAddress = ( await context.gaiaWallet.getAccounts() )[0].address; + context.gaiaUserAddress2 = ( + await context.gaiaWallet2.getAccounts() + )[0].address; context.neutronUserAddress = ( await context.wallet.getAccounts() )[0].address; @@ -1081,8 +1092,8 @@ describe('Core', () => { denom, address: context.gaiaUserAddress, min_amount: '10000', - fee: '0', - fee_address: 'fee_address', + fee: '0.1', + fee_address: context.gaiaUserAddress2, })), }, }, diff --git a/packages/puppeteer-base/src/execute.rs b/packages/puppeteer-base/src/execute.rs index 4d2bdc65..5edc4f39 100644 --- a/packages/puppeteer-base/src/execute.rs +++ b/packages/puppeteer-base/src/execute.rs @@ -58,6 +58,10 @@ where status: TxStateStatus, ) -> NeutronResult<()> { let tx_state = self.tx_state.load(deps.storage).unwrap_or_default(); + deps.api.debug(&format!( + "WASMDEBUG: validate_tx_state: real state: {:?} checked state: {:?}", + tx_state, status + )); ensure_eq!( tx_state.status, status, From 1da2ec3c2fe9488a04265900121a51cce178dbac Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Tue, 5 Mar 2024 14:40:59 +0200 Subject: [PATCH 08/10] fix tests and logic --- contracts/core/src/contract.rs | 98 +++++++++++-------- contracts/core/src/tests.rs | 66 ++++++------- .../src/testcases/core.fsm.test.ts | 7 +- packages/base/src/state/core.rs | 8 ++ 4 files changed, 98 insertions(+), 81 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index 4de3ac73..c59daf17 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -2,17 +2,17 @@ use crate::error::{ContractError, ContractResult}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ attr, ensure, ensure_eq, ensure_ne, entry_point, to_json_binary, Attribute, BankQuery, Binary, - Coin, CosmosMsg, CustomQuery, Decimal, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response, - StdError, StdResult, Timestamp, Uint128, WasmMsg, + Coin, CosmosMsg, CustomQuery, Decimal, Deps, DepsMut, Env, MessageInfo, Order, QueryRequest, + Response, StdError, StdResult, Timestamp, Uint128, WasmMsg, }; use cw2::set_contract_version; use lido_helpers::answer::response; use lido_puppeteer_base::msg::TransferReadyBatchMsg; use lido_staking_base::state::core::{ - Config, ConfigOptional, ContractState, NonNativeRewardsItem, UnbondBatch, UnbondBatchStatus, - UnbondItem, CONFIG, FAILED_BATCH_ID, FSM, LAST_ICA_BALANCE_CHANGE_HEIGHT, - LAST_PUPPETEER_RESPONSE, NON_NATIVE_REWARDS_CONFIG, PENDING_TRANSFER, PRE_UNBONDING_BALANCE, - TOTAL_LSM_SHARES, UNBOND_BATCHES, UNBOND_BATCH_ID, + Config, ConfigOptional, ContractState, FeeItem, NonNativeRewardsItem, UnbondBatch, + UnbondBatchStatus, UnbondItem, COLLECTED_FEES, CONFIG, FAILED_BATCH_ID, FSM, + LAST_ICA_BALANCE_CHANGE_HEIGHT, LAST_PUPPETEER_RESPONSE, NON_NATIVE_REWARDS_CONFIG, + PENDING_TRANSFER, PRE_UNBONDING_BALANCE, TOTAL_LSM_SHARES, UNBOND_BATCHES, UNBOND_BATCH_ID, }; use lido_staking_base::state::validatorset::ValidatorInfo; use lido_staking_base::state::withdrawal_voucher::{Metadata, Trait}; @@ -240,7 +240,7 @@ fn execute_tick( } fn execute_tick_idle( - deps: DepsMut, + mut deps: DepsMut, env: Env, info: MessageInfo, config: &Config, @@ -253,7 +253,9 @@ fn execute_tick_idle( deps.api.debug("WASMDEBUG: tick idle, 1"); //process non-native rewards deps.api.debug("WASMDEBUG: tick idle, 1.1"); - if let Some(transfer_msg) = get_non_native_rewards_transfer_msg(deps.as_ref(), info, env)? { + if let Some(transfer_msg) = + get_non_native_rewards_and_fee_transfer_msg(deps.as_ref(), info, env)? + { messages.push(transfer_msg); } else { //return error if none @@ -326,8 +328,8 @@ fn execute_tick_idle( } else { deps.api.debug("WASMDEBUG: tick idle, get_stake_msg"); - let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; - messages.extend(all_msgs); + let stake_msg = get_stake_msg(deps.branch(), &env, config, info.funds)?; + messages.push(stake_msg); FSM.go_to(deps.storage, ContractState::Staking)?; } } else { @@ -353,7 +355,7 @@ fn execute_tick_idle( } fn execute_tick_claiming( - deps: DepsMut, + mut deps: DepsMut, env: Env, info: MessageInfo, config: &Config, @@ -391,8 +393,8 @@ fn execute_tick_claiming( PENDING_TRANSFER.save(deps.storage, &pending_amount)?; messages.push(transfer_msg); } else { - let all_msgs = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; - messages.extend(all_msgs); + let stake_msg = get_stake_msg(deps.branch(), &env, config, info.funds)?; + messages.push(stake_msg); FSM.go_to(deps.storage, ContractState::Staking)?; } attrs.push(attr("state", "unbonding")); @@ -400,14 +402,14 @@ fn execute_tick_claiming( } fn execute_tick_transfering( - deps: DepsMut, + mut deps: DepsMut, env: Env, info: MessageInfo, config: &Config, ) -> ContractResult> { let _response_msg = get_received_puppeteer_response(deps.as_ref())?; LAST_PUPPETEER_RESPONSE.remove(deps.storage); - let messages = get_stake_msg(deps.as_ref(), &env, config, info.funds)?; + let stake_msg = get_stake_msg(deps.branch(), &env, config, info.funds)?; FSM.go_to(deps.storage, ContractState::Staking)?; Ok(response( @@ -415,7 +417,7 @@ fn execute_tick_transfering( CONTRACT_NAME, vec![attr("action", "tick_transfering"), attr("state", "staking")], ) - .add_messages(messages)) + .add_message(stake_msg)) } fn execute_tick_staking( @@ -812,13 +814,13 @@ fn get_transfer_pending_balance( } pub fn get_stake_msg( - deps: Deps, + deps: DepsMut, env: &Env, config: &Config, funds: Vec, -) -> ContractResult>> { +) -> ContractResult> { let (balance, balance_height) = get_ica_balance_by_denom( - deps, + deps.as_ref(), &config.puppeteer_contract, &config.remote_denom, false, @@ -844,9 +846,22 @@ pub fn get_stake_msg( }, )?; - let mut messages = vec![]; + if fee > Uint128::zero() && config.fee_address.is_some() { + COLLECTED_FEES.update(deps.storage, config.remote_denom.to_string(), |fee_item| { + if let Some(mut fee_item) = fee_item { + fee_item.amount += fee; + Ok::(fee_item) + } else { + Ok(FeeItem { + address: config.fee_address.clone().unwrap(), + denom: config.remote_denom.to_string(), + amount: fee, + }) + } + })?; + }; - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { + Ok(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract.to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { items: to_delegate @@ -857,27 +872,7 @@ pub fn get_stake_msg( reply_to: env.contract.address.to_string(), })?, funds, - })); - - if fee > Uint128::zero() && config.fee_address.is_some() { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.puppeteer_contract.to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - config.fee_address.clone().unwrap().to_string(), - cosmwasm_std::Coin { - denom: config.remote_denom.to_owned(), - amount: fee, - }, - )], - timeout: Some(config.puppeteer_timeout), - reply_to: env.contract.address.to_string(), - })?, - funds: vec![], - })); - } - - Ok(messages) + })) } fn get_received_puppeteer_response( @@ -953,7 +948,7 @@ fn new_unbond(now: u64) -> lido_staking_base::state::core::UnbondBatch { } } -pub fn get_non_native_rewards_transfer_msg( +pub fn get_non_native_rewards_and_fee_transfer_msg( deps: Deps, info: MessageInfo, env: Env, @@ -1014,6 +1009,23 @@ pub fn get_non_native_rewards_transfer_msg( } } + let collected_fees = COLLECTED_FEES + .range_raw(deps.storage, None, None, Order::Ascending) + .map(|item| item.map(|(_key, value)| value)) + .collect::>>()?; + + println!("WASMDEBUG: collected_fees: {:?}", collected_fees); + + for fee_item in collected_fees { + items.push(( + fee_item.address, + cosmwasm_std::Coin { + denom: fee_item.denom, + amount: fee_item.amount, + }, + )); + } + deps.api .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 3"); diff --git a/contracts/core/src/tests.rs b/contracts/core/src/tests.rs index 906591f9..a55aebfb 100644 --- a/contracts/core/src/tests.rs +++ b/contracts/core/src/tests.rs @@ -3,15 +3,16 @@ use std::marker::PhantomData; use cosmwasm_std::{ from_json, testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}, - to_json_binary, Coin, ContractResult, CosmosMsg, Decimal, Empty, OwnedDeps, Querier, - QuerierResult, QueryRequest, SystemError, SystemResult, Uint128, WasmMsg, WasmQuery, + to_json_binary, Coin, ContractResult, CosmosMsg, Decimal, Empty, Order, OwnedDeps, Querier, + QuerierResult, QueryRequest, StdResult, SystemError, SystemResult, Uint128, WasmMsg, WasmQuery, }; use lido_puppeteer_base::msg::QueryMsg as PuppeteerBaseQueryMsg; use lido_staking_base::{ msg::puppeteer::{MultiBalances, QueryExtMsg}, state::core::{ - Config, NonNativeRewardsItem, LAST_ICA_BALANCE_CHANGE_HEIGHT, NON_NATIVE_REWARDS_CONFIG, + Config, FeeItem, NonNativeRewardsItem, COLLECTED_FEES, LAST_ICA_BALANCE_CHANGE_HEIGHT, + NON_NATIVE_REWARDS_CONFIG, }, }; use lido_staking_base::{msg::strategy::QueryMsg as StategyQueryMsg, state::core::CONFIG}; @@ -20,7 +21,7 @@ use neutron_sdk::{ interchain_queries::v045::types::Balances, }; -use crate::contract::{get_non_native_rewards_transfer_msg, get_stake_msg}; +use crate::contract::{get_non_native_rewards_and_fee_transfer_msg, get_stake_msg}; pub const MOCK_PUPPETEER_CONTRACT_ADDR: &str = "puppeteer_contract"; pub const MOCK_STRATEGY_CONTRACT_ADDR: &str = "strategy_contract"; @@ -158,7 +159,7 @@ fn setup_config(deps: &mut OwnedDeps = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + get_non_native_rewards_and_fee_transfer_msg(deps.as_ref(), info, mock_env()) .unwrap() .unwrap(); @@ -214,7 +215,7 @@ fn get_non_native_rewards_transfer_msg_success() { } #[test] -fn get_non_native_rewards_transfer_msg_zero_fee() { +fn get_non_native_rewards_and_fee_transfer_msg_zero_fee() { let mut deps = mock_dependencies(); setup_config(&mut deps); @@ -235,7 +236,7 @@ fn get_non_native_rewards_transfer_msg_zero_fee() { let info = mock_info("addr0000", &[Coin::new(1000, "untrn")]); let result: CosmosMsg = - get_non_native_rewards_transfer_msg(deps.as_ref(), info, mock_env()) + get_non_native_rewards_and_fee_transfer_msg(deps.as_ref(), info, mock_env()) .unwrap() .unwrap(); @@ -270,19 +271,16 @@ fn get_stake_msg_success() { .save(deps.as_mut().storage, &1) .unwrap(); - let result: Vec> = get_stake_msg( - deps.as_ref(), + let stake_msg: CosmosMsg = get_stake_msg( + deps.as_mut(), &mock_env(), &get_default_config(Decimal::from_atomics(1u32, 1).ok()), vec![], ) .unwrap(); - let first_tx = result[0].clone(); - let second_tx = result[1].clone(); - assert_eq!( - first_tx, + stake_msg, CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: "puppeteer_contract".to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { @@ -295,24 +293,21 @@ fn get_stake_msg_success() { }) ); + let collected_fees = COLLECTED_FEES + .range_raw(deps.as_mut().storage, None, None, Order::Ascending) + .map(|item| item.map(|(_key, value)| value)) + .collect::>>() + .unwrap(); + + println!("123: {:?}", collected_fees); + assert_eq!( - second_tx, - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "puppeteer_contract".to_string(), - msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { - items: vec![( - "fee_address".to_string(), - Coin { - denom: "remote_denom".to_string(), - amount: Uint128::new(20) - } - )], - timeout: Some(60), - reply_to: "cosmos2contract".to_string() - }) - .unwrap(), - funds: vec![] - }) + collected_fees[0], + FeeItem { + address: "fee_address".to_string(), + denom: "remote_denom".to_string(), + amount: Uint128::new(20), + } ); } @@ -326,19 +321,16 @@ fn get_stake_msg_zero_fee() { .save(deps.as_mut().storage, &1) .unwrap(); - let result: Vec> = get_stake_msg( - deps.as_ref(), + let stake_msg: CosmosMsg = get_stake_msg( + deps.as_mut(), &mock_env(), &get_default_config(None), vec![], ) .unwrap(); - assert_eq!(result.len(), 1); - let first_tx = result[0].clone(); - assert_eq!( - first_tx, + stake_msg, CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: "puppeteer_contract".to_string(), msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Delegate { diff --git a/integration_tests/src/testcases/core.fsm.test.ts b/integration_tests/src/testcases/core.fsm.test.ts index ce5d03ea..d34ac7bb 100644 --- a/integration_tests/src/testcases/core.fsm.test.ts +++ b/integration_tests/src/testcases/core.fsm.test.ts @@ -1168,7 +1168,12 @@ describe('Core', () => { context.gaiaUserAddress, remoteNonNativeDenoms[0], ); - expect(receiverBalance.amount).toEqual('66666'); + expect(receiverBalance.amount).toEqual('60000'); + const feeBalance = await gaiaClient.getBalance( + context.gaiaUserAddress2, + remoteNonNativeDenoms[0], + ); + expect(feeBalance.amount).toEqual('6666'); // this one is still on ICA as amount is below min_amount const icaBalance = await gaiaClient.getBalance( context.icaAddress, diff --git a/packages/base/src/state/core.rs b/packages/base/src/state/core.rs index 63be5296..c8929e88 100644 --- a/packages/base/src/state/core.rs +++ b/packages/base/src/state/core.rs @@ -125,11 +125,19 @@ pub struct NonNativeRewardsItem { pub fee: Decimal, } +#[cw_serde] +pub struct FeeItem { + pub address: String, + pub denom: String, + pub amount: Uint128, +} + pub const FSM: Fsm = Fsm::new("machine_state", TRANSITIONS); pub const LAST_IDLE_CALL: Item = Item::new("last_tick"); pub const LAST_ICA_BALANCE_CHANGE_HEIGHT: Item = Item::new("last_ica_balance_change_height"); pub const LAST_PUPPETEER_RESPONSE: Item = Item::new("last_puppeteer_response"); +pub const COLLECTED_FEES: Map = Map::new("collected_fees"); pub const FAILED_BATCH_ID: Item = Item::new("failed_batch_id"); pub const PRE_UNBONDING_BALANCE: Item = Item::new("pre_unbonding_balance"); pub const PENDING_TRANSFER: Item = Item::new("pending_transfer"); From 41b279629d523f797e65b027b18a314ae53d7cf5 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Tue, 5 Mar 2024 14:43:40 +0200 Subject: [PATCH 09/10] remove debug info --- contracts/core/src/contract.rs | 33 --------------------------------- contracts/core/src/tests.rs | 2 -- 2 files changed, 35 deletions(-) diff --git a/contracts/core/src/contract.rs b/contracts/core/src/contract.rs index c59daf17..0b43c706 100644 --- a/contracts/core/src/contract.rs +++ b/contracts/core/src/contract.rs @@ -245,14 +245,11 @@ fn execute_tick_idle( info: MessageInfo, config: &Config, ) -> ContractResult> { - deps.api.debug("WASMDEBUG: tick idle, start"); let mut attrs = vec![attr("action", "tick_idle")]; let last_idle_call = LAST_IDLE_CALL.load(deps.storage)?; let mut messages = vec![]; if env.block.time.seconds() - last_idle_call < config.idle_min_interval { - deps.api.debug("WASMDEBUG: tick idle, 1"); //process non-native rewards - deps.api.debug("WASMDEBUG: tick idle, 1.1"); if let Some(transfer_msg) = get_non_native_rewards_and_fee_transfer_msg(deps.as_ref(), info, env)? { @@ -261,9 +258,7 @@ fn execute_tick_idle( //return error if none return Err(ContractError::IdleMinIntervalIsNotReached {}); } - deps.api.debug("WASMDEBUG: tick idle, 1.2"); } else { - deps.api.debug("WASMDEBUG: tick idle, 2"); ensure!( !is_unbonding_time_close( deps.as_ref(), @@ -272,7 +267,6 @@ fn execute_tick_idle( )?, ContractError::UnbondingTimeIsClose {} ); - deps.api.debug("WASMDEBUG: tick idle, 3"); let pump_address = config .pump_address .clone() @@ -289,7 +283,6 @@ fn execute_tick_idle( }), None => None, }; - deps.api.debug("WASMDEBUG: tick idle, 4"); let validators: Vec = deps.querier.query_wasm_smart( config.validators_set_contract.to_string(), @@ -316,7 +309,6 @@ fn execute_tick_idle( .map(|d| d.validator.clone()) .collect::>(); FSM.go_to(deps.storage, ContractState::Claiming)?; - deps.api.debug("WASMDEBUG: tick idle, set claiming state"); if validators_to_claim.is_empty() { attrs.push(attr("validators_to_claim", "empty")); if let Some((transfer_msg, pending_amount)) = @@ -326,8 +318,6 @@ fn execute_tick_idle( PENDING_TRANSFER.save(deps.storage, &pending_amount)?; messages.push(transfer_msg); } else { - deps.api.debug("WASMDEBUG: tick idle, get_stake_msg"); - let stake_msg = get_stake_msg(deps.branch(), &env, config, info.funds)?; messages.push(stake_msg); FSM.go_to(deps.storage, ContractState::Staking)?; @@ -350,7 +340,6 @@ fn execute_tick_idle( attrs.push(attr("state", "claiming")); LAST_IDLE_CALL.save(deps.storage, &env.block.time.seconds())?; } - deps.api.debug("WASMDEBUG: tick idle, 5"); Ok(response("execute-tick_idle", CONTRACT_NAME, attrs).add_messages(messages)) } @@ -953,8 +942,6 @@ pub fn get_non_native_rewards_and_fee_transfer_msg( info: MessageInfo, env: Env, ) -> ContractResult>> { - deps.api - .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, start"); let config = CONFIG.load(deps.storage)?; let non_native_rewards_receivers = NON_NATIVE_REWARDS_CONFIG.load(deps.storage)?; let mut items = vec![]; @@ -965,8 +952,6 @@ pub fn get_non_native_rewards_and_fee_transfer_msg( msg: lido_staking_base::msg::puppeteer::QueryExtMsg::NonNativeRewardsBalances {}, }, )?; - deps.api - .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 1"); let rewards_map = rewards .0 @@ -976,14 +961,6 @@ pub fn get_non_native_rewards_and_fee_transfer_msg( .collect::>(); let default_amount = Uint128::zero(); - deps.api - .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 2"); - - deps.api.debug(&format!( - "WASMDEBUG: non_native_rewards_receivers: {:?}, rewards: {:?}", - non_native_rewards_receivers, rewards - )); - for item in non_native_rewards_receivers { let amount = rewards_map.get(&item.denom).unwrap_or(&default_amount); if amount > &item.min_amount { @@ -1014,8 +991,6 @@ pub fn get_non_native_rewards_and_fee_transfer_msg( .map(|item| item.map(|(_key, value)| value)) .collect::>>()?; - println!("WASMDEBUG: collected_fees: {:?}", collected_fees); - for fee_item in collected_fees { items.push(( fee_item.address, @@ -1026,18 +1001,10 @@ pub fn get_non_native_rewards_and_fee_transfer_msg( )); } - deps.api - .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 3"); - - deps.api.debug(&format!("WASMDEBUG: items: {:?}", items)); - if items.is_empty() { return Ok(None); } - deps.api - .debug("WASMDEBUG: get_non_native_rewards_transfer_msg, 4"); - Ok(Some(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: config.puppeteer_contract, msg: to_json_binary(&lido_staking_base::msg::puppeteer::ExecuteMsg::Transfer { diff --git a/contracts/core/src/tests.rs b/contracts/core/src/tests.rs index a55aebfb..6e574653 100644 --- a/contracts/core/src/tests.rs +++ b/contracts/core/src/tests.rs @@ -299,8 +299,6 @@ fn get_stake_msg_success() { .collect::>>() .unwrap(); - println!("123: {:?}", collected_fees); - assert_eq!( collected_fees[0], FeeItem { From 7ad0d0a450f3486ff04087ed075289c2422e6964 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Tue, 5 Mar 2024 14:45:24 +0200 Subject: [PATCH 10/10] remove deubg info 2 --- contracts/puppeteer/src/contract.rs | 1 - packages/puppeteer-base/src/execute.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/contracts/puppeteer/src/contract.rs b/contracts/puppeteer/src/contract.rs index 9c502211..da088730 100644 --- a/contracts/puppeteer/src/contract.rs +++ b/contracts/puppeteer/src/contract.rs @@ -482,7 +482,6 @@ fn execute_transfer( deps.api.addr_validate(&reply_to)?; let config: Config = puppeteer_base.config.load(deps.storage)?; validate_sender(&config, &info.sender)?; - deps.api.debug("WASMDEBUG: tranexecute_transfer: 1"); puppeteer_base.validate_tx_idle_state(deps.as_ref())?; let ica = puppeteer_base.ica.get_address(deps.storage)?; let mut any_msgs = vec![]; diff --git a/packages/puppeteer-base/src/execute.rs b/packages/puppeteer-base/src/execute.rs index 5edc4f39..4d2bdc65 100644 --- a/packages/puppeteer-base/src/execute.rs +++ b/packages/puppeteer-base/src/execute.rs @@ -58,10 +58,6 @@ where status: TxStateStatus, ) -> NeutronResult<()> { let tx_state = self.tx_state.load(deps.storage).unwrap_or_default(); - deps.api.debug(&format!( - "WASMDEBUG: validate_tx_state: real state: {:?} checked state: {:?}", - tx_state, status - )); ensure_eq!( tx_state.status, status,