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
2 changes: 1 addition & 1 deletion .github/workflows/scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
uses: davidB/rust-cargo-make@v1

- name: Install stable Rust
run: cd ../ && cargo make install-stable && cd scripts
run: cd ../ && cargo make install-stable-for-scripts && cd scripts

# selecting a toolchain should happen before the plugin, as the cache uses the current rustc version as its cache key
- name: Cache dependencies
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

4 changes: 4 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ rustup component add clippy --toolchain ${RUST_VERSION}
rustup component add llvm-tools-preview --toolchain ${RUST_VERSION}
'''

[tasks.install-stable-for-scripts]
env = { RUST_VERSION = "1.72.0" }
run_task = "install-stable"

[tasks.install-nightly]
script = '''
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain nightly
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.0.1"
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions contracts/credit-manager/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,6 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> ContractResult<Binary> {
pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> ContractResult<Response> {
match msg {
MigrateMsg::V1_0_0ToV2_0_0(updates) => migrations::v2_0_0::migrate(deps, env, updates),
MigrateMsg::V2_0_0ToV2_0_1 {} => migrations::v2_0_1::migrate(deps),
}
}
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_0_0;
pub mod v2_0_1;
21 changes: 21 additions & 0 deletions contracts/credit-manager/src/migrations/v2_0_1.rs
Original file line number Diff line number Diff line change
@@ -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<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)?;

Ok(Response::new()
.add_attribute("action", "migrate")
.add_attribute("from_version", FROM_VERSION)
.add_attribute("to_version", CONTRACT_VERSION))
}
11 changes: 8 additions & 3 deletions contracts/credit-manager/src/repay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ use mars_types::credit_manager::{ActionCoin, CallbackMsg::Repay, ExecuteMsg};

use crate::{
error::{ContractError, ContractResult},
state::{DEBT_SHARES, RED_BANK, TOTAL_DEBT_SHARES},
state::{COIN_BALANCES, DEBT_SHARES, RED_BANK, TOTAL_DEBT_SHARES},
utils::{debt_shares_to_amount, decrement_coin_balance, increment_coin_balance},
};

