Skip to content

Commit

Permalink
Mp 2347 integrate astro staking into credit manager (#394)
Browse files Browse the repository at this point in the history
* feat: stake lp in astroport incentives

* tidy

* move mars / astroport incentives to individual files

* correctly add files for previous commit

* fmt

* fix tests

* add missing import

* don't swallow errors, update naming

* update credit_manager assertion

* credit manager astroport incentives implementation

* fix lp rewards query

* Mock astroport incentives dependency

* tidy structure

* astro_lp incentives integration test

* add lp rewards query

* tidy

* additional tests

* fmt

* add cm tests for astro incentives

* Fix astro deps in incentives.

* add rewards recieved to event attributes

* fix - increment not decrement

* error if lp balance lt requested

* improve tests

* fix staking issue

* add unstake tests

* Add staked lp to account collateral

* clippy + fmt

* schema

* fix deps

* add staked lp to positions

* remove redundant code

* improve test coverage

* generate types

* add incentive query tests

* naming

* generate schema

* comments

* add incentives documentation (#399)

* add incentives documentation

* remove todo

* better error handling

* rename files

* add rewards as attribute

* improve naming, attributes on response

* improve test_claim_lp_rewards

* improve test_stake_astro_lp

* improve test_unstake_astro_lp

* improve test_querying

* small fixes and naming

* improve test_astro_lp_incentives

* more naming

* improve tests

* update types

* merge 'dev' into MP-2347-integrate-astro-staking

* updated types

* Reorder in tests.

* Rename claming test case for astro.

---------

Co-authored-by: piobab <[email protected]>
  • Loading branch information
markonmars and piobab authored Jun 5, 2024
1 parent 9572675 commit 1fb38b1
Show file tree
Hide file tree
Showing 137 changed files with 3,615 additions and 2,126 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

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

18 changes: 10 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"contracts/vault",

# mock contracts
"contracts/mock-astroport-incentives",
"contracts/mock-credit-manager",
"contracts/mock-health",
"contracts/mock-incentives",
Expand Down Expand Up @@ -131,14 +132,15 @@ mars-vault = { path = "./contracts/vault" }
mars-zapper-base = { path = "./contracts/v2-zapper/base" }

# mocks
mars-mock-credit-manager = { path = "./contracts/mock-credit-manager" }
mars-mock-incentives = { path = "./contracts/mock-incentives" }
mars-mock-oracle = { path = "./contracts/mock-oracle" }
mars-mock-red-bank = { path = "./contracts/mock-red-bank" }
mars-mock-vault = { path = "./contracts/mock-vault" }
mars-mock-rover-health = { path = "./contracts/mock-health" }
mars-swapper-mock = { path = "./contracts/swapper/mock" }
mars-zapper-mock = { path = "./contracts/v2-zapper/mock" }
mars-mock-astroport-incentives = { path = "./contracts/mock-astroport-incentives" }
mars-mock-credit-manager = { path = "./contracts/mock-credit-manager" }
mars-mock-incentives = { path = "./contracts/mock-incentives" }
mars-mock-oracle = { path = "./contracts/mock-oracle" }
mars-mock-red-bank = { path = "./contracts/mock-red-bank" }
mars-mock-vault = { path = "./contracts/mock-vault" }
mars-mock-rover-health = { path = "./contracts/mock-health" }
mars-swapper-mock = { path = "./contracts/swapper/mock" }
mars-zapper-mock = { path = "./contracts/v2-zapper/mock" }

[profile.release]
codegen-units = 1
Expand Down
31 changes: 16 additions & 15 deletions contracts/credit-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,19 @@ mars-vault = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
cw-multi-test = { workspace = true }
itertools = { workspace = true }
mars-account-nft = { workspace = true }
mars-address-provider = { workspace = true }
mars-mock-incentives = { workspace = true }
mars-mock-oracle = { workspace = true }
mars-mock-red-bank = { workspace = true }
mars-mock-vault = { workspace = true }
mars-params = { workspace = true }
mars-rover-health = { workspace = true }
mars-swapper-mock = { workspace = true }
mars-testing = { workspace = true }
mars-zapper-mock = { workspace = true }
test-case = { workspace = true }
anyhow = { workspace = true }
cw-multi-test = { workspace = true }
itertools = { workspace = true }
mars-account-nft = { workspace = true }
mars-address-provider = { workspace = true }
mars-mock-astroport-incentives = { workspace = true }
mars-mock-incentives = { workspace = true }
mars-mock-oracle = { workspace = true }
mars-mock-red-bank = { workspace = true }
mars-mock-vault = { workspace = true }
mars-params = { workspace = true }
mars-rover-health = { workspace = true }
mars-swapper-mock = { workspace = true }
mars-testing = { workspace = true }
mars-zapper-mock = { workspace = true }
test-case = { workspace = true }
38 changes: 38 additions & 0 deletions contracts/credit-manager/src/claim_astro_lp_rewards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use cosmwasm_std::{DepsMut, Response};
use mars_types::traits::Stringify;

use crate::{
error::{ContractError, ContractResult},
state::INCENTIVES,
utils::increment_coin_balance,
};

pub fn claim_lp_rewards(
deps: DepsMut,
account_id: &str,
lp_denom: &str,
) -> ContractResult<Response> {
let incentives = INCENTIVES.load(deps.storage)?;

// Query rewards user is receiving, update balance
let rewards = incentives.query_staked_astro_lp_rewards(&deps.querier, account_id, lp_denom)?;
if rewards.is_empty() {
return Err(ContractError::NoAmount);
}

for reward in rewards.iter() {
increment_coin_balance(deps.storage, account_id, reward)?;
}

let claim_rewards_msg = incentives.claim_staked_astro_lp_rewards_msg(account_id, lp_denom)?;
let mut res = Response::new()
.add_message(claim_rewards_msg)
.add_attribute("action", "claim_astro_lp_rewards")
.add_attribute("account_id", account_id);

if !rewards.is_empty() {
res = res.add_attribute("rewards", rewards.as_slice().to_string());
}

Ok(res)
}
6 changes: 6 additions & 0 deletions contracts/credit-manager/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ pub enum ContractError {
reason: String,
},

#[error("Insufficient funds. Requested {requested:?}, available {available:?}")]
InsufficientFunds {
requested: Uint128,
available: Uint128,
},

#[error("{reason:?}")]
InvalidConfig {
reason: String,
Expand Down
33 changes: 33 additions & 0 deletions contracts/credit-manager/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use mars_vault::msg::{ExecuteMsg, ExtensionExecuteMsg};

use crate::{
borrow::borrow,
claim_astro_lp_rewards::claim_lp_rewards,
claim_rewards::{claim_rewards, send_rewards},
deposit::{assert_deposit_caps, deposit},
error::{ContractError, ContractResult},
Expand All @@ -25,8 +26,10 @@ use crate::{
reclaim::reclaim,
refund::refund_coin_balances,
repay::{repay, repay_for_recipient},
stake_astro_lp::stake_lp,
state::{ACCOUNT_KINDS, ACCOUNT_NFT, REENTRANCY_GUARD},
swap::swap_exact_in,
unstake_astro_lp::unstake_lp,
update_coin_balances::{update_coin_balance, update_coin_balance_after_vault_liquidation},
utils::{assert_is_token_owner, get_account_kind},
vault::{
Expand Down Expand Up @@ -316,6 +319,24 @@ pub fn dispatch_actions(
lp_token,
slippage,
}),
Action::StakeAstroLp {
lp_token,
} => callbacks.push(CallbackMsg::StakeAstroLp {
account_id: account_id.to_string(),
lp_token,
}),
Action::UnstakeAstroLp {
lp_token,
} => callbacks.push(CallbackMsg::UnstakeAstroLp {
account_id: account_id.to_string(),
lp_token,
}),
Action::ClaimAstroLpRewards {
lp_denom,
} => callbacks.push(CallbackMsg::ClaimAstroLpRewards {
account_id: account_id.to_string(),
lp_denom,
}),
Action::RefundAllCoinBalances {} => {
callbacks.push(CallbackMsg::RefundAllCoinBalances {
account_id: account_id.to_string(),
Expand Down Expand Up @@ -580,5 +601,17 @@ pub fn execute_callback(
previous_balances,
recipient,
} => send_rewards(deps, &env.contract.address, &account_id, recipient, previous_balances),
CallbackMsg::StakeAstroLp {
account_id,
lp_token,
} => stake_lp(deps, &account_id, lp_token),
CallbackMsg::UnstakeAstroLp {
account_id,
lp_token,
} => unstake_lp(deps, &account_id, lp_token),
CallbackMsg::ClaimAstroLpRewards {
account_id,
lp_denom,
} => claim_lp_rewards(deps, &account_id, &lp_denom),
}
}
3 changes: 3 additions & 0 deletions contracts/credit-manager/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod borrow;
pub mod claim_astro_lp_rewards;
pub mod claim_rewards;
pub mod contract;
pub mod deposit;
Expand All @@ -16,8 +17,10 @@ pub mod query;
pub mod reclaim;
pub mod refund;
pub mod repay;
pub mod stake_astro_lp;
pub mod state;
pub mod swap;
pub mod unstake_astro_lp;
pub mod update_coin_balances;
pub mod update_config;
pub mod utils;
Expand Down
3 changes: 3 additions & 0 deletions contracts/credit-manager/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ pub fn query_positions(deps: Deps, account_id: &str) -> ContractResult<Positions
debts: query_debt_amounts(deps, account_id)?,
lends: RED_BANK.load(deps.storage)?.query_all_lent(&deps.querier, account_id)?,
vaults: query_vault_positions(deps, account_id)?,
staked_lp: INCENTIVES
.load(deps.storage)?
.query_all_staked_astro_lp_coins(&deps.querier, account_id)?,
})
}

Expand Down
50 changes: 50 additions & 0 deletions contracts/credit-manager/src/stake_astro_lp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use cosmwasm_std::{coin, DepsMut, Response};
use mars_types::{
credit_manager::{ActionAmount, ActionCoin},
traits::Stringify,
};

use crate::{
error::ContractResult,
state::{COIN_BALANCES, INCENTIVES},
utils::{decrement_coin_balance, increment_coin_balance},
};

pub fn stake_lp(deps: DepsMut, account_id: &str, lp_coin: ActionCoin) -> ContractResult<Response> {
let incentives = INCENTIVES.load(deps.storage)?;

// Query rewards user is receiving to update their balances
let rewards = incentives.query_staked_astro_lp_rewards(
&deps.querier,
account_id,
lp_coin.denom.as_str(),
)?;

let coin_balance =
COIN_BALANCES.may_load(deps.storage, (account_id, &lp_coin.denom))?.unwrap_or_default();
let new_amount = match lp_coin.amount {
ActionAmount::Exact(amt) => amt,
ActionAmount::AccountBalance => coin_balance,
};

let updated_coin = coin(new_amount.u128(), lp_coin.denom.as_str());

decrement_coin_balance(deps.storage, account_id, &updated_coin)?;

for reward in rewards.iter() {
increment_coin_balance(deps.storage, account_id, reward)?;
}

// stake msg
let stake_msg = incentives.stake_astro_lp_msg(account_id, updated_coin)?;
let mut res = Response::new()
.add_message(stake_msg)
.add_attribute("action", "stake_astro_lp")
.add_attribute("account_id", account_id);

if !rewards.is_empty() {
res = res.add_attribute("rewards", rewards.as_slice().to_string());
}

Ok(res)
}
63 changes: 63 additions & 0 deletions contracts/credit-manager/src/unstake_astro_lp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use cosmwasm_std::{coin, DepsMut, Response};
use mars_types::{
credit_manager::{ActionAmount, ActionCoin},
traits::Stringify,
};

use crate::{
error::{ContractError, ContractResult},
state::INCENTIVES,
utils::increment_coin_balance,
};

pub fn unstake_lp(
deps: DepsMut,
account_id: &str,
lp_coin: ActionCoin,
) -> ContractResult<Response> {
let incentives = INCENTIVES.load(deps.storage)?;

// Query rewards user is receiving, update balance
let lp_position = incentives.query_staked_astro_lp_position(
&deps.querier,
account_id,
lp_coin.denom.as_str(),
)?;

for reward in lp_position.rewards.iter() {
increment_coin_balance(deps.storage, account_id, reward)?;
}

let new_amount = match lp_coin.amount {
ActionAmount::Exact(amt) => {
if lp_position.lp_coin.amount.lt(&amt) {
return Err(ContractError::InsufficientFunds {
requested: amt,
available: lp_position.lp_coin.amount,
});
} else {
lp_position.lp_coin.amount.checked_sub(amt)?
}
}
ActionAmount::AccountBalance => lp_position.lp_coin.amount,
};

let updated_coin = coin(new_amount.u128(), lp_coin.denom.as_str());

increment_coin_balance(deps.storage, account_id, &updated_coin)?;

// unstake msg
let unstake_msg = incentives.unstake_astro_lp_msg(account_id, &updated_coin)?;

let mut res = Response::new()
.add_message(unstake_msg)
.add_attribute("action", "unstake_astro_lp")
.add_attribute("account_id", account_id)
.add_attribute("lp_unstaked", updated_coin.to_string());

if !lp_position.rewards.is_empty() {
res = res.add_attribute("rewards", lp_position.rewards.as_slice().to_string());
}

Ok(res)
}
3 changes: 3 additions & 0 deletions contracts/credit-manager/tests/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub use mars_testing::multitest::helpers;

mod test_borrow;
mod test_claim_astro_lp_rewards;
mod test_claim_rewards;
mod test_coin_balances;
mod test_create_credit_account;
Expand Down Expand Up @@ -30,7 +31,9 @@ mod test_refund_balances;
mod test_repay;
mod test_repay_for_recipient;
mod test_repay_from_wallet;
mod test_stake_astro_lp;
mod test_swap;
mod test_unstake_astro_lp;
mod test_update_admin;
mod test_update_config;
mod test_update_credit_account_with_new_acc;
Expand Down
Loading

0 comments on commit 1fb38b1

Please sign in to comment.