From 8afceb59403647aae4d6da05041b42d6d90803e1 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Fri, 10 Jan 2025 12:01:25 +0800 Subject: [PATCH 1/2] Account for unbonding balances when calculating withdrawn rewards --- src/contract.rs | 139 +++++++++++++++++++++++++++++++++--------------- src/msg.rs | 22 +++++++- src/staking.rs | 44 ++++++++++++--- 3 files changed, 154 insertions(+), 51 deletions(-) diff --git a/src/contract.rs b/src/contract.rs index fcb305d..6760c4b 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -16,12 +16,12 @@ use crate::data_structure::EmptyStruct; use crate::error::ContractError; use crate::msg::{ AdminListResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, OpListResponse, QueryMsg, - ShowConfigResponse, ShowInfoResponse, ShowTotalVestedResponse, + ShowConfigResponse, ShowInfoResponse, ShowTotalVestedResponse, StakingQueryExt, }; use crate::permission::{authorize_admin, authorize_op, authorize_self_call}; use crate::staking::{ - delegate, get_all_delegated_validators, get_delegation_rewards, redelegate, undelegate, - withdraw_delegation_rewards, + delegate, get_all_delegated_validators, get_delegation_rewards, get_unbonding_balance, + redelegate, undelegate, withdraw_delegation_rewards, }; use crate::state::{ get_number_of_admins, next_proposal_id, ADMINS, ADMIN_VOTING_THRESHOLD, BALLOTS, DENOM, @@ -37,7 +37,7 @@ const CONTRACT_NAME: &str = "crates.io:sei-gringotts"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub fn validate_migration( - deps: Deps, + deps: Deps, contract_name: &str, contract_version: &str, ) -> Result<(), ContractError> { @@ -57,7 +57,11 @@ pub fn validate_migration( // NOTE: New migrations may need store migrations if store changes are being made #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(deps: DepsMut, env: Env, _msg: MigrateMsg) -> Result { +pub fn migrate( + deps: DepsMut, + env: Env, + _msg: MigrateMsg, +) -> Result { validate_migration(deps.as_ref(), CONTRACT_NAME, CONTRACT_VERSION)?; // set the new version @@ -74,7 +78,10 @@ pub fn migrate(deps: DepsMut, env: Env, _msg: MigrateMsg) -> Result Result { +fn migrate_105_handler( + deps: DepsMut, + env: Env, +) -> Result { if env.contract.address.as_str() == "sei1w0fvamykx7v2e6n5x0e2s39m0jz3krejjkpmgc3tmnqdf8p9fy5syg05yv" { @@ -194,13 +201,16 @@ fn migrate_105_handler(deps: DepsMut, env: Env) -> Result Result { +fn migrate_109_handler( + deps: DepsMut, + env: Env, +) -> Result { Ok(Response::new()) } #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: InstantiateMsg, @@ -253,7 +263,7 @@ pub fn instantiate( #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -331,7 +341,7 @@ pub fn execute( } fn execute_delegate( - deps: Deps, + deps: Deps, info: MessageInfo, validator: String, amount: u128, @@ -344,7 +354,7 @@ fn execute_delegate( } fn execute_redelegate( - deps: Deps, + deps: Deps, info: MessageInfo, src_validator: String, dst_validator: String, @@ -358,7 +368,7 @@ fn execute_redelegate( } fn execute_undelegate( - deps: Deps, + deps: Deps, info: MessageInfo, validator: String, amount: u128, @@ -371,7 +381,7 @@ fn execute_undelegate( } fn execute_initiate_withdraw_unlocked( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, amount: u128, @@ -385,7 +395,7 @@ fn execute_initiate_withdraw_unlocked( } fn execute_initiate_withdraw_reward( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, ) -> Result, ContractError> { @@ -418,7 +428,10 @@ fn execute_initiate_withdraw_reward( // calculationg for now. This would make under-withdraw possible but still impossible to over-withdraw (which is bad). // To avoid under-withdraw, the operator can wait till there is no unbonding amount for the contract when executing // rewards withdrawal. -fn calculate_withdrawn_rewards(deps: Deps, env: Env) -> Result { +fn calculate_withdrawn_rewards( + deps: Deps, + env: Env, +) -> Result { let bank_balance = deps .querier .query_balance(env.contract.address.clone(), DENOM.load(deps.storage)?)? @@ -429,7 +442,7 @@ fn calculate_withdrawn_rewards(deps: Deps, env: Env) -> Result u128 { if del.amount.clone().denom != DENOM.load(deps.storage).unwrap() { @@ -438,9 +451,10 @@ fn calculate_withdrawn_rewards(deps: Deps, env: Env) -> Result Result, info: MessageInfo, op: Addr, remove: bool, @@ -464,7 +478,7 @@ fn execute_update_op( } fn execute_propose_update_admin( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, admin: Addr, @@ -494,7 +508,7 @@ fn execute_propose_update_admin( } fn execute_propose_update_unlocked_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, unlocked_distribution_address: Addr, @@ -520,7 +534,7 @@ fn execute_propose_update_unlocked_distribution_address( } fn execute_propose_update_staking_reward_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, staking_reward_distribution_address: Addr, @@ -546,7 +560,7 @@ fn execute_propose_update_staking_reward_distribution_address( } fn execute_propose_emergency_withdraw( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, dst: Addr, @@ -567,7 +581,7 @@ fn execute_propose_emergency_withdraw( } fn execute_propose_gov_vote( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, gov_proposal_id: u64, @@ -588,7 +602,7 @@ fn execute_propose_gov_vote( } fn execute_propose( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, title: String, @@ -628,7 +642,7 @@ fn execute_propose( } fn execute_vote( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64, @@ -665,7 +679,7 @@ fn execute_vote( } fn execute_process_proposal( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64, @@ -693,7 +707,7 @@ fn execute_process_proposal( } fn execute_internal_update_admin( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, admin: Addr, @@ -709,7 +723,7 @@ fn execute_internal_update_admin( } fn execute_internal_update_unlocked_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, unlocked_distribution_address: Addr, @@ -720,7 +734,7 @@ fn execute_internal_update_unlocked_distribution_address( } fn execute_internal_update_staking_reward_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, staking_reward_distribution_address: Addr, @@ -731,7 +745,7 @@ fn execute_internal_update_staking_reward_distribution_address( } fn execute_internal_withdraw_locked( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, dst: Addr, @@ -750,7 +764,7 @@ fn execute_internal_withdraw_locked( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::ListProposals {} => to_binary(&query_proposals(deps, env)?), QueryMsg::ListVotes { proposal_id } => to_binary(&query_votes(deps, proposal_id)?), @@ -762,7 +776,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { } } -fn query_proposals(deps: Deps, env: Env) -> StdResult { +fn query_proposals(deps: Deps, env: Env) -> StdResult { let proposals: Vec = PROPOSALS .range(deps.storage, None, None, Order::Descending) .map(|p| map_proposal(&env.block, p)) @@ -791,7 +805,7 @@ fn map_proposal( }) } -fn query_votes(deps: Deps, proposal_id: u64) -> StdResult { +fn query_votes(deps: Deps, proposal_id: u64) -> StdResult { let votes = BALLOTS .prefix(proposal_id) .range(deps.storage, None, None, Order::Ascending) @@ -808,7 +822,7 @@ fn query_votes(deps: Deps, proposal_id: u64) -> StdResult { Ok(VoteListResponse { votes }) } -fn query_admins(deps: Deps) -> StdResult { +fn query_admins(deps: Deps) -> StdResult { let admins: Vec = ADMINS .range(deps.storage, None, None, Order::Ascending) .map(|admin| admin.map(|(admin, _)| -> Addr { admin })) @@ -816,7 +830,7 @@ fn query_admins(deps: Deps) -> StdResult { Ok(AdminListResponse { admins }) } -fn query_ops(deps: Deps) -> StdResult { +fn query_ops(deps: Deps) -> StdResult { let ops: Vec = OPS .range(deps.storage, None, None, Order::Ascending) .map(|op| op.map(|(op, _)| -> Addr { op })) @@ -824,7 +838,7 @@ fn query_ops(deps: Deps) -> StdResult { Ok(OpListResponse { ops }) } -fn query_info(deps: Deps) -> StdResult { +fn query_info(deps: Deps) -> StdResult { Ok(ShowInfoResponse { denom: DENOM.load(deps.storage)?, vesting_timestamps: VESTING_TIMESTAMPS.load(deps.storage)?, @@ -837,14 +851,14 @@ fn query_info(deps: Deps) -> StdResult { }) } -fn query_config(deps: Deps) -> StdResult { +fn query_config(deps: Deps) -> StdResult { Ok(ShowConfigResponse { max_voting_period: MAX_VOTING_PERIOD.load(deps.storage)?, admin_voting_threshold: ADMIN_VOTING_THRESHOLD.load(deps.storage)?, }) } -fn query_total_vested(deps: Deps, env: Env) -> StdResult { +fn query_total_vested(deps: Deps, env: Env) -> StdResult { let vested_amount = total_vested_amount(deps.storage, env.block.time)?; Ok(ShowTotalVestedResponse { vested_amount: vested_amount, @@ -853,13 +867,21 @@ fn query_total_vested(deps: Deps, env: Env) -> StdResult OwnedDeps, StakingQueryExt> { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier::new(&[]), + custom_query_type: PhantomData::default(), + } + } + // this will set up the instantiation for other tests #[track_caller] - fn setup_test_case(deps: DepsMut, info: MessageInfo) -> Result, ContractError> { + fn setup_test_case( + deps: DepsMut, + info: MessageInfo, + ) -> Result, ContractError> { let env = mock_env(); let mut vesting_amounts = vec![12000000u128]; let mut vesting_timestamps = vec![env.block.time.plus_seconds(31536000)]; @@ -1154,11 +1189,27 @@ mod tests { }, ], ); - // principal: 48000000 - 1500000 (delegations). Withdrawn rewards: 100 deps.querier.update_balance( mock_env().contract.address.clone(), vec![Coin::new(48000000 - 1500000 + 100, "usei")], ); + // principal: 48000000 - 1500000 (delegations). + // Withdrawn rewards: principal - balance (100) + 10 = 110 + deps.querier = deps.querier.with_custom_handler( + |_: &StakingQueryExt| -> MockQuerierCustomHandlerResult { + let res = UnbondingDelegationsResponse { + entries: vec![UnbondingDelegationEntry { + creation_height: 1, + completion_time: "".to_string(), + initial_balance: Uint128::new(10), + balance: Uint128::new(10), + }], + }; + return MockQuerierCustomHandlerResult::Ok(ContractResult::Ok( + to_json_binary(&res).unwrap(), + )); + }, + ); let info = mock_info(VOTER5, &[Coin::new(48000000, "usei".to_string())]); setup_test_case(deps.as_mut(), info.clone()).unwrap(); @@ -1167,7 +1218,7 @@ mod tests { let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); assert_eq!(5, res.messages.len()); assert_eq!( - 35 + 100, + 35 + 110, WITHDRAWN_STAKING_REWARDS .load(deps.as_ref().storage) .unwrap() diff --git a/src/msg.rs b/src/msg.rs index 81246b6..d48c1d4 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Addr, Timestamp, VoteOption}; +use cosmwasm_std::{Addr, CustomQuery, Timestamp, Uint128, VoteOption}; use cw_utils::{Duration, Threshold}; use crate::data_structure::Tranche; @@ -128,3 +128,23 @@ pub struct ShowConfigResponse { pub struct ShowTotalVestedResponse { pub vested_amount: u128, } + +#[cw_serde] +pub enum StakingQueryExt { + UnbondingDelegations { delegator: String }, +} + +impl CustomQuery for StakingQueryExt {} + +#[cw_serde] +pub struct UnbondingDelegationEntry { + pub creation_height: i64, + pub completion_time: String, + pub initial_balance: Uint128, + pub balance: Uint128, +} + +#[cw_serde] +pub struct UnbondingDelegationsResponse { + pub entries: Vec, +} diff --git a/src/staking.rs b/src/staking.rs index e7f22fd..e4b06b8 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -1,6 +1,11 @@ -use cosmwasm_std::{coins, BankMsg, Coin, Deps, DistributionMsg, Env, Response, StakingMsg}; +use cosmwasm_std::{ + coins, BankMsg, Coin, Deps, DistributionMsg, Env, QueryRequest, Response, StakingMsg, + StdResult, Uint128, +}; +use serde::Deserialize; use crate::{ + msg::{StakingQueryExt, UnbondingDelegationsResponse}, state::{DENOM, STAKING_REWARD_ADDRESS}, ContractError, }; @@ -37,7 +42,7 @@ pub fn undelegate(response: Response, validator: String, amount: u128, denom: St } pub fn withdraw_delegation_rewards( - deps: Deps, + deps: Deps, response: Response, validator: String, amount: u128, @@ -58,7 +63,10 @@ pub fn withdraw_delegation_rewards( // the `all_delegations` endpoint do not return full delegation info (i.e. no withdrawable delegation reward) // so we only return validators here for subsequent logic to query full delegation info one validator at a time -pub fn get_all_delegated_validators(deps: Deps, env: Env) -> Result, ContractError> { +pub fn get_all_delegated_validators( + deps: Deps, + env: Env, +) -> Result, ContractError> { Ok(deps .querier .query_all_delegations(env.contract.address.to_string()) @@ -70,8 +78,21 @@ pub fn get_all_delegated_validators(deps: Deps, env: Env) -> Result, })?) } +pub fn get_unbonding_balance(deps: Deps, env: Env) -> StdResult { + let request = StakingQueryExt::UnbondingDelegations { + delegator: env.contract.address.to_string(), + }; + let wrapped_request = QueryRequest::Custom(request); + let response: UnbondingDelegationsResponse = deps.querier.query(&wrapped_request)?; + Ok(response + .entries + .iter() + .map(|entry| -> u128 { entry.balance.u128() }) + .sum()) +} + pub fn get_delegation_rewards( - deps: Deps, + deps: Deps, env: Env, validator: String, ) -> Result { @@ -93,11 +114,13 @@ pub fn get_delegation_rewards( #[cfg(test)] mod tests { + use core::marker::PhantomData; use cosmwasm_std::{ - testing::{mock_dependencies, mock_env}, - Addr, Coin, Decimal, FullDelegation, Validator, + testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage, MOCK_CONTRACT_ADDR}, + Addr, Coin, Decimal, FullDelegation, OwnedDeps, Validator, }; + use crate::msg::StakingQueryExt; use crate::state::DENOM; use super::get_delegation_rewards; @@ -105,6 +128,15 @@ mod tests { const VALIDATOR: &str = "val"; const DELEGATOR: &str = "del"; + fn mock_dependencies() -> OwnedDeps { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier::default(), + custom_query_type: PhantomData::default(), + } + } + #[test] fn test_get_delegation_rewards_empty() { let mut deps = mock_dependencies(); From b537f215f7269f75bd1b38f800a1150e5923c9aa Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Fri, 10 Jan 2025 18:37:16 +0800 Subject: [PATCH 2/2] fmt --- src/contract.rs | 76 ++++++++++++++++++++++++------------------------- src/msg.rs | 17 +++++++++-- src/staking.rs | 21 ++++++++------ 3 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/contract.rs b/src/contract.rs index 6760c4b..dd286ad 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -16,7 +16,7 @@ use crate::data_structure::EmptyStruct; use crate::error::ContractError; use crate::msg::{ AdminListResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, OpListResponse, QueryMsg, - ShowConfigResponse, ShowInfoResponse, ShowTotalVestedResponse, StakingQueryExt, + SeiQueryWrapper, ShowConfigResponse, ShowInfoResponse, ShowTotalVestedResponse, }; use crate::permission::{authorize_admin, authorize_op, authorize_self_call}; use crate::staking::{ @@ -37,7 +37,7 @@ const CONTRACT_NAME: &str = "crates.io:sei-gringotts"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub fn validate_migration( - deps: Deps, + deps: Deps, contract_name: &str, contract_version: &str, ) -> Result<(), ContractError> { @@ -58,7 +58,7 @@ pub fn validate_migration( // NOTE: New migrations may need store migrations if store changes are being made #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate( - deps: DepsMut, + deps: DepsMut, env: Env, _msg: MigrateMsg, ) -> Result { @@ -79,7 +79,7 @@ pub fn migrate( } fn migrate_105_handler( - deps: DepsMut, + deps: DepsMut, env: Env, ) -> Result { if env.contract.address.as_str() @@ -202,7 +202,7 @@ fn migrate_105_handler( } fn migrate_109_handler( - deps: DepsMut, + deps: DepsMut, env: Env, ) -> Result { Ok(Response::new()) @@ -210,7 +210,7 @@ fn migrate_109_handler( #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: InstantiateMsg, @@ -263,7 +263,7 @@ pub fn instantiate( #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -341,7 +341,7 @@ pub fn execute( } fn execute_delegate( - deps: Deps, + deps: Deps, info: MessageInfo, validator: String, amount: u128, @@ -354,7 +354,7 @@ fn execute_delegate( } fn execute_redelegate( - deps: Deps, + deps: Deps, info: MessageInfo, src_validator: String, dst_validator: String, @@ -368,7 +368,7 @@ fn execute_redelegate( } fn execute_undelegate( - deps: Deps, + deps: Deps, info: MessageInfo, validator: String, amount: u128, @@ -381,7 +381,7 @@ fn execute_undelegate( } fn execute_initiate_withdraw_unlocked( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, amount: u128, @@ -395,7 +395,7 @@ fn execute_initiate_withdraw_unlocked( } fn execute_initiate_withdraw_reward( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, ) -> Result, ContractError> { @@ -429,7 +429,7 @@ fn execute_initiate_withdraw_reward( // To avoid under-withdraw, the operator can wait till there is no unbonding amount for the contract when executing // rewards withdrawal. fn calculate_withdrawn_rewards( - deps: Deps, + deps: Deps, env: Env, ) -> Result { let bank_balance = deps @@ -463,7 +463,7 @@ fn calculate_withdrawn_rewards( } fn execute_update_op( - deps: DepsMut, + deps: DepsMut, info: MessageInfo, op: Addr, remove: bool, @@ -478,7 +478,7 @@ fn execute_update_op( } fn execute_propose_update_admin( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, admin: Addr, @@ -508,7 +508,7 @@ fn execute_propose_update_admin( } fn execute_propose_update_unlocked_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, unlocked_distribution_address: Addr, @@ -534,7 +534,7 @@ fn execute_propose_update_unlocked_distribution_address( } fn execute_propose_update_staking_reward_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, staking_reward_distribution_address: Addr, @@ -560,7 +560,7 @@ fn execute_propose_update_staking_reward_distribution_address( } fn execute_propose_emergency_withdraw( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, dst: Addr, @@ -581,7 +581,7 @@ fn execute_propose_emergency_withdraw( } fn execute_propose_gov_vote( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, gov_proposal_id: u64, @@ -602,7 +602,7 @@ fn execute_propose_gov_vote( } fn execute_propose( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, title: String, @@ -642,7 +642,7 @@ fn execute_propose( } fn execute_vote( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64, @@ -679,7 +679,7 @@ fn execute_vote( } fn execute_process_proposal( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64, @@ -707,7 +707,7 @@ fn execute_process_proposal( } fn execute_internal_update_admin( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, admin: Addr, @@ -723,7 +723,7 @@ fn execute_internal_update_admin( } fn execute_internal_update_unlocked_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, unlocked_distribution_address: Addr, @@ -734,7 +734,7 @@ fn execute_internal_update_unlocked_distribution_address( } fn execute_internal_update_staking_reward_distribution_address( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, staking_reward_distribution_address: Addr, @@ -745,7 +745,7 @@ fn execute_internal_update_staking_reward_distribution_address( } fn execute_internal_withdraw_locked( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, dst: Addr, @@ -764,7 +764,7 @@ fn execute_internal_withdraw_locked( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::ListProposals {} => to_binary(&query_proposals(deps, env)?), QueryMsg::ListVotes { proposal_id } => to_binary(&query_votes(deps, proposal_id)?), @@ -776,7 +776,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult< } } -fn query_proposals(deps: Deps, env: Env) -> StdResult { +fn query_proposals(deps: Deps, env: Env) -> StdResult { let proposals: Vec = PROPOSALS .range(deps.storage, None, None, Order::Descending) .map(|p| map_proposal(&env.block, p)) @@ -805,7 +805,7 @@ fn map_proposal( }) } -fn query_votes(deps: Deps, proposal_id: u64) -> StdResult { +fn query_votes(deps: Deps, proposal_id: u64) -> StdResult { let votes = BALLOTS .prefix(proposal_id) .range(deps.storage, None, None, Order::Ascending) @@ -822,7 +822,7 @@ fn query_votes(deps: Deps, proposal_id: u64) -> StdResult) -> StdResult { +fn query_admins(deps: Deps) -> StdResult { let admins: Vec = ADMINS .range(deps.storage, None, None, Order::Ascending) .map(|admin| admin.map(|(admin, _)| -> Addr { admin })) @@ -830,7 +830,7 @@ fn query_admins(deps: Deps) -> StdResult { Ok(AdminListResponse { admins }) } -fn query_ops(deps: Deps) -> StdResult { +fn query_ops(deps: Deps) -> StdResult { let ops: Vec = OPS .range(deps.storage, None, None, Order::Ascending) .map(|op| op.map(|(op, _)| -> Addr { op })) @@ -838,7 +838,7 @@ fn query_ops(deps: Deps) -> StdResult { Ok(OpListResponse { ops }) } -fn query_info(deps: Deps) -> StdResult { +fn query_info(deps: Deps) -> StdResult { Ok(ShowInfoResponse { denom: DENOM.load(deps.storage)?, vesting_timestamps: VESTING_TIMESTAMPS.load(deps.storage)?, @@ -851,14 +851,14 @@ fn query_info(deps: Deps) -> StdResult { }) } -fn query_config(deps: Deps) -> StdResult { +fn query_config(deps: Deps) -> StdResult { Ok(ShowConfigResponse { max_voting_period: MAX_VOTING_PERIOD.load(deps.storage)?, admin_voting_threshold: ADMIN_VOTING_THRESHOLD.load(deps.storage)?, }) } -fn query_total_vested(deps: Deps, env: Env) -> StdResult { +fn query_total_vested(deps: Deps, env: Env) -> StdResult { let vested_amount = total_vested_amount(deps.storage, env.block.time)?; Ok(ShowTotalVestedResponse { vested_amount: vested_amount, @@ -881,7 +881,7 @@ mod tests { use cw_utils::{Duration, Expiration, ThresholdResponse}; use crate::data_structure::Tranche; - use crate::msg::{StakingQueryExt, UnbondingDelegationEntry, UnbondingDelegationsResponse}; + use crate::msg::{SeiQueryWrapper, UnbondingDelegationEntry, UnbondingDelegationsResponse}; use crate::state::get_number_of_ops; use super::*; @@ -898,7 +898,7 @@ mod tests { const REWARD_ADDR1: &str = "reward0001"; fn mock_dependencies( - ) -> OwnedDeps, StakingQueryExt> { + ) -> OwnedDeps, SeiQueryWrapper> { OwnedDeps { storage: MockStorage::default(), api: MockApi::default(), @@ -910,7 +910,7 @@ mod tests { // this will set up the instantiation for other tests #[track_caller] fn setup_test_case( - deps: DepsMut, + deps: DepsMut, info: MessageInfo, ) -> Result, ContractError> { let env = mock_env(); @@ -1196,7 +1196,7 @@ mod tests { // principal: 48000000 - 1500000 (delegations). // Withdrawn rewards: principal - balance (100) + 10 = 110 deps.querier = deps.querier.with_custom_handler( - |_: &StakingQueryExt| -> MockQuerierCustomHandlerResult { + |_: &SeiQueryWrapper| -> MockQuerierCustomHandlerResult { let res = UnbondingDelegationsResponse { entries: vec![UnbondingDelegationEntry { creation_height: 1, diff --git a/src/msg.rs b/src/msg.rs index d48c1d4..0975ebc 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -130,11 +130,22 @@ pub struct ShowTotalVestedResponse { } #[cw_serde] -pub enum StakingQueryExt { - UnbondingDelegations { delegator: String }, +pub struct SeiQueryWrapper { + pub route: SeiRoute, + pub query_data: SeiQuery, +} + +impl CustomQuery for SeiQueryWrapper {} + +#[cw_serde] +pub enum SeiRoute { + Stakingext, } -impl CustomQuery for StakingQueryExt {} +#[cw_serde] +pub enum SeiQuery { + UnbondingDelegations { delegator: String }, +} #[cw_serde] pub struct UnbondingDelegationEntry { diff --git a/src/staking.rs b/src/staking.rs index e4b06b8..9a24f2a 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{ use serde::Deserialize; use crate::{ - msg::{StakingQueryExt, UnbondingDelegationsResponse}, + msg::{SeiQuery, SeiQueryWrapper, SeiRoute, UnbondingDelegationsResponse}, state::{DENOM, STAKING_REWARD_ADDRESS}, ContractError, }; @@ -42,7 +42,7 @@ pub fn undelegate(response: Response, validator: String, amount: u128, denom: St } pub fn withdraw_delegation_rewards( - deps: Deps, + deps: Deps, response: Response, validator: String, amount: u128, @@ -64,7 +64,7 @@ pub fn withdraw_delegation_rewards( // the `all_delegations` endpoint do not return full delegation info (i.e. no withdrawable delegation reward) // so we only return validators here for subsequent logic to query full delegation info one validator at a time pub fn get_all_delegated_validators( - deps: Deps, + deps: Deps, env: Env, ) -> Result, ContractError> { Ok(deps @@ -78,9 +78,12 @@ pub fn get_all_delegated_validators( })?) } -pub fn get_unbonding_balance(deps: Deps, env: Env) -> StdResult { - let request = StakingQueryExt::UnbondingDelegations { - delegator: env.contract.address.to_string(), +pub fn get_unbonding_balance(deps: Deps, env: Env) -> StdResult { + let request = SeiQueryWrapper { + route: SeiRoute::Stakingext, + query_data: SeiQuery::UnbondingDelegations { + delegator: env.contract.address.to_string(), + }, }; let wrapped_request = QueryRequest::Custom(request); let response: UnbondingDelegationsResponse = deps.querier.query(&wrapped_request)?; @@ -92,7 +95,7 @@ pub fn get_unbonding_balance(deps: Deps, env: Env) -> StdResult } pub fn get_delegation_rewards( - deps: Deps, + deps: Deps, env: Env, validator: String, ) -> Result { @@ -120,7 +123,7 @@ mod tests { Addr, Coin, Decimal, FullDelegation, OwnedDeps, Validator, }; - use crate::msg::StakingQueryExt; + use crate::msg::SeiQueryWrapper; use crate::state::DENOM; use super::get_delegation_rewards; @@ -128,7 +131,7 @@ mod tests { const VALIDATOR: &str = "val"; const DELEGATOR: &str = "del"; - fn mock_dependencies() -> OwnedDeps { + fn mock_dependencies() -> OwnedDeps { OwnedDeps { storage: MockStorage::default(), api: MockApi::default(),