pub fn repay(deps: DepsMut, account_id: &str, coin: &ActionCoin) -> ContractResult<Response> {
// Ensure repayment does not exceed max debt on account
let (debt_amount, debt_shares) =
current_debt_for_denom(deps.as_ref(), account_id, &coin.denom)?;
let amount_to_repay = min(debt_amount, coin.amount.value().unwrap_or(Uint128::MAX));
let coin_balance =
COIN_BALANCES.may_load(deps.storage, (account_id, &coin.denom))?.unwrap_or_default();
let amount_to_repay = min(debt_amount, coin.amount.value().unwrap_or(coin_balance));
let coin_to_repay = Coin {
denom: coin.denom.to_string(),
amount: amount_to_repay,
Expand Down Expand Up @@ -86,7 +88,10 @@ pub fn repay_for_recipient(
) -> ContractResult<Response> {
let (debt_amount, _) =
current_debt_for_denom(deps.as_ref(), recipient_account_id, &coin.denom)?;
let amount_to_repay = min(debt_amount, coin.amount.value().unwrap_or(Uint128::MAX));
let coin_balance = COIN_BALANCES
.may_load(deps.storage, (benefactor_account_id, &coin.denom))?
.unwrap_or_default();
let amount_to_repay = min(debt_amount, coin.amount.value().unwrap_or(coin_balance));
let coin_to_repay = &Coin {
denom: coin.denom,
amount: amount_to_repay,
Expand Down
28 changes: 26 additions & 2 deletions contracts/credit-manager/tests/tests/test_migration_v2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use cosmwasm_std::{
attr,
testing::{mock_dependencies, mock_env},
Addr, Decimal,
Addr, Decimal, Event,
};
use cw2::VersionError;
use cw2::{ContractVersion, VersionError};
use mars_credit_manager::{
contract::migrate,
error::ContractError,
Expand Down Expand Up @@ -148,3 +149,26 @@ fn successful_migration() {
let set_red_bank = RED_BANK.load(deps.as_ref().storage).unwrap();
assert_eq!(old_red_bank, set_red_bank.addr.as_str());
}

#[test]
fn successful_migration_to_v2_0_1() {
let mut deps = mock_dependencies();
cw2::set_contract_version(deps.as_mut().storage, "crates.io:mars-credit-manager", "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<Event>);
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-credit-manager".to_string(),
version: "2.0.1".to_string(),
};
assert_eq!(cw2::get_contract_version(deps.as_ref().storage).unwrap(), new_contract_version);
}
53 changes: 53 additions & 0 deletions contracts/credit-manager/tests/tests/test_repay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use mars_types::{
use super::helpers::{
assert_err, uosmo_info, AccountToFund, CoinInfo, MockEnv, DEFAULT_RED_BANK_COIN_BALANCE,
};
use crate::tests::helpers::{get_coin, get_debt, uatom_info};

#[test]
fn only_token_owner_can_repay() {
Expand Down Expand Up @@ -389,3 +390,55 @@ fn amount_none_repays_total_debt() {
let coin = mock.query_balance(&Addr::unchecked(config.red_bank), &coin_info.denom);
assert_eq!(coin.amount, DEFAULT_RED_BANK_COIN_BALANCE.add(Uint128::new(1)));
}

#[test]
fn amount_none_repays_no_more_than_available_asset() {
let uosmo_info = uosmo_info();
let uatom_info = uatom_info();

let user = Addr::unchecked("user");

let mut mock = MockEnv::new()
.set_params(&[uosmo_info.clone(), uatom_info.clone()])
.fund_account(AccountToFund {
addr: user.clone(),
funds: coins(300, uatom_info.denom.clone()),
})
.build()
.unwrap();

let account_id = mock.create_credit_account(&user).unwrap();

mock.update_credit_account(
&account_id,
&user,
vec![
Deposit(uatom_info.to_coin(300)),
Borrow(uosmo_info.to_coin(50)),
Withdraw(uosmo_info.to_action_coin(10)),
Repay {
recipient_account_id: None,
coin: uosmo_info.to_action_coin_full_balance(),
},
],
&[uatom_info.to_coin(300)],
)
.unwrap();

let position = mock.query_positions(&account_id);
assert_eq!(position.debts.len(), 1);
let uosmo_debt = get_debt(&uosmo_info.denom, &position.debts);
// debt: 50 uosmo,
// account balance: 40 uosmo (50 borrowed - 10 withdrawn)
// repaying full balance should repay 40 uosmo
assert_eq!(uosmo_debt.amount, Uint128::new(11)); // 10 + 1 interest

assert_eq!(position.deposits.len(), 1);
assert_eq!(get_coin(&uatom_info.denom, &position.deposits), uatom_info.to_coin(300));

let coin = mock.query_balance(&mock.rover, &uatom_info.denom);
assert_eq!(coin.amount, Uint128::new(300));

let coin = mock.query_balance(&mock.rover, &uosmo_info.denom);
assert_eq!(coin.amount, Uint128::zero());
}
65 changes: 64 additions & 1 deletion contracts/credit-manager/tests/tests/test_repay_for_recipient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use mars_types::credit_manager::{
};

use super::helpers::{
assert_err, uosmo_info, AccountToFund, MockEnv, DEFAULT_RED_BANK_COIN_BALANCE,
assert_err, uatom_info, uosmo_info, AccountToFund, MockEnv, DEFAULT_RED_BANK_COIN_BALANCE,
};
use crate::tests::helpers::{get_coin, get_debt};

#[test]
fn only_rover_can_call_repay_for_recipient_callback() {
Expand Down Expand Up @@ -392,3 +393,65 @@ fn benefactor_attempts_to_pay_more_than_max_debt() {
let coin = mock.query_balance(&Addr::unchecked(config.red_bank), &coin_info.denom);
assert_eq!(coin.amount, DEFAULT_RED_BANK_COIN_BALANCE.add(Uint128::new(1)));
}

#[test]
fn amount_none_repays_no_more_than_available_asset() {
let uosmo_info = uosmo_info();
let uatom_info = uatom_info();

let recipient = Addr::unchecked("recipient");
let benefactor = Addr::unchecked("benefactor");

let mut mock = MockEnv::new()
.set_params(&[uosmo_info.clone(), uatom_info.clone()])
.fund_account(AccountToFund {
addr: benefactor.clone(),
funds: coins(300, uosmo_info.denom.clone()),
})
.fund_account(AccountToFund {
addr: recipient.clone(),
funds: coins(300, uatom_info.denom.clone()),
})
.build()
.unwrap();

let recipient_account_id = mock.create_credit_account(&recipient).unwrap();
let benefactor_account_id = mock.create_credit_account(&benefactor).unwrap();

mock.update_credit_account(
&recipient_account_id,
&recipient,
vec![Deposit(uatom_info.to_coin(300)), Borrow(uosmo_info.to_coin(60))],
&[coin(300, uatom_info.denom.clone())],
)
.unwrap();

mock.update_credit_account(
&benefactor_account_id,
&benefactor,
vec![
Deposit(uosmo_info.to_coin(50)),
Repay {
recipient_account_id: Some(recipient_account_id.clone()),
coin: uosmo_info.to_action_coin_full_balance(),
},
],
&[coin(50, uosmo_info.denom.clone())],
)
.unwrap();

let recipient_position = mock.query_positions(&recipient_account_id.clone());
assert_eq!(recipient_position.deposits.len(), 2);
assert_eq!(get_coin(&uatom_info.denom, &recipient_position.deposits), uatom_info.to_coin(300));
assert_eq!(get_coin(&uosmo_info.denom, &recipient_position.deposits), uosmo_info.to_coin(60));
assert_eq!(recipient_position.debts.len(), 1);
let uosmo_debt = get_debt(&uosmo_info.denom, &recipient_position.debts);
// recipient debt: 60 uosmo,
// benefactor account balance: 50 uosmo
// repaying with benefactor full balance, should repay 50 uosmo
assert_eq!(uosmo_debt.amount, Uint128::new(11)); // 10 + 1 interest

let benefactor_position = mock.query_positions(&benefactor_account_id.clone());
assert_eq!(benefactor_position.deposits.len(), 0);
assert_eq!(benefactor_position.debts.len(), 0);
}
1 change: 1 addition & 0 deletions packages/types/src/credit_manager/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ pub struct V2Updates {
#[cw_serde]
pub enum MigrateMsg {
V1_0_0ToV2_0_0(V2Updates),
V2_0_0ToV2_0_1 {},
}
2 changes: 1 addition & 1 deletion schemas/mars-credit-manager/mars-credit-manager.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"contract_name": "mars-credit-manager",
"contract_version": "2.0.0",
"contract_version": "2.0.1",
"idl_version": "1.0.0",
"instantiate": {
"$schema": "http://json-schema.org/draft-07/schema#",
Expand Down