Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ARTIFACTS_DIR_PATH = "target/wasm32-unknown-unknown/release"
RUST_OPTIMIZER_VERSION = "0.16.0"
# Use rust version from rust-optimizer Dockerfile (see https://github.com/CosmWasm/optimizer/blob/v0.16.0/Dockerfile#L1)
# to be sure that we compile / test against the same version
RUST_VERSION = "1.78.0"
RUST_VERSION = "1.81.0"

[tasks.install-stable]
script = '''
Expand Down
1 change: 1 addition & 0 deletions contracts/account-nft/tests/tests/helpers/mock_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use mars_types::{

use super::MockEnvBuilder;

#[allow(dead_code)]
pub struct MockEnv {
pub app: BasicApp,
pub minter: Addr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ impl MockEnvBuilder {
zapper: "n/a".to_string(),
health_contract: "n/a".to_string(),
rewards_collector: None,
swap_fee: Decimal::percent(1),
},
},
&[],
Expand Down
2 changes: 1 addition & 1 deletion contracts/credit-manager/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mars-credit-manager"
version = { workspace = true }
version = "2.2.0"
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
Expand Down
6 changes: 3 additions & 3 deletions contracts/credit-manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{
query::{
query_accounts, query_all_coin_balances, query_all_debt_shares,
query_all_total_debt_shares, query_all_vault_positions, query_all_vault_utilizations,
query_config, query_positions, query_total_debt_shares, query_vault_bindings,
query_vault_position_value, query_vault_utilization,
query_config, query_positions, query_swap_fee, query_total_debt_shares,
query_vault_bindings, query_vault_position_value, query_vault_utilization,
},
repay::repay_from_wallet,
update_config::{update_config, update_nft_config, update_owner},
Expand Down Expand Up @@ -139,5 +139,5 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult<Binary> {

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> Result<Response, ContractError> {
migrations::v2_1_0::migrate(deps)
migrations::v2_2_0::migrate(deps)
}
3 changes: 2 additions & 1 deletion contracts/credit-manager/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
HEALTH_CONTRACT, INCENTIVES, MAX_SLIPPAGE, MAX_UNLOCKING_POSITIONS, ORACLE, OWNER, PARAMS,
RED_BANK, SWAPPER, SWAP_FEE, ZAPPER,
},
utils::assert_max_slippage,
utils::{assert_max_slippage, assert_swap_fee},
};

pub fn store_config(deps: DepsMut, env: Env, msg: &InstantiateMsg) -> ContractResult<()> {
Expand All @@ -32,6 +32,7 @@ pub fn store_config(deps: DepsMut, env: Env, msg: &InstantiateMsg) -> ContractRe
HEALTH_CONTRACT.save(deps.storage, &msg.health_contract.check(deps.api)?)?;
PARAMS.save(deps.storage, &msg.params.check(deps.api)?)?;
INCENTIVES.save(deps.storage, &msg.incentives.check(deps.api, env.contract.address)?)?;
assert_swap_fee(msg.swap_fee)?;
SWAP_FEE.save(deps.storage, &msg.swap_fee)?;

Ok(())
Expand Down
1 change: 1 addition & 0 deletions contracts/credit-manager/src/liquidate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
/// - Exceeds liquidatee's total debt for denom
/// - Not enough liquidatee request coin balance to match
/// - The value of the debt repaid exceeds the Maximum Debt Repayable (MDR)
///
/// Returns -> (Debt Coin, Liquidator Request Coin, Liquidatee Request Coin)
/// Difference between Liquidator Request Coin and Liquidatee Request Coin goes to rewards-collector account as protocol fee.
pub fn calculate_liquidation(
Expand Down
1 change: 1 addition & 0 deletions contracts/credit-manager/src/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod v2_1_0;
pub mod v2_2_0;
10 changes: 4 additions & 6 deletions contracts/credit-manager/src/migrations/v2_1_0.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
use cosmwasm_std::{DepsMut, Response};
use cw2::{assert_contract_version, set_contract_version};

use crate::{
contract::{CONTRACT_NAME, CONTRACT_VERSION},
error::ContractError,
};
use crate::{contract::CONTRACT_NAME, error::ContractError};

const FROM_VERSION: &str = "2.0.3";
const TO_VERSION: &str = "2.1.0";

pub fn migrate(deps: DepsMut) -> Result<Response, ContractError> {
// make sure we're migrating the correct contract and from the correct version
assert_contract_version(deps.storage, &format!("crates.io:{CONTRACT_NAME}"), FROM_VERSION)?;

set_contract_version(deps.storage, format!("crates.io:{CONTRACT_NAME}"), CONTRACT_VERSION)?;
set_contract_version(deps.storage, format!("crates.io:{CONTRACT_NAME}"), TO_VERSION)?;

Ok(Response::new()
.add_attribute("action", "migrate")
.add_attribute("from_version", FROM_VERSION)
.add_attribute("to_version", CONTRACT_VERSION))
.add_attribute("to_version", TO_VERSION))
}
43 changes: 43 additions & 0 deletions contracts/credit-manager/src/migrations/v2_2_0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use cosmwasm_std::{Decimal, DepsMut, Response};
use cw2::{assert_contract_version, get_contract_version, set_contract_version, VersionError};

use crate::{
contract::{CONTRACT_NAME, CONTRACT_VERSION},
error::ContractError,
state::SWAP_FEE,
};

const FROM_VERSION: &str = "2.1.0";

pub fn migrate(deps: DepsMut) -> Result<Response, ContractError> {
let contract = format!("crates.io:{CONTRACT_NAME}");
let version = get_contract_version(deps.storage)?;
let from_version = version.version;

if version.contract != contract {
return Err(ContractError::Version(VersionError::WrongContract {
expected: contract,
found: version.contract,
}));
}

if from_version != FROM_VERSION {
return Err(ContractError::Version(VersionError::WrongVersion {
expected: FROM_VERSION.to_string(),
found: from_version,
}));
}

assert_contract_version(deps.storage, &contract, FROM_VERSION)?;

if SWAP_FEE.may_load(deps.storage)?.is_none() {
SWAP_FEE.save(deps.storage, &Decimal::zero())?;
}

set_contract_version(deps.storage, format!("crates.io:{CONTRACT_NAME}"), CONTRACT_VERSION)?;

Ok(Response::new()
.add_attribute("action", "migrate")
.add_attribute("from_version", from_version)
.add_attribute("to_version", CONTRACT_VERSION))
}
7 changes: 5 additions & 2 deletions contracts/credit-manager/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{Coin, Deps, Env, Order, StdResult};
use cosmwasm_std::{Coin, Decimal, Deps, Env, Order, StdResult};
use cw_paginate::{paginate_map, paginate_map_query, PaginationResponse, DEFAULT_LIMIT, MAX_LIMIT};
use cw_storage_plus::Bound;
use mars_types::{
Expand Down Expand Up @@ -59,10 +59,13 @@ pub fn query_config(deps: Deps) -> ContractResult<ConfigResponse> {
zapper: ZAPPER.load(deps.storage)?.address().into(),
health_contract: HEALTH_CONTRACT.load(deps.storage)?.address().into(),
rewards_collector: REWARDS_COLLECTOR.may_load(deps.storage)?,
swap_fee: SWAP_FEE.load(deps.storage)?,
})
}

pub fn query_swap_fee(deps: Deps) -> ContractResult<Decimal> {
Ok(SWAP_FEE.load(deps.storage)?)
}

pub fn query_positions(deps: Deps, account_id: &str) -> ContractResult<Positions> {
Ok(Positions {
account_id: account_id.to_string(),
Expand Down
3 changes: 2 additions & 1 deletion contracts/credit-manager/tests/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ mod test_liquidate_lend;
mod test_liquidate_staked_astro_lp;
mod test_liquidate_vault;
mod test_liquidation_pricing;
mod test_migration_v2;
mod test_migration_v2_2_0;
mod test_no_health_check;
mod test_reclaim;
mod test_reentrancy_guard;
mod test_refund_balances;
mod test_repay;
mod test_repay_for_recipient;
mod test_repay_from_wallet;
mod test_rewards_collector_whitelist;
mod test_stake_astro_lp;
mod test_swap;
mod test_unstake_astro_lp;
Expand Down
8 changes: 8 additions & 0 deletions contracts/credit-manager/tests/tests/test_instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ fn params_set_on_instantiate() {
fn raises_on_invalid_params_addr() {
MockEnv::new().params("%%%INVALID%%%").build().unwrap();
}

#[test]
#[should_panic]
fn raises_on_invalid_swap_fee() {
use cosmwasm_std::Decimal;

MockEnv::new().swap_fee(Decimal::percent(100)).build().unwrap();
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use cosmwasm_std::{attr, testing::mock_env, Empty, Event};
use cosmwasm_std::{attr, testing::mock_env, Decimal, Empty, Event};
use cw2::{ContractVersion, VersionError};
use mars_credit_manager::{contract::migrate, error::ContractError};
use mars_credit_manager::{contract::migrate, error::ContractError, state::SWAP_FEE};
use mars_testing::mock_dependencies;

#[test]
fn wrong_contract_name() {
let mut deps = mock_dependencies(&[]);
cw2::set_contract_version(deps.as_mut().storage, "contract_xyz", "2.0.3").unwrap();
cw2::set_contract_version(deps.as_mut().storage, "contract_xyz", "2.1.0").unwrap();

let err = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap_err();

assert_eq!(
err,
match err {
ContractError::Version(VersionError::WrongContract {
expected: "crates.io:mars-credit-manager".to_string(),
found: "contract_xyz".to_string()
})
);
expected,
found,
}) => {
assert_eq!(expected, "crates.io:mars-credit-manager".to_string());
assert_eq!(found, "contract_xyz".to_string());
}
other => panic!("unexpected error: {other:?}"),
}
}

#[test]
Expand All @@ -27,19 +30,21 @@ fn wrong_contract_version() {

let err = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap_err();

assert_eq!(
err,
match err {
ContractError::Version(VersionError::WrongVersion {
expected: "2.0.3".to_string(),
found: "4.1.0".to_string()
})
);
found,
..
}) => {
assert_eq!(found, "4.1.0".to_string());
}
other => panic!("unexpected error: {other:?}"),
}
}

#[test]
fn successful_migration() {
fn successful_migration_from_2_1_0() {
let mut deps = mock_dependencies(&[]);
cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-credit-manager", "2.0.3")
cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-credit-manager", "2.1.0")
.unwrap();

let res = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap();
Expand All @@ -49,12 +54,16 @@ fn successful_migration() {
assert!(res.data.is_none());
assert_eq!(
res.attributes,
vec![attr("action", "migrate"), attr("from_version", "2.0.3"), attr("to_version", "2.1.0")]
vec![attr("action", "migrate"), attr("from_version", "2.1.0"), attr("to_version", "2.2.0")]
);

let new_contract_version = ContractVersion {
contract: "crates.io:mars-credit-manager".to_string(),
version: "2.1.0".to_string(),
version: "2.2.0".to_string(),
};
assert_eq!(cw2::get_contract_version(deps.as_ref().storage).unwrap(), new_contract_version);

// Ensure swap fee exists post-migration (zero by default if absent)
let swap_fee = SWAP_FEE.may_load(deps.as_ref().storage).unwrap().unwrap_or_else(Decimal::zero);
assert!(swap_fee <= Decimal::one());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use cosmwasm_std::{coin, Addr};
use cw_multi_test::{BankSudo, Executor, SudoMsg};
use mars_testing::multitest::helpers;
use mars_types::rewards_collector::{
ExecuteMsg as RcExecuteMsg, UpdateConfig as RcUpdateConfig, WhitelistAction,
};

#[test]
fn rewards_collector_whitelist_enforced() {
let mut mock = helpers::MockEnv::new().build().unwrap();
let config = mock.query_config();
let rewards_collector_info = config.rewards_collector.expect("rewards collector configured");
let rewards_collector_addr = Addr::unchecked(rewards_collector_info.address.clone());

// fund the rewards collector with uusdc so distribution can execute
mock.app
.sudo(SudoMsg::Bank(BankSudo::Mint {
to_address: rewards_collector_addr.to_string(),
amount: vec![coin(1_000, "uusdc")],
}))
.unwrap();

// non-whitelisted address cannot distribute rewards
assert!(mock
.app
.execute_contract(
Addr::unchecked("not_whitelisted"),
rewards_collector_addr.clone(),
&RcExecuteMsg::DistributeRewards {
denom: "uusdc".to_string(),
},
&[],
)
.is_err());

// whitelist alice
mock.app
.execute_contract(
Addr::unchecked("owner"),
rewards_collector_addr.clone(),
&RcExecuteMsg::UpdateConfig {
new_cfg: RcUpdateConfig {
whitelist_actions: Some(vec![WhitelistAction::AddAddress {
address: "alice".to_string(),
}]),
..Default::default()
},
},
&[],
)
.unwrap();

// whitelisted address succeeds
mock.app
.execute_contract(
Addr::unchecked("alice"),
rewards_collector_addr,
&RcExecuteMsg::DistributeRewards {
denom: "uusdc".to_string(),
},
&[],
)
.unwrap();
}
3 changes: 0 additions & 3 deletions contracts/credit-manager/tests/tests/test_update_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,6 @@ fn update_config_works_with_full_config() {
assert_eq!(&new_config.health_contract, new_health_contract.address());
assert_ne!(new_config.health_contract, original_config.health_contract);

assert_eq!(new_config.swap_fee, new_swap_fee);
assert_ne!(new_config.swap_fee, original_config.swap_fee);

let rc_accounts = mock.query_accounts(&new_rewards_collector, None, None);
let rc_account = rc_accounts.first().unwrap();
assert_eq!(rc_account.kind, AccountKind::Default);
Expand Down
1 change: 0 additions & 1 deletion contracts/health/tests/tests/helpers/mock_env_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ impl MockEnvBuilder {
zapper: "n/a".to_string(),
health_contract: "n/a".to_string(),
rewards_collector: None,
swap_fee: Decimal::permille(1),
},
},
&[],
Expand Down
2 changes: 1 addition & 1 deletion contracts/incentives/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl MaybeMutStorage<'_> {
/// - duration is a multiple of epoch duration
/// - enough tokens are sent to cover the entire duration
/// - start_time is a multiple of epoch duration away from any other existing incentive
/// for the same collateral denom and incentive denom tuple
/// for the same collateral denom and incentive denom tuple
pub fn validate_incentive_schedule(
storage: &dyn Storage,
info: &MessageInfo,
Expand Down
Loading
Loading