Skip to content

Commit

Permalink
wip: EpochChangedMSG and FillRewards full test
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFable committed Apr 18, 2024
1 parent a7077c7 commit 26ac97f
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 82 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ test-case = { version = "3.3.1" }
# contracts
whale-lair = { path = "./contracts/liquidity_hub/whale_lair" }
epoch-manager = { path = "./contracts/liquidity_hub/epoch-manager" }
pool-manager = { path = "./contracts/liquidity_hub/pool-manager" }
fee_collector = { path = "./contracts/liquidity_hub/fee_collector" }
fee_distributor = { path = "./contracts/liquidity_hub/fee_distributor" }
fee-distributor-mock = { path = "./contracts/liquidity_hub/fee-distributor-mock" }
incentive-factory = { path = "./contracts/liquidity_hub/pool-network/incentive_factory" }
terraswap-token = { path = "./contracts/liquidity_hub/pool-network/terraswap_token" }
terraswap-pair = { path = "./contracts/liquidity_hub/pool-network/terraswap_pair" }


[workspace.metadata.dylint]
libraries = [{ git = "https://github.com/0xFable/cw-lint" }]

Expand Down
2 changes: 2 additions & 0 deletions contracts/liquidity_hub/bonding-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ serde.workspace = true
thiserror.workspace = true
white-whale-std.workspace = true
cw-utils.workspace = true
pool-manager.workspace = true

[dev-dependencies]
cw-multi-test.workspace = true
anyhow.workspace = true
white-whale-testing.workspace = true
pool-manager.workspace = true
53 changes: 52 additions & 1 deletion contracts/liquidity_hub/bonding-manager/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use cosmwasm_std::{
ensure, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, Env, MessageInfo, Order, Response,
StdError, StdResult, Timestamp, Uint128, Uint64,
};
use white_whale_std::constants::LP_SYMBOL;
use white_whale_std::pool_network::asset;

use white_whale_std::bonding_manager::Bond;
Expand All @@ -25,6 +26,7 @@ pub(crate) fn bond(
helpers::validate_funds(&deps, &info, &asset, asset.denom.clone())?;
helpers::validate_claimed(&deps, &info)?;
helpers::validate_bonding_for_current_epoch(&deps, &env)?;
println!("Bonding asset: {:?}", asset);
let mut bond = BOND
.key((&info.sender, &asset.denom))
.may_load(deps.storage)?
Expand Down Expand Up @@ -78,7 +80,6 @@ pub(crate) fn unbond(

helpers::validate_claimed(&deps, &info)?;
helpers::validate_bonding_for_current_epoch(&deps, &env)?;

if let Some(mut unbond) = BOND
.key((&info.sender, &asset.denom))
.may_load(deps.storage)?
Expand Down Expand Up @@ -307,3 +308,53 @@ pub fn claim(deps: DepsMut, env: Env, info: MessageInfo) -> Result<Response, Con
.add_attributes(vec![("action", "claim")])
.add_messages(messages))
}

