From bb5da4a4668e64b1696197f02ec09c35cd387e23 Mon Sep 17 00:00:00 2001 From: piobab Date: Wed, 21 Feb 2024 17:08:44 +0100 Subject: [PATCH] Fix inflated collateral (#354) * Inflated collateral issue. * Fix inflated collateral. * Bound current utilization ratio to 100% max. * Add check for zero debt shares just in case. * Add migration. * Return error if utilization rate > 100%. * Revert "Return error if utilization rate > 100%." This reverts commit 835efaf08d41e7ce260f4be254841fe948fda719. * Update migration to v2.0.3. * Update schema. --- Cargo.lock | 6 +- contracts/credit-manager/Cargo.toml | 2 +- contracts/credit-manager/src/borrow.rs | 5 + contracts/credit-manager/src/contract.rs | 2 +- contracts/credit-manager/src/error.rs | 3 + .../credit-manager/src/migrations/mod.rs | 2 +- .../src/migrations/{v2_0_2.rs => v2_0_3.rs} | 2 +- .../tests/tests/test_migration_v2.rs | 10 +- contracts/red-bank/Cargo.toml | 2 +- contracts/red-bank/src/borrow.rs | 10 +- contracts/red-bank/src/contract.rs | 13 +- contracts/red-bank/src/error.rs | 2 +- contracts/red-bank/src/interest_rates.rs | 7 +- contracts/red-bank/src/migrations/mod.rs | 1 + contracts/red-bank/src/migrations/v2_0_1.rs | 21 ++ contracts/red-bank/tests/tests/mod.rs | 2 +- .../tests/tests/test_inflated_collateral.rs | 201 ++++++++++++++++++ .../red-bank/tests/tests/test_migration_v2.rs | 36 +++- packages/types/src/credit_manager/migrate.rs | 2 +- packages/types/src/red_bank/msg.rs | 6 + .../mars-credit-manager.json | 2 +- schemas/mars-red-bank/mars-red-bank.json | 2 +- 22 files changed, 305 insertions(+), 34 deletions(-) rename contracts/credit-manager/src/migrations/{v2_0_2.rs => v2_0_3.rs} (95%) create mode 100644 contracts/red-bank/src/migrations/v2_0_1.rs create mode 100644 contracts/red-bank/tests/tests/test_inflated_collateral.rs diff --git a/Cargo.lock b/Cargo.lock index 84297e92b..a6940811a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2215,7 +2215,7 @@ dependencies = [ [[package]] name = "mars-credit-manager" -version = "2.0.2" +version = "2.0.3" dependencies = [ "anyhow", "cosmwasm-schema", @@ -2519,7 +2519,7 @@ dependencies = [ [[package]] name = "mars-red-bank" -version = "2.0.0" +version = "2.0.1" dependencies = [ "anyhow", "cosmwasm-schema", @@ -2762,7 +2762,7 @@ dependencies = [ name = "mars-types" version = "2.0.0" dependencies = [ - "astroport", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 1.1.0", diff --git a/contracts/credit-manager/Cargo.toml b/contracts/credit-manager/Cargo.toml index 687b8f750..6865538a6 100644 --- a/contracts/credit-manager/Cargo.toml +++ b/contracts/credit-manager/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mars-credit-manager" -version = "2.0.2" +version = "2.0.3" authors = { workspace = true } license = { workspace = true } edition = { workspace = true } diff --git a/contracts/credit-manager/src/borrow.rs b/contracts/credit-manager/src/borrow.rs index 63e3efce7..c14f69dca 100644 --- a/contracts/credit-manager/src/borrow.rs +++ b/contracts/credit-manager/src/borrow.rs @@ -31,6 +31,11 @@ pub fn borrow(mut deps: DepsMut, account_id: &str, coin: Coin) -> ContractResult .checked_multiply_ratio(coin.amount, total_debt_amount)? }; + // It shouldn't happen but just in case + if debt_shares_to_add.is_zero() { + return Err(ContractError::ZeroDebtShares); + } + TOTAL_DEBT_SHARES.update(deps.storage, &coin.denom, |shares| { shares .unwrap_or_else(Uint128::zero) diff --git a/contracts/credit-manager/src/contract.rs b/contracts/credit-manager/src/contract.rs index d130689b2..07c53159a 100644 --- a/contracts/credit-manager/src/contract.rs +++ b/contracts/credit-manager/src/contract.rs @@ -128,6 +128,6 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult { pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> ContractResult { match msg { MigrateMsg::V1_0_0ToV2_0_0(updates) => migrations::v2_0_0::migrate(deps, env, updates), - MigrateMsg::V2_0_1ToV2_0_2 {} => migrations::v2_0_2::migrate(deps), + MigrateMsg::V2_0_2ToV2_0_3 {} => migrations::v2_0_3::migrate(deps), } } diff --git a/contracts/credit-manager/src/error.rs b/contracts/credit-manager/src/error.rs index 499161941..9c79a18e3 100644 --- a/contracts/credit-manager/src/error.rs +++ b/contracts/credit-manager/src/error.rs @@ -186,4 +186,7 @@ pub enum ContractError { #[error(transparent)] Oracle(#[from] OracleError), + + #[error("Debt cannot be represented by zero debt shares")] + ZeroDebtShares, } diff --git a/contracts/credit-manager/src/migrations/mod.rs b/contracts/credit-manager/src/migrations/mod.rs index 55e91380a..19e4b2c41 100644 --- a/contracts/credit-manager/src/migrations/mod.rs +++ b/contracts/credit-manager/src/migrations/mod.rs @@ -1,2 +1,2 @@ pub mod v2_0_0; -pub mod v2_0_2; +pub mod v2_0_3; diff --git a/contracts/credit-manager/src/migrations/v2_0_2.rs b/contracts/credit-manager/src/migrations/v2_0_3.rs similarity index 95% rename from contracts/credit-manager/src/migrations/v2_0_2.rs rename to contracts/credit-manager/src/migrations/v2_0_3.rs index 19adaf51e..b0b1b12cb 100644 --- a/contracts/credit-manager/src/migrations/v2_0_2.rs +++ b/contracts/credit-manager/src/migrations/v2_0_3.rs @@ -6,7 +6,7 @@ use crate::{ error::ContractError, }; -const FROM_VERSION: &str = "2.0.1"; +const FROM_VERSION: &str = "2.0.2"; pub fn migrate(deps: DepsMut) -> Result { // make sure we're migrating the correct contract and from the correct version diff --git a/contracts/credit-manager/tests/tests/test_migration_v2.rs b/contracts/credit-manager/tests/tests/test_migration_v2.rs index 0a258f39f..2e73e84cd 100644 --- a/contracts/credit-manager/tests/tests/test_migration_v2.rs +++ b/contracts/credit-manager/tests/tests/test_migration_v2.rs @@ -151,24 +151,24 @@ fn successful_migration() { } #[test] -fn successful_migration_to_v2_0_2() { +fn successful_migration_to_v2_0_3() { let mut deps = mock_dependencies(); - cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-credit-manager", "2.0.1") + cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-credit-manager", "2.0.2") .unwrap(); - let res = migrate(deps.as_mut(), mock_env(), MigrateMsg::V2_0_1ToV2_0_2 {}).unwrap(); + let res = migrate(deps.as_mut(), mock_env(), MigrateMsg::V2_0_2ToV2_0_3 {}).unwrap(); assert_eq!(res.messages, vec![]); assert_eq!(res.events, vec![] as Vec); assert!(res.data.is_none()); assert_eq!( res.attributes, - vec![attr("action", "migrate"), attr("from_version", "2.0.1"), attr("to_version", "2.0.2")] + vec![attr("action", "migrate"), attr("from_version", "2.0.2"), attr("to_version", "2.0.3")] ); let new_contract_version = ContractVersion { contract: "crates.io:mars-credit-manager".to_string(), - version: "2.0.2".to_string(), + version: "2.0.3".to_string(), }; assert_eq!(cw2::get_contract_version(deps.as_ref().storage).unwrap(), new_contract_version); } diff --git a/contracts/red-bank/Cargo.toml b/contracts/red-bank/Cargo.toml index ff4b71600..e4b579797 100644 --- a/contracts/red-bank/Cargo.toml +++ b/contracts/red-bank/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mars-red-bank" description = "A smart contract that manages asset deposit, borrowing, and liquidations" -version = { workspace = true } +version = "2.0.1" authors = { workspace = true } edition = { workspace = true } license = { workspace = true } diff --git a/contracts/red-bank/src/borrow.rs b/contracts/red-bank/src/borrow.rs index fc7345043..831c058b2 100644 --- a/contracts/red-bank/src/borrow.rs +++ b/contracts/red-bank/src/borrow.rs @@ -58,9 +58,15 @@ pub fn borrow( &borrow_market, env.block.time.seconds(), )?; + let debt_balance_before = get_underlying_debt_amount( + borrow_market.debt_total_scaled, + &borrow_market, + env.block.time.seconds(), + )?; - // Cannot borrow zero amount or more than available collateral - if borrow_amount.is_zero() || borrow_amount > collateral_balance_before { + // Cannot borrow zero amount or more than available liquidity + let available_liquidity = collateral_balance_before.checked_sub(debt_balance_before)?; + if borrow_amount.is_zero() || borrow_amount > available_liquidity { return Err(ContractError::InvalidBorrowAmount { denom, }); diff --git a/contracts/red-bank/src/contract.rs b/contracts/red-bank/src/contract.rs index b941f7dd7..76272671b 100644 --- a/contracts/red-bank/src/contract.rs +++ b/contracts/red-bank/src/contract.rs @@ -1,7 +1,5 @@ -use cosmwasm_std::{ - entry_point, to_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, -}; -use mars_types::red_bank::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use cosmwasm_std::{entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response}; +use mars_types::red_bank::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; use crate::{ asset, borrow, collateral, config, deposit, error::ContractError, instantiate, liquidate, @@ -260,6 +258,9 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Result { - migrations::v2_0_0::migrate(deps) +pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result { + match msg { + MigrateMsg::V1_0_0ToV2_0_0 {} => migrations::v2_0_0::migrate(deps), + MigrateMsg::V2_0_0ToV2_0_1 {} => migrations::v2_0_1::migrate(deps), + } } diff --git a/contracts/red-bank/src/error.rs b/contracts/red-bank/src/error.rs index 26b9728da..31a9d7acd 100644 --- a/contracts/red-bank/src/error.rs +++ b/contracts/red-bank/src/error.rs @@ -81,7 +81,7 @@ pub enum ContractError { #[error("Cannot have 0 as liquidity index")] InvalidLiquidityIndex {}, - #[error("Borrow amount must be greater than 0 and less or equal available collateral (asset: {denom:?})")] + #[error("Borrow amount must be greater than 0 and less or equal available liquidity (asset: {denom:?})")] InvalidBorrowAmount { denom: String, }, diff --git a/contracts/red-bank/src/interest_rates.rs b/contracts/red-bank/src/interest_rates.rs index 0132729f7..3d65c6774 100644 --- a/contracts/red-bank/src/interest_rates.rs +++ b/contracts/red-bank/src/interest_rates.rs @@ -111,12 +111,17 @@ pub fn update_interest_rates( let total_debt = get_underlying_debt_amount(market.debt_total_scaled, market, current_timestamp)?; - let current_utilization_rate = if !total_collateral.is_zero() { + let mut current_utilization_rate = if !total_collateral.is_zero() { Decimal::from_ratio(total_debt, total_collateral) } else { Decimal::zero() }; + // Limit utilization_rate to 100%. + // With the current code it should hopefully never happen that it gets calculated to more than 100%, + // but better be safe than sorry. + current_utilization_rate = current_utilization_rate.min(Decimal::one()); + market.update_interest_rates(current_utilization_rate)?; Ok(response.add_event(build_interests_updated_event(&market.denom, market))) diff --git a/contracts/red-bank/src/migrations/mod.rs b/contracts/red-bank/src/migrations/mod.rs index 7592b6f12..24a4db4ab 100644 --- a/contracts/red-bank/src/migrations/mod.rs +++ b/contracts/red-bank/src/migrations/mod.rs @@ -1 +1,2 @@ pub mod v2_0_0; +pub mod v2_0_1; diff --git a/contracts/red-bank/src/migrations/v2_0_1.rs b/contracts/red-bank/src/migrations/v2_0_1.rs new file mode 100644 index 000000000..777b1e365 --- /dev/null +++ b/contracts/red-bank/src/migrations/v2_0_1.rs @@ -0,0 +1,21 @@ +use cosmwasm_std::{DepsMut, Response}; +use cw2::{assert_contract_version, set_contract_version}; + +use crate::{ + contract::{CONTRACT_NAME, CONTRACT_VERSION}, + error::ContractError, +}; + +const FROM_VERSION: &str = "2.0.0"; + +pub fn migrate(deps: DepsMut) -> Result { + // 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)?; + + Ok(Response::new() + .add_attribute("action", "migrate") + .add_attribute("from_version", FROM_VERSION) + .add_attribute("to_version", CONTRACT_VERSION)) +} diff --git a/contracts/red-bank/tests/tests/mod.rs b/contracts/red-bank/tests/tests/mod.rs index c3fa34e41..871897b04 100644 --- a/contracts/red-bank/tests/tests/mod.rs +++ b/contracts/red-bank/tests/tests/mod.rs @@ -5,7 +5,7 @@ mod test_borrow; mod test_credit_accounts; mod test_deposit; mod test_health; -mod test_liquidate; +mod test_inflated_collateral; mod test_migration_v2; mod test_misc; mod test_payment; diff --git a/contracts/red-bank/tests/tests/test_inflated_collateral.rs b/contracts/red-bank/tests/tests/test_inflated_collateral.rs new file mode 100644 index 000000000..f05a6eb2c --- /dev/null +++ b/contracts/red-bank/tests/tests/test_inflated_collateral.rs @@ -0,0 +1,201 @@ +use std::{cmp::min, str::FromStr}; + +use cosmwasm_std::{coin, Addr, Decimal, Uint128}; +use mars_red_bank::error::ContractError; +use mars_testing::integration::mock_env::MockEnvBuilder; +use mars_types::{ + params::{AssetParams, CmSettings, LiquidationBonus, RedBankSettings}, + red_bank::{InitOrUpdateAssetParams, InterestRateModel}, +}; + +use crate::tests::helpers::assert_err; + +#[test] +fn inflated_collateral() { + let atom_price = Decimal::from_ratio(1133u128, 100u128); // 1 ATOM = 11.33 USD + let osmo_price = Decimal::from_ratio(163u128, 100u128); // 1 OSMO = 1.63 USD + + let owner = Addr::unchecked("owner"); + let mut mock_env = MockEnvBuilder::new(None, owner).build(); + let oracle = mock_env.oracle.clone(); + oracle.set_price_source_fixed(&mut mock_env, "uatom", atom_price); + oracle.set_price_source_fixed(&mut mock_env, "uosmo", osmo_price); + + let red_bank = mock_env.red_bank.clone(); + let params = mock_env.params.clone(); + + let (atom_market_params, atom_asset_params) = atom_asset_params("uatom"); + red_bank.init_asset(&mut mock_env, &atom_asset_params.denom, atom_market_params); + params.init_params(&mut mock_env, atom_asset_params.clone()); + + let (osmo_market_params, osmo_asset_params) = osmo_asset_params("uosmo"); + red_bank.init_asset(&mut mock_env, &osmo_asset_params.denom, osmo_market_params); + params.init_params(&mut mock_env, osmo_asset_params.clone()); + + let borrower = Addr::unchecked("borrower"); + let borrower2 = Addr::unchecked("borrower2"); + let other_depositor = Addr::unchecked("otherdepositor"); + + let funded_atom = 1024000000; + let donated_atom = 450 * funded_atom; + // max_atom_borrow_amt = osmo_collateral * osmo_price * osmo_ltv / atom_price + // osmo_collateral = max_atom_borrow_amt * atom_price / (osmo_price * osmo_ltv) + let osmo_collateral = Uint128::new(donated_atom) + .checked_mul_floor(atom_price) + .unwrap() + .checked_div_floor(osmo_price) + .unwrap() + .checked_div_floor(osmo_asset_params.max_loan_to_value) + .unwrap() + .u128(); + let osmo_other_deposit = 3_059_483_963_978_u128; // OSMO deposit from someone else (OSMO funds already deposited in the market) + + // Deposit ATOM collateral + mock_env.fund_account(&borrower, &[coin(funded_atom, "uatom")]); + red_bank.deposit(&mut mock_env, &borrower, coin(funded_atom, "uatom")).unwrap(); + + // Donate ATOM to the protocol (which will be borrowed later) to inflate the collateral + mock_env.fund_account(&red_bank.contract_addr, &[coin(donated_atom, "uatom")]); + + // From another account, deposit max allowed OSMO to fill the caps + let left_osmo_deposit = osmo_asset_params.deposit_cap - Uint128::new(osmo_other_deposit); + let osmo_collateral = min(osmo_collateral, left_osmo_deposit.u128()); + mock_env.fund_account(&borrower2, &[coin(osmo_collateral, "uosmo")]); + red_bank.deposit(&mut mock_env, &borrower2, coin(osmo_collateral, "uosmo")).unwrap(); + assert_eq!(osmo_collateral, 4_387_649_382_300_u128); + + // Fund OSMO market (representing OSMO funds from other depositors) + mock_env.fund_account(&other_depositor, &[coin(osmo_other_deposit, "uosmo")]); + red_bank.deposit(&mut mock_env, &other_depositor, coin(osmo_other_deposit, "uosmo")).unwrap(); + + // Borrow available liquidity + red_bank.borrow(&mut mock_env, &borrower2, "uatom", funded_atom).unwrap(); + let error_res = red_bank.borrow(&mut mock_env, &borrower2, "uatom", funded_atom); + assert_err( + error_res, + ContractError::InvalidBorrowAmount { + denom: "uatom".to_string(), + }, + ); + + // borrower2 received only part of the initially donated ATOM + let atom_balance_borrower2 = mock_env.query_balance(&borrower2, "uatom").unwrap(); + assert_eq!(atom_balance_borrower2.amount.u128(), funded_atom); + let left_atom_donated = Uint128::new(donated_atom) - atom_balance_borrower2.amount; + + // Validate that borrower2 has no OSMO left in balance + let uosmo_balance_borrower2 = mock_env.query_balance(&borrower2, "uosmo").unwrap(); + assert_eq!(uosmo_balance_borrower2.amount.u128(), 0); + + // Wait 4 hours + let seconds_to_wait: u64 = 60 * 60 * 4; + mock_env.app.update_block(|b| b.time = b.time.plus_seconds(seconds_to_wait)); + + // Validate ATOM market borrow and liquidity rates aren't hyper inflated + let market = red_bank.query_market(&mut mock_env, "uatom"); + assert_eq!(market.borrow_rate, Decimal::percent(320)); + assert_eq!(market.liquidity_rate, Decimal::percent(288)); + + let new_user_res = red_bank.query_user_collateral(&mut mock_env, &borrower, "uatom"); + + let uosmo_borrow_amount = new_user_res + .amount + .checked_mul_floor(atom_price) + .unwrap() + .checked_mul_floor(atom_asset_params.max_loan_to_value) + .unwrap() + .checked_div_floor(osmo_price) + .unwrap(); + + // Borrows OSMO against ATOM collateral + let uosmo_borrow_amount = + min(uosmo_borrow_amount, Uint128::new(osmo_collateral + osmo_other_deposit)); // Borrow max allowed OSMO based on available liquidity + red_bank.borrow(&mut mock_env, &borrower, "uosmo", uosmo_borrow_amount.u128()).unwrap(); + + // Validate borrower has received borrowed OSMO + let uosmo_balance_borrower = mock_env.query_balance(&borrower, "uosmo").unwrap(); + assert_eq!(uosmo_balance_borrower.amount.u128(), uosmo_borrow_amount.u128()); + + // Validate borrower has OSMO debt + let uosmo_debt_borrower = red_bank.query_user_debt(&mut mock_env, &borrower, "uosmo"); + assert_eq!(uosmo_debt_borrower.amount.u128(), uosmo_borrow_amount.u128()); + + // Calculate profit + let usd_funded_osmo = + Uint128::new(osmo_collateral).checked_mul_floor(osmo_price).unwrap().u128() as i128; + let usd_uosmo_borrow_amount = + uosmo_borrow_amount.checked_mul_floor(osmo_price).unwrap().u128() as i128; + let usd_left_atom_donated = + left_atom_donated.checked_mul_floor(atom_price).unwrap().u128() as i128; + + let usd_profit = usd_uosmo_borrow_amount - usd_funded_osmo - usd_left_atom_donated; + assert!(usd_profit.checked_div(1_000_000).unwrap() < 0); +} + +fn atom_asset_params(denom: &str) -> (InitOrUpdateAssetParams, AssetParams) { + let market_params = InitOrUpdateAssetParams { + reserve_factor: Some(Decimal::percent(10)), + interest_rate_model: Some(InterestRateModel { + optimal_utilization_rate: Decimal::percent(80), + base: Decimal::percent(0), + slope_1: Decimal::percent(20), + slope_2: Decimal::percent(300), + }), + }; + let asset_params = AssetParams { + denom: denom.to_string(), + credit_manager: CmSettings { + whitelisted: false, + hls: None, + }, + red_bank: RedBankSettings { + deposit_enabled: true, + borrow_enabled: true, + }, + max_loan_to_value: Decimal::percent(74), + liquidation_threshold: Decimal::percent(75), + liquidation_bonus: LiquidationBonus { + starting_lb: Decimal::zero(), + slope: Decimal::from_str("1").unwrap(), + min_lb: Decimal::percent(5), + max_lb: Decimal::percent(20), + }, + protocol_liquidation_fee: Decimal::percent(25), + deposit_cap: Uint128::from(700000000000u128), + }; + (market_params, asset_params) +} + +fn osmo_asset_params(denom: &str) -> (InitOrUpdateAssetParams, AssetParams) { + let market_params = InitOrUpdateAssetParams { + reserve_factor: Some(Decimal::percent(10)), + interest_rate_model: Some(InterestRateModel { + optimal_utilization_rate: Decimal::percent(60), + base: Decimal::percent(0), + slope_1: Decimal::percent(15), + slope_2: Decimal::percent(300), + }), + }; + let asset_params = AssetParams { + denom: denom.to_string(), + credit_manager: CmSettings { + whitelisted: false, + hls: None, + }, + red_bank: RedBankSettings { + deposit_enabled: true, + borrow_enabled: true, + }, + max_loan_to_value: Decimal::percent(73), + liquidation_threshold: Decimal::percent(75), + liquidation_bonus: LiquidationBonus { + starting_lb: Decimal::zero(), + slope: Decimal::from_str("1").unwrap(), + min_lb: Decimal::percent(5), + max_lb: Decimal::percent(20), + }, + protocol_liquidation_fee: Decimal::percent(25), + deposit_cap: Uint128::from(10000000000000u128), + }; + (market_params, asset_params) +} diff --git a/contracts/red-bank/tests/tests/test_migration_v2.rs b/contracts/red-bank/tests/tests/test_migration_v2.rs index fa4213ee9..d6639a3fd 100644 --- a/contracts/red-bank/tests/tests/test_migration_v2.rs +++ b/contracts/red-bank/tests/tests/test_migration_v2.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, str::FromStr}; use cosmwasm_std::{ attr, testing::{mock_env, mock_info}, - Addr, Decimal, Empty, Event, Order, StdResult, Uint128, + Addr, Decimal, Event, Order, StdResult, Uint128, }; use cw2::{ContractVersion, VersionError}; use mars_red_bank::{ @@ -15,7 +15,7 @@ use mars_red_bank::{ use mars_testing::mock_dependencies; use mars_types::{ keys::{UserId, UserIdKey}, - red_bank::{Collateral, ExecuteMsg, InterestRateModel, Market, MigrateV1ToV2}, + red_bank::{Collateral, ExecuteMsg, InterestRateModel, Market, MigrateMsg, MigrateV1ToV2}, }; use mars_utils::error::GuardError; @@ -24,7 +24,7 @@ fn wrong_contract_name() { let mut deps = mock_dependencies(&[]); cw2::set_contract_version(deps.as_mut().storage, "contract_xyz", "1.0.0").unwrap(); - let err = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap_err(); + let err = migrate(deps.as_mut(), mock_env(), MigrateMsg::V1_0_0ToV2_0_0 {}).unwrap_err(); assert_eq!( err, @@ -40,7 +40,7 @@ fn wrong_contract_version() { let mut deps = mock_dependencies(&[]); cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-red-bank", "4.1.0").unwrap(); - let err = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap_err(); + let err = migrate(deps.as_mut(), mock_env(), MigrateMsg::V1_0_0ToV2_0_0 {}).unwrap_err(); assert_eq!( err, @@ -101,19 +101,19 @@ fn full_migration() { .save(deps.as_mut().storage, (&Addr::unchecked("user_2"), "uatom"), &user_2_atom_collateral) .unwrap(); - let res = migrate(deps.as_mut(), mock_env(), Empty {}).unwrap(); + let res = migrate(deps.as_mut(), mock_env(), MigrateMsg::V1_0_0ToV2_0_0 {}).unwrap(); assert_eq!(res.messages, vec![]); assert_eq!(res.events, vec![] as Vec); assert!(res.data.is_none()); assert_eq!( res.attributes, - vec![attr("action", "migrate"), attr("from_version", "1.0.0"), attr("to_version", "2.0.0")] + vec![attr("action", "migrate"), attr("from_version", "1.0.0"), attr("to_version", "2.0.1")] ); let new_contract_version = ContractVersion { contract: "crates.io:mars-red-bank".to_string(), - version: "2.0.0".to_string(), + version: "2.0.1".to_string(), }; assert_eq!(cw2::get_contract_version(deps.as_ref().storage).unwrap(), new_contract_version); @@ -381,3 +381,25 @@ fn compare_markers(old_market: &v1_state::Market, market: &Market) -> bool { && old_market.collateral_total_scaled == market.collateral_total_scaled && old_market.debt_total_scaled == market.debt_total_scaled } + +#[test] +fn successful_migration_to_v2_0_1() { + let mut deps = mock_dependencies(&[]); + cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-red-bank", "2.0.0").unwrap(); + + let res = migrate(deps.as_mut(), mock_env(), MigrateMsg::V2_0_0ToV2_0_1 {}).unwrap(); + + assert_eq!(res.messages, vec![]); + assert_eq!(res.events, vec![] as Vec); + assert!(res.data.is_none()); + assert_eq!( + res.attributes, + vec![attr("action", "migrate"), attr("from_version", "2.0.0"), attr("to_version", "2.0.1")] + ); + + let new_contract_version = ContractVersion { + contract: "crates.io:mars-red-bank".to_string(), + version: "2.0.1".to_string(), + }; + assert_eq!(cw2::get_contract_version(deps.as_ref().storage).unwrap(), new_contract_version); +} diff --git a/packages/types/src/credit_manager/migrate.rs b/packages/types/src/credit_manager/migrate.rs index 3abd3a753..670742290 100644 --- a/packages/types/src/credit_manager/migrate.rs +++ b/packages/types/src/credit_manager/migrate.rs @@ -18,5 +18,5 @@ pub struct V2Updates { #[cw_serde] pub enum MigrateMsg { V1_0_0ToV2_0_0(V2Updates), - V2_0_1ToV2_0_2 {}, + V2_0_2ToV2_0_3 {}, } diff --git a/packages/types/src/red_bank/msg.rs b/packages/types/src/red_bank/msg.rs index 9ef10bbfb..be8ba0aac 100644 --- a/packages/types/src/red_bank/msg.rs +++ b/packages/types/src/red_bank/msg.rs @@ -268,3 +268,9 @@ pub enum QueryMsg { amount_scaled: Uint128, }, } + +#[cw_serde] +pub enum MigrateMsg { + V1_0_0ToV2_0_0 {}, + V2_0_0ToV2_0_1 {}, +} diff --git a/schemas/mars-credit-manager/mars-credit-manager.json b/schemas/mars-credit-manager/mars-credit-manager.json index 8fcaac976..22aa2d85f 100644 --- a/schemas/mars-credit-manager/mars-credit-manager.json +++ b/schemas/mars-credit-manager/mars-credit-manager.json @@ -1,6 +1,6 @@ { "contract_name": "mars-credit-manager", - "contract_version": "2.0.2", + "contract_version": "2.0.3", "idl_version": "1.0.0", "instantiate": { "$schema": "http://json-schema.org/draft-07/schema#", diff --git a/schemas/mars-red-bank/mars-red-bank.json b/schemas/mars-red-bank/mars-red-bank.json index 5f43ecc87..97faad451 100644 --- a/schemas/mars-red-bank/mars-red-bank.json +++ b/schemas/mars-red-bank/mars-red-bank.json @@ -1,6 +1,6 @@ { "contract_name": "mars-red-bank", - "contract_version": "2.0.0", + "contract_version": "2.0.1", "idl_version": "1.0.0", "instantiate": { "$schema": "http://json-schema.org/draft-07/schema#",