use crate::contract::{execute, instantiate, query};
use crate::testing::mock_querier::mock_dependencies;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{
from_json, to_json_binary, CosmosMsg, Decimal256, SubMsg, Uint128, Uint256, WasmMsg,
};
use cw20::Cw20ExecuteMsg;
use cw20::Cw20ReceiveMsg;
use solid_moneymarket::liquidation::MarketExecuteMsg;
use solid_moneymarket::liquidation_queue::{
Cw20HookMsg, ExecuteMsg, InstantiateMsg, LiquidationAmountResponse, QueryMsg,
};
#[test]
fn partial_one_collateral_one_slot_high_ltv() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(90))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 0u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(19000u64),
borrow_limit: Uint256::from(18000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))], collateral_prices: vec![Decimal256::percent(100)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(16429u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(100),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(16433u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(16433u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_one_collateral_one_slot() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(7273u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(7291u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(692u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_one_collateral_one_slot_with_fees() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(7401u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(7551u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(710u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(7u128),
})
.unwrap(),
}))
]
);
}
#[test]
fn partial_one_collateral_one_slot_with_fees_all() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(1),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(7532u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(7686u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(716u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(7u128),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "liquidator00000".to_string(),
amount: Uint128::from(7u128),
})
.unwrap(),
}))
]
);
}
#[test]
fn partial_one_collateral_two_slots() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(10300u64),
borrow_limit: Uint256::from(10000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(200000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(42841u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(42860u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(4015u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),]
);
}
#[test]
fn partial_one_collateral_two_slots_with_fees() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(10300u64),
borrow_limit: Uint256::from(10000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(200000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(43626u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(44453u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(4117u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(41u128),
})
.unwrap(),
})),
]
);
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(4117u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(41u128),
})
.unwrap(),
})),
]
);
}
#[test]
fn non_partial_liquidation() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::from(1000000u128),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
let info = mock_info("stable0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(12632u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(12643u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1201u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn non_partial_liquidation_two_slots() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::from(1000000u128),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(12745u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(12756u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1200u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn non_partial_liquidation_with_fees() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::from(1000000u128),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(12760u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(12899u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1213u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap()
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(12u128),
})
.unwrap(),
}))
]
);
}
#[test]
fn non_partial_liquidation_two_slots_with_fees() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::from(1000000u128),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200u64),
borrow_limit: Uint256::from(1000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000u64))],
collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(12874u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(13015u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1212u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(12u128),
})
.unwrap(),
}))
]
);
}
#[test]
fn non_partial_liquidation_two_slots_with_fees_big_nums() {
let mut deps = mock_dependencies(&[]);
deps.querier
.with_collateral_max_ltv(&[(&"token0000".to_string(), &Decimal256::percent(50))]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::from(2000000000u128),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1500000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1500000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1300000000u64),
borrow_limit: Uint256::from(1000000000u64),
collaterals: vec![("token0000".to_string(), Uint256::from(20000000000u64))], collateral_prices: vec![Decimal256::percent(10)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(13822434876u64))],
}
);
let info = mock_info("token0000", &[]);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(13833067518u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1301000000u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(13141414u128),
})
.unwrap(),
}))
]
);
}
#[test]
fn partial_two_collaterals_ltv_diff() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(99)),
(&"token0001".to_string(), &Decimal256::percent(1)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 0u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 0u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200000000u64),
borrow_limit: Uint256::from(1000000000u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(1000000000u64)), ("token0001".to_string(), Uint256::from(1000000000u64)), ],
collateral_prices: vec![Decimal256::percent(100), Decimal256::percent(100)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(19230770u64)),
("token0001".to_string(), Uint256::from(399193549u64))
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(100),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(100),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(19230775u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(19230775u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(399193550u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(399193550u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_two_collaterals_multi_slots_per_col() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(280u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(280u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 11u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(280u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 3u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(280u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1700u64),
borrow_limit: Uint256::from(1450u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(20000u64)), ("token0001".to_string(), Uint256::from(30000u64)), ],
collateral_prices: vec![Decimal256::percent(10), Decimal256::percent(5)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(3776u64)),
("token0001".to_string(), Uint256::from(9607u64))
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(5),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(3796u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(355u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(9637u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(453u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_two_collaterals_one_slot_diff_ltv() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1600u64),
borrow_limit: Uint256::from(1450u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(20000u64)), ("token0001".to_string(), Uint256::from(30000u64)), ],
collateral_prices: vec![Decimal256::percent(10), Decimal256::percent(5)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(3019u64)),
("token0001".to_string(), Uint256::from(7747u64))
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(5),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(3037u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(288u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(7775u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(369u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_three_collaterals_one_slot_diff_ltv() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(70)),
(&"token0002".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0002".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(1000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(100000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(100000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(100000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0002".to_string(),
premium_slot: 1u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(4500u64),
borrow_limit: Uint256::from(4030u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(20000u64)), ("token0001".to_string(), Uint256::from(30000u64)), ("token0002".to_string(), Uint256::from(6000u64)), ],
collateral_prices: vec![
Decimal256::percent(10),
Decimal256::percent(5),
Decimal256::percent(110),
],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(3310u64)),
("token0001".to_string(), Uint256::from(5765u64)),
("token0002".to_string(), Uint256::from(1209u64)),
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(5),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0002".to_string(), "uusd".to_string()),
&(
Decimal256::percent(110),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(3328u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(316u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(5824u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(262u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(1210u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0002", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1317u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_three_collaterals_one_slot_diff_ltv_big_amounts() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(40)),
(&"token0002".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0002".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(1000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0002".to_string(),
premium_slot: 1u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(1200000000000u64),
borrow_limit: Uint256::from(1007980000000u128),
collaterals: vec![
("token0000".to_string(), Uint256::from(200000000000u64)), ("token0001".to_string(), Uint256::from(3000000000u64)), ("token0002".to_string(), Uint256::from(60000000u64)), ],
collateral_prices: vec![
Decimal256::percent(1000),
Decimal256::percent(500),
Decimal256::percent(11000),
],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(69498951644u64)),
("token0001".to_string(), Uint256::from(2471406686u64)),
("token0002".to_string(), Uint256::from(50965898u64)),
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(1000),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(500),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0002".to_string(), "uusd".to_string()),
&(
Decimal256::percent(11000),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(69498951644u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(660240040618u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(2471406687u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(11121330091u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(50965898u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0002", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(5550186292u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn partial_three_collaterals_one_slot_diff_ltv_big_amounts_2() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(40)),
(&"token0002".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0002".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0002".to_string(),
premium_slot: 1u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(9100000000u64),
borrow_limit: Uint256::from(8980000000u128),
collaterals: vec![
("token0000".to_string(), Uint256::from(200000000u64)), ("token0001".to_string(), Uint256::from(3000000000u64)), ("token0002".to_string(), Uint256::from(60000000u64)), ],
collateral_prices: vec![
Decimal256::percent(1000),
Decimal256::percent(500),
Decimal256::percent(11000),
],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(21944167u64)),
("token0001".to_string(), Uint256::from(390171057u64)),
("token0002".to_string(), Uint256::from(8046195u64)),
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(1000),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(500),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0002".to_string(), "uusd".to_string()),
&(
Decimal256::percent(11000),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(23089478u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(219350041u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(390171057u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1755769756u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(8046195u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0002", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(876230635u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}
#[test]
fn not_enough_bids_for_one_of_two_col() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(50)),
(&"token0001".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(1),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0001".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(10000u128), premium_rate_per_slot: Decimal256::percent(1),
};
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(10000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 5u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(400000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0001".to_string(),
premium_slot: 10u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(2800000u64),
borrow_limit: Uint256::from(2450000u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(20000000u64)), ("token0001".to_string(), Uint256::from(30000000u64)), ],
collateral_prices: vec![Decimal256::percent(10), Decimal256::percent(5)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![
("token0000".to_string(), Uint256::from(11655875u64)),
("token0001".to_string(), Uint256::from(6451613u64))
],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[
(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(10),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
(
&("token0001".to_string(), "uusd".to_string()),
&(
Decimal256::percent(5),
env.block.time.seconds(),
env.block.time.seconds(),
),
),
]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(11862304u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(1115649u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(11269u128),
})
.unwrap()
}))
]
);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(6541171u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0001", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(291409u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
})),
SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Transfer {
recipient: "fee0000".to_string(),
amount: Uint128::from(2943u128),
})
.unwrap()
}))
]
);
}
#[test]
fn integration_test_simul() {
let mut deps = mock_dependencies(&[]);
deps.querier.with_collateral_max_ltv(&[
(&"token0000".to_string(), &Decimal256::percent(60)),
(&"token0001".to_string(), &Decimal256::percent(30)),
]);
let msg = InstantiateMsg {
owner: "owner0000".to_string(),
oracle_contract: "oracle0000".to_string(),
stable_contract: "stable0000".to_string(),
safe_ratio: Decimal256::percent(80),
bid_fee: Decimal256::percent(0),
liquidator_fee: Decimal256::percent(0),
liquidation_threshold: Uint256::zero(),
price_timeframe: 60u64,
waiting_period: 60u64,
overseer: "overseer0000".to_string(),
};
let info = mock_info("addr0000", &[]);
let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = ExecuteMsg::WhitelistCollateral {
collateral_token: "token0000".to_string(),
max_slot: 30u8,
bid_threshold: Uint256::from(100000000000000000000u128), premium_rate_per_slot: Decimal256::percent(1),
};
let info = mock_info("owner0000", &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
for slot in 1..30 {
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(300u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: slot as u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
}
let info = mock_info("stable0000", &[]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "addr0000".to_string(),
amount: Uint128::from(3000000000000u128),
msg: to_json_binary(&Cw20HookMsg::SubmitBid {
collateral_token: "token0000".to_string(),
premium_slot: 30u8,
})
.unwrap(),
});
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
let msg = QueryMsg::LiquidationAmount {
borrow_amount: Uint256::from(6000000000u64),
borrow_limit: Uint256::from(5400000000u64),
collaterals: vec![
("token0000".to_string(), Uint256::from(10000000000u64)), ],
collateral_prices: vec![Decimal256::percent(90)],
};
let res = query(deps.as_ref(), mock_env(), msg).unwrap();
let res: LiquidationAmountResponse = from_json(&res).unwrap();
assert_eq!(
res,
LiquidationAmountResponse {
collaterals: vec![("token0000".to_string(), Uint256::from(8484841036u64)),],
}
);
let env = mock_env();
deps.querier.with_oracle_price(&[(
&("token0000".to_string(), "uusd".to_string()),
&(
Decimal256::percent(90),
env.block.time.seconds(),
env.block.time.seconds(),
),
)]);
let msg = ExecuteMsg::Receive(Cw20ReceiveMsg {
sender: "custody0000".to_string(),
amount: Uint128::from(8489891541u64),
msg: to_json_binary(&Cw20HookMsg::ExecuteBid {
liquidator: "liquidator00000".to_string(),
fee_address: Some("fee0000".to_string()),
repay_address: Some("repay0000".to_string()),
borrower_address: Some("addr0000".to_string()),
})
.unwrap(),
});
let info = mock_info("token0000", &[]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
res.messages,
vec![SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: "stable0000".to_string(),
funds: vec![],
msg: to_json_binary(&Cw20ExecuteMsg::Send {
contract: "repay0000".to_string(),
amount: Uint128::from(5348633145u128),
msg: to_json_binary(&MarketExecuteMsg::RepayStableFromLiquidation {
borrower: "addr0000".to_string()
})
.unwrap(),
})
.unwrap(),
}))]
);
}