pub(crate) fn fill_rewards(
deps: DepsMut,
env: Env,
info: MessageInfo,
) -> Result<Response, ContractError> {
{
// Use aggregate_coins to get the total amount of new coins
// Finding the most recent EpochID
let most_recent_epoch_id = EPOCHS
.keys(deps.storage, None, None, Order::Descending)
.next()
.unwrap()?;

let _messages: Vec<CosmosMsg> = vec![];
// Verify coins are coming
// swap non-whale to whale
// Search info funds for LP tokens, LP tokens will contain LP_SYMBOL from lp_common and the string .pair.
let lp_tokens = info
.funds
.iter()
.filter(|coin| coin.denom.contains(".pair.") | coin.denom.contains(LP_SYMBOL));
// LP tokens have the format "{pair_label}.pair.{identifier}.{LP_SYMBOL}", get the identifier and not the LP SYMBOL
let _pair_identifier = lp_tokens
.map(|coin| coin.denom.split(".pair.").collect::<Vec<&str>>()[1])
.next()
.unwrap();

// // if LP Tokens ,verify and withdraw then swap to whale
// let lp_withdrawal_msg = white_whale_std::pool_manager::ExecuteMsg::WithdrawLiquidity { pair_identifier: pair_identifier.to_string() };
// messages.push(CosmosMsg::Wasm(WasmMsg::Execute {
// contract_addr: ,
// msg: to_json_binary(&lp_withdrawal_msg)?,
// funds: vec![],
// }));

// Note: Might need to convert back to ints and use that for ranking to get the most recent ID
// Note: After swap,
EPOCHS.update(
deps.storage,
&most_recent_epoch_id,
|bucket| -> StdResult<_> {
let mut bucket = bucket.unwrap_or_default();
bucket.available = asset::aggregate_coins(bucket.available, vec![])?;
Ok(bucket)
},
)?;
Ok(Response::default().add_attributes(vec![("action", "fill_rewards".to_string())]))
}
}
78 changes: 30 additions & 48 deletions contracts/liquidity_hub/bonding-manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,58 +110,36 @@ pub fn execute(
unbonding_period,
growth_rate,
} => commands::update_config(deps, info, owner, unbonding_period, growth_rate),
ExecuteMsg::FillRewards { .. } => {
// Use aggregate_coins to get the total amount of new coins
// Finding the most recent EpochID
let most_recent_epoch_id = EPOCHS
.keys(deps.storage, None, None, Order::Descending)
.next()
.unwrap()?;

let _messages: Vec<CosmosMsg> = vec![];
// Verify coins are coming
// swap non-whale to whale
// Search info funds for LP tokens, LP tokens will contain LP_SYMBOL from lp_common and the string .pair.
let lp_tokens = info
.funds
.iter()
.filter(|coin| coin.denom.contains(".pair.") | coin.denom.contains(LP_SYMBOL));
// LP tokens have the format "{pair_label}.pair.{identifier}.{LP_SYMBOL}", get the identifier and not the LP SYMBOL
let _pair_identifier = lp_tokens
.map(|coin| coin.denom.split(".pair.").collect::<Vec<&str>>()[1])
.next()
.unwrap();

// // if LP Tokens ,verify and withdraw then swap to whale
// let lp_withdrawal_msg = white_whale_std::pool_manager::ExecuteMsg::WithdrawLiquidity { pair_identifier: pair_identifier.to_string() };
// messages.push(CosmosMsg::Wasm(WasmMsg::Execute {
// contract_addr: ,
// msg: to_json_binary(&lp_withdrawal_msg)?,
// funds: vec![],
// }));

// Note: Might need to convert back to ints and use that for ranking to get the most recent ID
// Note: After swap,
EPOCHS.update(
deps.storage,
&most_recent_epoch_id,
|bucket| -> StdResult<_> {
let mut bucket = bucket.unwrap_or_default();
bucket.available = asset::aggregate_coins(bucket.available, vec![])?;
Ok(bucket)
},
)?;
Ok(Response::default().add_attributes(vec![("action", "fill_rewards".to_string())]))
}
ExecuteMsg::FillRewards { .. } => commands::fill_rewards(deps, env, info),
ExecuteMsg::FillRewardsCoin => commands::fill_rewards(deps, env, info),
ExecuteMsg::Claim { .. } => commands::claim(deps, env, info),
ExecuteMsg::EpochChangedHook { msg } => {
ExecuteMsg::EpochChangedHook { current_epoch } => {
// Epoch has been updated, update rewards bucket
// and forward the expiring epoch
// Store epoch manager and verify the sender is him
println!("New epoch created: {:?}", current_epoch);

let new_epoch_id = msg.current_epoch.id;
let expiring_epoch_id = new_epoch_id.checked_sub(1u64).unwrap();
let new_epoch_id = current_epoch.id;
let next_epoch_id = new_epoch_id.checked_add(1u64).unwrap();
// Creates a new bucket for the rewards flowing from this time on, i.e. to be distributed in the next epoch. Also, forwards the expiring epoch (only 21 epochs are live at a given moment)
// Add a new rewards bucket for the new epoch
EPOCHS.save(
deps.storage,
&next_epoch_id.to_be_bytes(),
&Epoch {
id: next_epoch_id.into(),
start_time: current_epoch.start_time,
..Epoch::default()
},
)?;
println!("New epoch created: {}", next_epoch_id);
// Return early if the epoch is the first one
if new_epoch_id == 1 {
return Ok(Response::default()
.add_attributes(vec![("action", "epoch_changed_hook".to_string())]));
}

let expiring_epoch_id = new_epoch_id.checked_sub(1u64).unwrap();
// Verify that it is indeed the expiring epoch that is being forwarded
let _ = match get_expiring_epoch(deps.as_ref())? {
Some(epoch) if epoch.id.u64() == expiring_epoch_id => Ok(()),
Expand All @@ -176,10 +154,11 @@ pub fn execute(
&next_epoch_id.to_be_bytes(),
&Epoch {
id: next_epoch_id.into(),
start_time: msg.current_epoch.start_time,
start_time: current_epoch.start_time,
..Epoch::default()
},
)?;

// Load all the available assets from the expiring epoch
let amount_to_be_forwarded = EPOCHS
.load(deps.storage, &expiring_epoch_id.to_be_bytes())?
Expand Down Expand Up @@ -253,7 +232,10 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
}
QueryMsg::TotalBonded {} => to_json_binary(&queries::query_total_bonded(deps)?),
QueryMsg::GlobalIndex {} => to_json_binary(&queries::query_global_index(deps)?),
QueryMsg::Claimable { addr } => to_json_binary(&queries::query_claimable(deps, &deps.api.addr_validate(&addr)?)?),
QueryMsg::Claimable { addr } => to_json_binary(&queries::query_claimable(
deps,
&deps.api.addr_validate(&addr)?,
)?),
QueryMsg::ClaimableEpochs {} => to_json_binary(&queries::get_claimable_epochs(deps)?),
}
}
Expand Down
4 changes: 3 additions & 1 deletion contracts/liquidity_hub/bonding-manager/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub(crate) fn query_bonded(deps: Deps, address: String) -> StdResult<BondedRespo
Ok(bond)
})
.collect::<StdResult<Vec<Bond>>>()?;
println!("bonds is empty : {:?}", bonds.is_empty());

