From 1dcbd7ba00a3a9743c005fc08b868e466569cf89 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 16 May 2024 16:55:36 +0100 Subject: [PATCH] test: fix tests --- .../schema/bonding-manager.json | 39 +- .../bonding-manager/schema/raw/query.json | 6 +- .../schema/raw/response_to_claimable.json | 10 +- .../schema/raw/response_to_global_index.json | 10 +- .../schema/raw/response_to_unbonding.json | 13 +- .../bonding-manager/src/bonding/commands.rs | 13 +- .../bonding-manager/src/contract.rs | 6 +- .../bonding-manager/src/helpers.rs | 9 +- .../bonding-manager/src/queries.rs | 50 +-- .../bonding-manager/src/rewards/commands.rs | 16 - .../bonding-manager/src/state.rs | 12 - .../bonding-manager/src/tests/bond.rs | 10 +- .../bonding-manager/src/tests/claim.rs | 2 +- .../bonding-manager/src/tests/helpers.rs | 1 - .../bonding-manager/src/tests/instantiate.rs | 2 +- .../bonding-manager/src/tests/mod.rs | 1 + .../bonding-manager/src/tests/queries.rs | 369 ++++++++++++++++++ .../bonding-manager/src/tests/suite.rs | 23 +- .../src/tests/unbond_withdraw.rs | 36 +- .../white-whale-std/src/bonding_manager.rs | 34 +- 20 files changed, 490 insertions(+), 172 deletions(-) create mode 100644 contracts/liquidity_hub/bonding-manager/src/tests/queries.rs diff --git a/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json b/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json index 9d4a045a..8fe857a7 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json +++ b/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json @@ -488,7 +488,7 @@ "additionalProperties": false }, { - "description": "Returns the weight of the address. Returns the global index of the contract.", + "description": "Returns the global index of the contract.", "type": "object", "required": [ "global_index" @@ -497,8 +497,8 @@ "global_index": { "type": "object", "properties": { - "epoch_id": { - "description": "The epoch id to check for the global index. If none is provided, the current global index is returned.", + "reward_bucket_id": { + "description": "The reward bucket id to check for the global index. If none is provided, the current global index is returned.", "type": [ "integer", "null" @@ -678,8 +678,8 @@ "bonded_amount", "bonded_assets", "epoch_id", - "updated_last", - "weight" + "last_updated", + "last_weight" ], "properties": { "bonded_amount": { @@ -703,14 +703,14 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the total bond was updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, - "weight": { - "description": "The total weight of the bond at the given block height.", + "last_weight": { + "description": "The total weight of the contract at the given updated_last epoch id.", "allOf": [ { "$ref": "#/definitions/Uint128" @@ -863,8 +863,8 @@ "bonded_amount", "bonded_assets", "epoch_id", - "updated_last", - "weight" + "last_updated", + "last_weight" ], "properties": { "bonded_amount": { @@ -888,14 +888,14 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the total bond was updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, - "weight": { - "description": "The total weight of the bond at the given block height.", + "last_weight": { + "description": "The total weight of the contract at the given updated_last epoch id.", "allOf": [ { "$ref": "#/definitions/Uint128" @@ -1094,7 +1094,7 @@ "required": [ "asset", "created_at_epoch", - "updated_last", + "last_updated", "weight" ], "properties": { @@ -1112,12 +1112,21 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the bond was last time updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, + "unbonded_at": { + "description": "The time at which the Bond was unbonded.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, "weight": { "description": "The weight of the bond at the given block height.", "allOf": [ diff --git a/contracts/liquidity_hub/bonding-manager/schema/raw/query.json b/contracts/liquidity_hub/bonding-manager/schema/raw/query.json index 376bbcb4..1dae1f1d 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/bonding-manager/schema/raw/query.json @@ -107,7 +107,7 @@ "additionalProperties": false }, { - "description": "Returns the weight of the address. Returns the global index of the contract.", + "description": "Returns the global index of the contract.", "type": "object", "required": [ "global_index" @@ -116,8 +116,8 @@ "global_index": { "type": "object", "properties": { - "epoch_id": { - "description": "The epoch id to check for the global index. If none is provided, the current global index is returned.", + "reward_bucket_id": { + "description": "The reward bucket id to check for the global index. If none is provided, the current global index is returned.", "type": [ "integer", "null" diff --git a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_claimable.json b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_claimable.json index 351a5b7a..788b95ed 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_claimable.json +++ b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_claimable.json @@ -37,8 +37,8 @@ "bonded_amount", "bonded_assets", "epoch_id", - "updated_last", - "weight" + "last_updated", + "last_weight" ], "properties": { "bonded_amount": { @@ -62,14 +62,14 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the total bond was updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, - "weight": { - "description": "The total weight of the bond at the given block height.", + "last_weight": { + "description": "The total weight of the contract at the given updated_last epoch id.", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_global_index.json b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_global_index.json index 66367c40..6b598589 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_global_index.json +++ b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_global_index.json @@ -6,8 +6,8 @@ "bonded_amount", "bonded_assets", "epoch_id", - "updated_last", - "weight" + "last_updated", + "last_weight" ], "properties": { "bonded_amount": { @@ -31,14 +31,14 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the total bond was updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, - "weight": { - "description": "The total weight of the bond at the given block height.", + "last_weight": { + "description": "The total weight of the contract at the given updated_last epoch id.", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_unbonding.json b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_unbonding.json index ffa51158..5181a615 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_unbonding.json +++ b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_unbonding.json @@ -31,7 +31,7 @@ "required": [ "asset", "created_at_epoch", - "updated_last", + "last_updated", "weight" ], "properties": { @@ -49,12 +49,21 @@ "format": "uint64", "minimum": 0.0 }, - "updated_last": { + "last_updated": { "description": "The epoch id at which the bond was last time updated.", "type": "integer", "format": "uint64", "minimum": 0.0 }, + "unbonded_at": { + "description": "The time at which the Bond was unbonded.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, "weight": { "description": "The weight of the bond at the given block height.", "allOf": [ diff --git a/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs b/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs index 708677d5..7f022c52 100644 --- a/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs @@ -17,9 +17,7 @@ pub(crate) fn bond( _env: Env, asset: Coin, ) -> Result { - println!("----bond----"); helpers::validate_buckets_not_empty(&deps)?; - //todo maybe claim for the user helpers::validate_claimed(&deps, &info)?; helpers::validate_bonding_for_current_epoch(&deps)?; @@ -43,7 +41,7 @@ pub(crate) fn bond( ..Bond::default() }); - // update local values + // update bond values bond = update_bond_weight(&mut deps, info.sender.clone(), current_epoch.epoch.id, bond)?; bond.asset.amount = bond.asset.amount.checked_add(asset.amount)?; bond.weight = bond.weight.checked_add(asset.amount)?; @@ -52,12 +50,8 @@ pub(crate) fn bond( // update global values let mut global_index = GLOBAL.load(deps.storage)?; - // include time term in the weight - - println!("bonding global_index: {:?}", global_index); global_index = update_global_weight(&mut deps, current_epoch.epoch.id, global_index.clone())?; - global_index.last_weight = global_index.last_weight.checked_add(asset.amount)?; global_index.bonded_amount = global_index.bonded_amount.checked_add(asset.amount)?; global_index.bonded_assets = @@ -105,7 +99,7 @@ pub(crate) fn unbond( &white_whale_std::epoch_manager::epoch_manager::QueryMsg::CurrentEpoch {}, )?; - // update local values, decrease the bond + // update bond values, decrease the bond unbond = update_bond_weight( &mut deps, info.sender.clone(), @@ -125,12 +119,13 @@ pub(crate) fn unbond( // record the unbonding UNBOND.save( deps.storage, - (&info.sender, &asset.denom, env.block.time.nanos()), + (&info.sender, &asset.denom, env.block.time.seconds()), &Bond { asset: asset.clone(), weight: Uint128::zero(), last_updated: current_epoch.epoch.id, created_at_epoch: current_epoch.epoch.id, + unbonded_at: Some(env.block.time.seconds()), }, )?; // update global values diff --git a/contracts/liquidity_hub/bonding-manager/src/contract.rs b/contracts/liquidity_hub/bonding-manager/src/contract.rs index bd17d9fb..4afb321c 100644 --- a/contracts/liquidity_hub/bonding-manager/src/contract.rs +++ b/contracts/liquidity_hub/bonding-manager/src/contract.rs @@ -158,9 +158,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&queries::query_global_index( - deps, epoch_id, - )?)?), + QueryMsg::GlobalIndex { reward_bucket_id } => Ok(to_json_binary( + &queries::query_global_index(deps, reward_bucket_id)?, + )?), QueryMsg::Claimable { address } => { Ok(to_json_binary(&queries::query_claimable(&deps, address)?)?) } diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index 7e6390e7..e1513a14 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -90,24 +90,19 @@ pub fn validate_bonding_for_current_epoch(deps: &DepsMut) -> Result<(), Contract // If we do get some LP tokens to withdraw they could be swapped to whale in the reply pub fn handle_lp_tokens_rewards( deps: &DepsMut, - funds: &Vec, + funds: &[Coin], config: &Config, submessages: &mut Vec, ) -> Result<(), ContractError> { - println!("funds: {:?}", funds); let lp_tokens: Vec<&Coin> = funds .iter() .filter(|coin| coin.denom.contains(".pool.") | coin.denom.contains(LP_SYMBOL)) .collect(); - println!("lp_tokens: {:?}", lp_tokens); - for lp_token in lp_tokens { let pool_identifier = extract_pool_identifier(&lp_token.denom).ok_or(ContractError::AssetMismatch)?; - println!("pool_identifier: {:?}", pool_identifier); - // make sure a pool with the given identifier exists let pool: StdResult = deps.querier.query_wasm_smart( config.pool_manager_addr.to_string(), @@ -305,7 +300,7 @@ pub fn calculate_rewards( deps, reward_bucket.id, address.to_string(), - Some(reward_bucket.global_index.clone()), + reward_bucket.global_index.clone(), )?; // sanity check, if the user has no share in the bucket, skip it diff --git a/contracts/liquidity_hub/bonding-manager/src/queries.rs b/contracts/liquidity_hub/bonding-manager/src/queries.rs index 423658f0..c8a595f0 100644 --- a/contracts/liquidity_hub/bonding-manager/src/queries.rs +++ b/contracts/liquidity_hub/bonding-manager/src/queries.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; -use cosmwasm_std::{Decimal, Deps, Order, StdError, StdResult, Uint128}; +use cosmwasm_std::{Decimal, Deps, Order, StdResult, Uint128}; use cw_storage_plus::Bound; use crate::{helpers, ContractError}; @@ -151,7 +151,7 @@ pub(crate) fn query_weight( deps: &Deps, epoch_id: u64, address: String, - global_index: Option, + mut global_index: GlobalIndex, ) -> StdResult { let address = deps.api.addr_validate(&address)?; @@ -161,15 +161,10 @@ pub(crate) fn query_weight( .take(MAX_PAGE_LIMIT as usize) .collect(); - println!("----query_weight----"); - println!("bonds: {:?}", bonds); - let config = CONFIG.load(deps.storage)?; let mut total_bond_weight = Uint128::zero(); - println!("epoch id: {:?}", epoch_id); - for (_, mut bond) in bonds? { bond.weight = get_weight( epoch_id, @@ -182,22 +177,8 @@ pub(crate) fn query_weight( // Aggregate the weights of all the bonds for the given address. // This assumes bonding assets are fungible. total_bond_weight = total_bond_weight.checked_add(bond.weight)?; - println!("total_bond_weight: {:?}", total_bond_weight); } - // If a global weight from an Epoch was passed, use that to get the weight, otherwise use the current global index weight - let mut global_index = if let Some(global_index) = global_index { - global_index - } else { - println!("here?"); - GLOBAL - .may_load(deps.storage) - .unwrap_or_else(|_| Some(GlobalIndex::default())) - .ok_or_else(|| StdError::generic_err("Global index not found"))? - }; - - println!("global_index: {:?}", global_index); - global_index.last_weight = get_weight( epoch_id, global_index.last_weight, @@ -206,8 +187,6 @@ pub(crate) fn query_weight( global_index.last_updated, )?; - println!("global_index--after: {:?}", global_index); - // Represents the share of the global weight that the address has // If global_index.weight is zero no one has bonded yet so the share is let share = if global_index.last_weight.is_zero() { @@ -216,8 +195,6 @@ pub(crate) fn query_weight( Decimal::from_ratio(total_bond_weight, global_index.last_weight) }; - println!("share: {:?}", share); - Ok(BondingWeightResponse { address: address.to_string(), weight: total_bond_weight, @@ -228,13 +205,15 @@ pub(crate) fn query_weight( } /// Queries the global index -pub fn query_global_index(deps: Deps, epoch_id: Option) -> StdResult { - // if an epoch_id is provided, return the global index of the corresponding reward bucket - if let Some(epoch_id) = epoch_id { - let reward_bucket = REWARD_BUCKETS.may_load(deps.storage, epoch_id)?; - if let Some(reward_bucket) = reward_bucket { - return Ok(reward_bucket.global_index); - } +pub fn query_global_index(deps: Deps, reward_bucket_id: Option) -> StdResult { + // if a reward_bucket_id is provided, return the global index of the corresponding reward bucket + if let Some(reward_bucket_id) = reward_bucket_id { + let reward_bucket = REWARD_BUCKETS.may_load(deps.storage, reward_bucket_id)?; + return if let Some(reward_bucket) = reward_bucket { + Ok(reward_bucket.global_index) + } else { + Ok(GlobalIndex::default()) + }; } let global_index = GLOBAL.may_load(deps.storage)?.unwrap_or_default(); @@ -298,17 +277,12 @@ pub fn query_claimable( address: Option, ) -> StdResult { let mut claimable_reward_buckets = get_claimable_reward_buckets(deps)?.reward_buckets; - println!("fable"); - println!("claimable_reward_buckets: {:?}", claimable_reward_buckets); - // if an address is provided, filter what's claimable for that address if let Some(address) = address { let address = deps.api.addr_validate(&address)?; let last_claimed_epoch = LAST_CLAIMED_EPOCH.may_load(deps.storage, &address)?; - println!("last_claimed_epoch: {:?}", last_claimed_epoch); - // filter out buckets that have already been claimed by the user if let Some(last_claimed_epoch) = last_claimed_epoch { claimable_reward_buckets.retain(|bucket| bucket.id > last_claimed_epoch); @@ -322,8 +296,6 @@ pub fn query_claimable( claimable_reward_buckets.retain(|bucket| !bucket.available.is_empty()); } - println!("claimable_reward_buckets: {:?}", claimable_reward_buckets); - Ok(ClaimableRewardBucketsResponse { reward_buckets: claimable_reward_buckets, }) diff --git a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs index 992fec00..444c2f36 100644 --- a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs @@ -25,11 +25,6 @@ pub(crate) fn on_epoch_created( ) -> Result { cw_utils::nonpayable(&info)?; - println!( - ">>>>>>>>>>>>>>>>>>> {:?}{:?}{:?}", - current_epoch.id, current_epoch.id, current_epoch.id - ); - println!("EpochChangedHook: {:?}", current_epoch); // A new epoch has been created, update rewards bucket and forward the expiring bucket let config = CONFIG.load(deps.storage)?; ensure!( @@ -58,8 +53,6 @@ pub(crate) fn on_epoch_created( GLOBAL.save(deps.storage, &global_index)?; - println!("--- global_index: {:?}", global_index); - // Create a new reward bucket for the current epoch with the total rewards accrued in the // upcoming bucket item let upcoming_bucket = UPCOMING_REWARD_BUCKET.load(deps.storage)?; @@ -103,8 +96,6 @@ pub(crate) fn fill_rewards( env: Env, info: MessageInfo, ) -> Result { - println!("----fill_rewards----"); - let config = CONFIG.load(deps.storage)?; let distribution_denom = config.distribution_denom.clone(); @@ -159,8 +150,6 @@ pub(crate) fn fill_rewards( /// Handles the lp withdrawal reply. It will swap the non-distribution denom coins to the /// distribution denom and aggregate the funds to the upcoming reward bucket. pub fn handle_lp_withdrawal_reply(deps: DepsMut, msg: Reply) -> Result { - println!("---handle_lp_withdrawal_reply---"); - // Read the coins sent via data on the withdraw response of the pool manager let execute_contract_response = parse_reply_execute_data(msg.clone()).unwrap(); let data = execute_contract_response @@ -172,7 +161,6 @@ pub fn handle_lp_withdrawal_reply(deps: DepsMut, msg: Reply) -> Result Result Result StdResult { - // haces bond epoca 1 -> 1000 - // w = 1000 + 1000 * 9 * 1 = 10000 - // haces bond epoca 10 -> 1000 - // 11000 + 11000 * 9 * 1 -> 110000 - // w = 11000 / epoch 10 - - // epoch 20 - // w = 11000 + 11000 * 9 * 10 = 110000 let time_factor = if current_epoch_id == epoch_id { Uint128::zero() } else { diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/bond.rs b/contracts/liquidity_hub/bonding-manager/src/tests/bond.rs index 3579dd79..7d882e5c 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/bond.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/bond.rs @@ -1,14 +1,6 @@ -use cosmwasm_std::{coin, coins, Coin, Decimal, Timestamp, Uint128}; -use std::cell::RefCell; - -use white_whale_std::bonding_manager::{ - BondedResponse, BondingWeightResponse, GlobalIndex, RewardBucket, -}; -use white_whale_std::fee::{Fee, PoolFee}; -use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT; - use crate::tests::suite::TestingSuite; use crate::ContractError; +use cosmwasm_std::{coin, coins}; #[test] fn test_bond_unsuccessful() { diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs index 841b99f3..9b1308bb 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs @@ -1008,7 +1008,7 @@ fn test_rewards_forwarding() { }); // create two more epochs (without swapping, so they won't have any rewards), so the first bucket is forwarded to the one with id 22 - for i in 1..=2 { + for _ in 1..=2 { suite.add_one_day().create_new_epoch(); } diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/tests/helpers.rs index bc3092aa..44b0fab3 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/helpers.rs @@ -1,5 +1,4 @@ use crate::helpers::extract_pool_identifier; -use cosmwasm_std::coin; #[test] fn test_extract_pool_identifier() { diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/instantiate.rs b/contracts/liquidity_hub/bonding-manager/src/tests/instantiate.rs index c52b0379..da0bdf64 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/instantiate.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/instantiate.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Decimal, Uint64}; +use cosmwasm_std::{Addr, Decimal}; use white_whale_std::bonding_manager::Config; diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/mod.rs b/contracts/liquidity_hub/bonding-manager/src/tests/mod.rs index b84b242f..3b12657a 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/mod.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/mod.rs @@ -3,6 +3,7 @@ mod claim; mod epoch; mod helpers; mod instantiate; +mod queries; mod rewards; mod suite; mod unbond_withdraw; diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/queries.rs b/contracts/liquidity_hub/bonding-manager/src/tests/queries.rs new file mode 100644 index 00000000..b399961f --- /dev/null +++ b/contracts/liquidity_hub/bonding-manager/src/tests/queries.rs @@ -0,0 +1,369 @@ +use cosmwasm_std::{coin, coins, Coin, Decimal, Uint128}; + +use white_whale_std::bonding_manager::{Bond, BondedResponse, GlobalIndex, UnbondingResponse}; +use white_whale_std::fee::{Fee, PoolFee}; +use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT; + +use crate::tests::suite::TestingSuite; +use crate::ContractError; + +#[test] +fn test_queries() { + let mut suite = TestingSuite::default(); + let creator = suite.senders[0].clone(); + + let asset_denoms = vec!["uwhale".to_string(), "uusdc".to_string()]; + + #[cfg(not(feature = "osmosis"))] + let pool_fees = PoolFee { + protocol_fee: Fee { + share: Decimal::from_ratio(1u128, 100u128), + }, + swap_fee: Fee { + share: Decimal::from_ratio(1u128, 100u128), + }, + burn_fee: Fee { + share: Decimal::zero(), + }, + extra_fees: vec![], + }; + + suite + .instantiate_default() + .bond(creator.clone(), &coins(1_000u128, "ampWHALE"), |result| { + let err = result.unwrap_err().downcast::().unwrap(); + // the system has not been initialized + match err { + ContractError::Unauthorized { .. } => {} + _ => panic!("Wrong error type, should return ContractError::Unauthorized"), + } + }); + + suite + .fast_forward(259_200) + // epoch 1 + .create_new_epoch() + .create_pair( + creator.clone(), + asset_denoms.clone(), + pool_fees.clone(), + white_whale_std::pool_manager::PoolType::ConstantProduct, + Some("whale-uusdc".to_string()), + vec![coin(1000, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + creator.clone(), + "whale-uusdc".to_string(), + vec![ + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(1_000_000_000u128), + }, + Coin { + denom: "uusdc".to_string(), + amount: Uint128::from(1_000_000_000u128), + }, + ], + |result| { + // Ensure we got 999_000 in the response which is 1mil less the initial liquidity amount + assert!(result.unwrap().events.iter().any(|event| { + event.attributes.iter().any(|attr| { + attr.key == "share" + && attr.value + == (Uint128::from(1_000_000_000u128) - MINIMUM_LIQUIDITY_AMOUNT) + .to_string() + }) + })); + }, + ) + .swap( + creator.clone(), + coin(1_000u128, "uusdc"), + "uwhale".to_string(), + None, + None, + None, + "whale-uusdc".to_string(), + vec![Coin { + denom: "uusdc".to_string(), + amount: Uint128::from(1_000u128), + }], + |result| { + result.unwrap(); + }, + ) + // epoch 2 + .create_new_epoch() + .bond(creator.clone(), &coins(1_000u128, "ampWHALE"), |res| { + res.unwrap(); + }) + .swap( + creator.clone(), + coin(2_000u128, "uusdc"), + "uwhale".to_string(), + None, + None, + None, + "whale-uusdc".to_string(), + vec![Coin { + denom: "uusdc".to_string(), + amount: Uint128::from(2_000u128), + }], + |result| { + result.unwrap(); + }, + ) + .swap( + creator.clone(), + coin(2_000u128, "uwhale"), + "uusdc".to_string(), + None, + None, + None, + "whale-uusdc".to_string(), + vec![Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(2_000u128), + }], + |result| { + result.unwrap(); + }, + ); + + // epoch 3 + suite.create_new_epoch(); + + suite + .query_global_index(None, |result| { + let global_index = result.unwrap().1; + assert_eq!( + global_index, + GlobalIndex { + epoch_id: 3, + bonded_amount: Uint128::new(1_000), + bonded_assets: vec![Coin { + denom: "ampWHALE".to_string(), + amount: Uint128::from(1_000u128), + }], + last_updated: 2, + last_weight: Uint128::from(1_000u128), + } + ); + }) + .query_global_index(Some(3u64), |result| { + let global_index = result.unwrap().1; + assert_eq!( + global_index, + GlobalIndex { + epoch_id: 3, + bonded_amount: Uint128::new(1_000), + bonded_assets: vec![Coin { + denom: "ampWHALE".to_string(), + amount: Uint128::from(1_000u128), + }], + last_updated: 2, + last_weight: Uint128::from(1_000u128), + } + ); + }) + .query_global_index(Some(2u64), |result| { + let global_index = result.unwrap().1; + assert_eq!( + global_index, + GlobalIndex { + epoch_id: 2, + bonded_amount: Default::default(), + bonded_assets: vec![], + last_updated: 2, + last_weight: Default::default(), + } + ); + }) + .query_global_index(Some(1u64), |result| { + let global_index = result.unwrap().1; + assert_eq!( + global_index, + GlobalIndex { + epoch_id: 1, + bonded_amount: Default::default(), + bonded_assets: vec![], + last_updated: 1, + last_weight: Default::default(), + } + ); + }) + .query_bonded(None, |result| { + let bonded_response = result.unwrap().1; + assert_eq!( + bonded_response, + BondedResponse { + total_bonded: Uint128::new(1_000u128), + bonded_assets: vec![Coin { + denom: "ampWHALE".to_string(), + amount: Uint128::from(1_000u128), + }], + first_bonded_epoch_id: None, + } + ); + }); + + suite.claim(creator.clone(), |result| { + result.unwrap(); + }); + + suite + .unbond(creator.clone(), coin(100u128, "ampWHALE"), |result| { + result.unwrap(); + }) + .fast_forward(1_000) + .unbond(creator.clone(), coin(200u128, "ampWHALE"), |result| { + result.unwrap(); + }) + .fast_forward(1_000) + .unbond(creator.clone(), coin(300u128, "ampWHALE"), |result| { + result.unwrap(); + }) + .fast_forward(1_000) + .unbond(creator.clone(), coin(400u128, "ampWHALE"), |result| { + result.unwrap(); + }); + + suite + .query_unbonding( + creator.clone().to_string(), + "ampWHALE".to_string(), + None, + None, + |res| { + let unbonding_response = res.unwrap().1; + assert_eq!( + unbonding_response, + UnbondingResponse { + total_amount: Uint128::new(1_000), + unbonding_requests: vec![ + Bond { + asset: coin(100, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572056619), + last_updated: 3, + weight: Default::default(), + }, + Bond { + asset: coin(200, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572057619), + last_updated: 3, + weight: Default::default(), + }, + Bond { + asset: coin(300, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572058619), + last_updated: 3, + weight: Default::default(), + }, + Bond { + asset: coin(400, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572059619), + last_updated: 3, + weight: Default::default(), + }, + ], + } + ); + }, + ) + .query_unbonding( + creator.clone().to_string(), + "ampWHALE".to_string(), + None, + Some(2), + |res| { + let unbonding_response = res.unwrap().1; + assert_eq!( + unbonding_response, + UnbondingResponse { + total_amount: Uint128::new(300), + unbonding_requests: vec![ + Bond { + asset: coin(100, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572056619), + last_updated: 3, + weight: Default::default(), + }, + Bond { + asset: coin(200, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572057619), + last_updated: 3, + weight: Default::default(), + }, + ], + } + ); + }, + ); + + suite.query_unbonding( + creator.clone().to_string(), + "ampWHALE".to_string(), + Some(1572057619), + Some(2), + |res| { + let unbonding_response = res.unwrap().1; + assert_eq!( + unbonding_response, + UnbondingResponse { + total_amount: Uint128::new(700), + unbonding_requests: vec![ + Bond { + asset: coin(300, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572058619), + last_updated: 3, + weight: Default::default(), + }, + Bond { + asset: coin(400, "ampWHALE"), + created_at_epoch: 3, + unbonded_at: Some(1572059619), + last_updated: 3, + weight: Default::default(), + }, + ], + } + ); + }, + ); + + // epoch 4 + suite.add_one_day().create_new_epoch(); + + suite + .query_global_index(Some(4u64), |result| { + let global_index = result.unwrap().1; + assert_eq!( + global_index, + GlobalIndex { + epoch_id: 4, + bonded_amount: Uint128::zero(), + bonded_assets: vec![], + last_updated: 4, + last_weight: Uint128::zero(), + } + ); + }) + .query_global_index(Some(5u64), |result| { + let global_index = result.unwrap().1; + assert_eq!(global_index, GlobalIndex::default()); + }) + .query_global_index(Some(100u64), |result| { + let global_index = result.unwrap().1; + assert_eq!(global_index, GlobalIndex::default()); + }); +} diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/suite.rs b/contracts/liquidity_hub/bonding-manager/src/tests/suite.rs index 4158ee63..f56f2912 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/suite.rs @@ -1,9 +1,6 @@ use anyhow::Error; -use cosmwasm_std::testing::{mock_dependencies, mock_env, MockApi, MockQuerier, MockStorage}; -use cosmwasm_std::{ - coin, from_json, Addr, Binary, Coin, Decimal, Empty, OwnedDeps, StdResult, Uint128, Uint64, -}; -// use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; +use cosmwasm_std::testing::{MockApi, MockStorage}; +use cosmwasm_std::{coin, Addr, Coin, Decimal, Empty, StdResult, Uint128, Uint64}; use cw_multi_test::{ App, AppBuilder, AppResponse, BankKeeper, DistributionKeeper, Executor, FailingModule, GovFailingModule, IbcFailingModule, StakeKeeper, WasmKeeper, @@ -11,11 +8,10 @@ use cw_multi_test::{ use white_whale_std::fee::PoolFee; use white_whale_testing::multi_test::stargate_mock::StargateMock; -use crate::state::{CONFIG, REWARD_BUCKETS}; use cw_multi_test::{Contract, ContractWrapper}; use white_whale_std::bonding_manager::{ - BondedResponse, BondingWeightResponse, Config, ExecuteMsg, GlobalIndex, InstantiateMsg, - QueryMsg, RewardsResponse, UnbondingResponse, WithdrawableResponse, + BondedResponse, Config, ExecuteMsg, GlobalIndex, InstantiateMsg, QueryMsg, RewardsResponse, + UnbondingResponse, WithdrawableResponse, }; use white_whale_std::bonding_manager::{ClaimableRewardBucketsResponse, RewardBucket}; use white_whale_std::epoch_manager::epoch_manager::{Epoch as EpochV2, EpochConfig}; @@ -75,8 +71,6 @@ pub struct TestingSuite { pub bonding_manager_addr: Addr, pub pool_manager_addr: Addr, pub epoch_manager_addr: Addr, - owned_deps: OwnedDeps, - env: cosmwasm_std::Env, } /// instantiate / execute messages @@ -123,8 +117,6 @@ impl TestingSuite { bonding_manager_addr: Addr::unchecked(""), pool_manager_addr: Addr::unchecked(""), epoch_manager_addr: Addr::unchecked(""), - owned_deps: mock_dependencies(), - env: mock_env(), } } @@ -194,8 +186,7 @@ impl TestingSuite { white_whale_std::epoch_manager::epoch_manager::ExecuteMsg::AddHook { contract_addr: bonding_manager_addr.clone().to_string(), }; - let resp = self - .app + self.app .execute_contract( self.senders[0].clone(), epoch_manager_addr.clone(), @@ -468,7 +459,7 @@ impl TestingSuite { #[track_caller] pub(crate) fn query_global_index( &mut self, - epoch_id: Option, + reward_bucket_id: Option, response: impl Fn(StdResult<(&mut Self, GlobalIndex)>), ) -> &mut Self { let global_index: GlobalIndex = self @@ -476,7 +467,7 @@ impl TestingSuite { .wrap() .query_wasm_smart( &self.bonding_manager_addr, - &QueryMsg::GlobalIndex { epoch_id }, + &QueryMsg::GlobalIndex { reward_bucket_id }, ) .unwrap(); diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/unbond_withdraw.rs b/contracts/liquidity_hub/bonding-manager/src/tests/unbond_withdraw.rs index 17d192e8..47ede32b 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/unbond_withdraw.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/unbond_withdraw.rs @@ -462,6 +462,16 @@ fn test_unbonding_withdraw() { _ => panic!("Wrong error type, should return ContractError::InsufficientBond"), } }) + .unbond(creator.clone(), coin(0u128, "ampWHALE"), |result| { + let err = result.unwrap_err().downcast::().unwrap(); + // trying to unbond more than bonded + match err { + ContractError::InvalidUnbondingAmount { .. } => {} + _ => { + panic!("Wrong error type, should return ContractError::InvalidUnbondingAmount") + } + } + }) .unbond(creator.clone(), coin(1_000u128, "ampWHALE"), |result| { // total unbond result.unwrap(); @@ -494,6 +504,7 @@ fn test_unbonding_withdraw() { Bond { asset: coin(1_000u128, "ampWHALE"), created_at_epoch: 6, + unbonded_at: Some(1572335819), last_updated: 6, weight: Uint128::zero(), } @@ -520,11 +531,32 @@ fn test_unbonding_withdraw() { _ => panic!("Wrong error type, should return ContractError::NothingToWithdraw"), } }) + .query_withdrawable(creator.clone().to_string(), "ampWHALE".to_string(), |res| { + let withdrawable = res.unwrap().1; + assert_eq!(withdrawable.withdrawable_amount, Uint128::zero()); + }) .add_one_day() - .create_new_epoch() + .create_new_epoch(); + + let creator_balance = RefCell::new(Uint128::zero()); + + suite + .query_balance("ampWHALE".to_string(), creator.clone(), |balance| { + *creator_balance.borrow_mut() = balance; + }) + .query_withdrawable(creator.clone().to_string(), "ampWHALE".to_string(), |res| { + let withdrawable = res.unwrap().1; + assert_eq!(withdrawable.withdrawable_amount, Uint128::new(1_000)); + }) .withdraw(creator.clone(), "ampWHALE".to_string(), |result| { result.unwrap(); }) + .query_balance("ampWHALE".to_string(), creator.clone(), |balance| { + assert_eq!( + creator_balance.clone().into_inner() + Uint128::new(1000u128), + balance + ); + }) .query_rewards(creator.clone().to_string(), |res| { let (_, rewards) = res.unwrap(); assert!(rewards.rewards.is_empty()); @@ -711,12 +743,14 @@ fn test_unbonding_withdraw() { Bond { asset: coin(300u128, "bWHALE"), created_at_epoch: 8, + unbonded_at: Some(1572508619), last_updated: 8, weight: Uint128::zero(), }, Bond { asset: coin(200u128, "bWHALE"), created_at_epoch: 8, + unbonded_at: Some(1572508620), last_updated: 8, weight: Uint128::zero(), } diff --git a/packages/white-whale-std/src/bonding_manager.rs b/packages/white-whale-std/src/bonding_manager.rs index cf11b62e..ae9632df 100644 --- a/packages/white-whale-std/src/bonding_manager.rs +++ b/packages/white-whale-std/src/bonding_manager.rs @@ -54,15 +54,16 @@ pub struct UpcomingRewardBucket { #[cw_serde] pub struct Bond { - /// The amount of bonded tokens. - pub asset: Coin, /// The epoch id at which the Bond was created. pub created_at_epoch: u64, /// The epoch id at which the bond was last time updated. pub last_updated: u64, + /// The amount of bonded tokens. + pub asset: Coin, /// The weight of the bond at the given block height. pub weight: Uint128, - //pub previous: Option<(u64, Uint128)> + /// The time at which the Bond was unbonded. + pub unbonded_at: Option, } impl Default for Bond { @@ -73,9 +74,9 @@ impl Default for Bond { amount: Uint128::zero(), }, created_at_epoch: Default::default(), + unbonded_at: None, last_updated: Default::default(), weight: Uint128::zero(), - //previous: None, } } } @@ -166,7 +167,6 @@ pub enum QueryMsg { /// Returns the [Config] of te contract. #[returns(Config)] Config, - /// Returns the amount of assets that have been bonded by the specified address. #[returns(BondedResponse)] Bonded { @@ -174,7 +174,6 @@ pub enum QueryMsg { /// contract are returned. address: Option, }, - /// Returns the amount of tokens of the given denom that are been unbonded by the specified address. /// Allows pagination with start_after and limit. #[returns(UnbondingResponse)] @@ -188,7 +187,6 @@ pub enum QueryMsg { /// The maximum amount of unbonding assets to return. limit: Option, }, - /// Returns the amount of unbonding tokens of the given denom for the specified address that can /// be withdrawn, i.e. that have passed the unbonding period. #[returns(WithdrawableResponse)] @@ -198,29 +196,13 @@ pub enum QueryMsg { /// The denom to check for withdrawable assets. denom: String, }, - - //todo maybe this should be removed? No need to expose this if what's important is how many rewards - // the user have, which can be given with the Rewards query - /// Returns the weight of the address. - // #[returns(BondingWeightResponse)] - // Weight { - // /// The address to check for weight. - // address: String, - // /// The timestamp to check for weight. If none is provided, the current block time is used. - // epoch_id: Option, - // /// The global index to check for weight. If none is provided, the current global index is used. - // global_index: Option, - // }, - /// Returns the global index of the contract. #[returns(GlobalIndex)] GlobalIndex { - /// The epoch id to check for the global index. If none is provided, the current global index + /// The reward bucket id to check for the global index. If none is provided, the current global index /// is returned. - epoch_id: Option, + reward_bucket_id: Option, }, - - //todo maybe we don't need to expose this? /// Returns the [RewardBucket]s that can be claimed by an address. #[returns(ClaimableRewardBucketsResponse)] Claimable { @@ -228,8 +210,6 @@ pub enum QueryMsg { /// reward buckets stored in the contract that can potentially be claimed are returned. address: Option, }, - - //todo add rewards query that show how much a user can claim at that point of time /// Returns the rewards for the given address. #[returns(RewardsResponse)] Rewards { address: String },