// if it doesn't have bonded, return empty response
if bonds.is_empty() {
Expand All @@ -46,6 +47,7 @@ pub(crate) fn query_bonded(deps: Deps, address: String) -> StdResult<BondedRespo
first_bonded_epoch_id: Uint64::zero(),
});
}
println!("bonds: {:?}", bonds);

let mut total_bonded = Uint128::zero();
let mut bonded_assets = vec![];
Expand Down Expand Up @@ -295,7 +297,7 @@ pub fn get_claimable_epochs(deps: Deps) -> StdResult<ClaimableEpochsResponse> {
pub fn query_claimable(deps: Deps, address: &Addr) -> StdResult<ClaimableEpochsResponse> {
let mut claimable_epochs = get_claimable_epochs(deps)?.epochs;
let last_claimed_epoch = LAST_CLAIMED_EPOCH.may_load(deps.storage, address)?;

// filter out epochs that have already been claimed by the user
if let Some(last_claimed_epoch) = last_claimed_epoch {
claimable_epochs.retain(|epoch| epoch.id > last_claimed_epoch);
Expand Down
1 change: 1 addition & 0 deletions contracts/liquidity_hub/bonding-manager/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod bond;
mod claim;
mod instantiate;
mod rewards;
mod robot;
mod test_helpers;
mod unbond;
Expand Down
80 changes: 80 additions & 0 deletions contracts/liquidity_hub/bonding-manager/src/tests/rewards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use cosmwasm_std::testing::{mock_dependencies, mock_env};
use cosmwasm_std::{coin, Coin, Decimal, Uint128, Uint64};
use white_whale_std::coin;
use white_whale_std::fee::{Fee, PoolFee};
use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT;

use crate::tests::robot::TestingRobot;
use crate::tests::test_helpers;

#[test]
fn test_fill_rewards_from_pool_manager() {
let mut robot = TestingRobot::default();
let grace_period = Uint64::new(21);
let creator = robot.sender.clone();
let epochs = test_helpers::get_epochs();
let binding = epochs.clone();
let claimable_epochs = binding
.iter()
.rev()
.take(grace_period.u64() as usize)
.collect::<Vec<_>>();
let asset_infos = vec!["uwhale".to_string(), "uusdc".to_string()];

// Default Pool fees white_whale_std::pool_network::pair::PoolFee
// Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0%
#[cfg(not(feature = "osmosis"))]
let pool_fees = PoolFee {
protocol_fee: Fee {
share: Decimal::from_ratio(1u128, 100_000u128),
},
swap_fee: Fee {
share: Decimal::from_ratio(1u128, 100_000u128),
},
burn_fee: Fee {
share: Decimal::zero(),
},
extra_fees: vec![],
};

robot
.instantiate_default()
.add_epochs_to_state(epochs)
.create_pair(
creator.clone(),
asset_infos,
pool_fees,
white_whale_std::pool_network::asset::PairType::ConstantProduct,
Some("whale-uusdc".to_string()),
vec![coin(1000, "uusdc")],
|result| {
result.unwrap();
},
);

// Lets try to add liquidity
robot.provide_liquidity(
creator.clone(),
"whale-uluna".to_string(),
vec![
Coin {
denom: "uwhale".to_string(),
amount: Uint128::from(1000000u128),
},
Coin {
denom: "uluna".to_string(),
amount: Uint128::from(1000000u128),
},
],
|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_000u128) - MINIMUM_LIQUIDITY_AMOUNT).to_string()
})
}));
},
);
}
Loading

0 comments on commit 26ac97f

Please sign in to comment.