diff --git a/contracts/suilend/Move.lock b/contracts/suilend/Move.lock
index 7bca1f3..d397ba8 100644
--- a/contracts/suilend/Move.lock
+++ b/contracts/suilend/Move.lock
@@ -1,44 +1,44 @@
# @generated by Move, please check-in and do not edit manually.
[move]
-version = 2
+version = 3
manifest_digest = "97E92C3AE2671D15B98EDF2F75D00F01F060C660AA87BCA5FB95A6792D62C242"
deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600"
dependencies = [
- { name = "Pyth" },
- { name = "Sui" },
+ { id = "Pyth", name = "Pyth" },
+ { id = "Sui", name = "Sui" },
]
[[move.package]]
-name = "MoveStdlib"
+id = "MoveStdlib"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/mainnet", subdir = "crates/sui-framework/packages/move-stdlib" }
[[move.package]]
-name = "Pyth"
+id = "Pyth"
source = { git = "https://github.com/solendprotocol/pyth-crosschain.git", rev = "98e218c64bb75cf1350eb7b021e1ffcc3aedfd62", subdir = "target_chains/sui/contracts" }
dependencies = [
- { name = "Sui" },
- { name = "Wormhole" },
+ { id = "Sui", name = "Sui" },
+ { id = "Wormhole", name = "Wormhole" },
]
[[move.package]]
-name = "Sui"
+id = "Sui"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/mainnet", subdir = "crates/sui-framework/packages/sui-framework" }
dependencies = [
- { name = "MoveStdlib" },
+ { id = "MoveStdlib", name = "MoveStdlib" },
]
[[move.package]]
-name = "Wormhole"
+id = "Wormhole"
source = { git = "https://github.com/solendprotocol/wormhole.git", rev = "e1698d3c72b15cdddd7da98ad43e151f83b72a0a", subdir = "sui/wormhole" }
dependencies = [
- { name = "Sui" },
+ { id = "Sui", name = "Sui" },
]
[move.toolchain-version]
-compiler-version = "1.34.1"
+compiler-version = "1.35.3"
edition = "2024.beta"
flavor = "sui"
diff --git a/contracts/suilend/sources/lending_market.move b/contracts/suilend/sources/lending_market.move
index c21531e..875ec74 100644
--- a/contracts/suilend/sources/lending_market.move
+++ b/contracts/suilend/sources/lending_market.move
@@ -769,6 +769,15 @@ module suilend::lending_market {
object_table::borrow(&lending_market.obligations, obligation_id)
}
+ public fun fee_receiver
(lending_market: &LendingMarket
): address {
+ lending_market.fee_receiver
+ }
+
+ public use fun rate_limiter_exemption_amount as RateLimiterExemption.amount;
+ public fun rate_limiter_exemption_amount
(exemption: &RateLimiterExemption
): u64 {
+ exemption.amount
+ }
+
// === Admin Functions ===
entry fun migrate
(
_: &LendingMarketOwnerCap
,
@@ -1071,1606 +1080,4 @@ module suilend::lending_market {
let LendingMarketOwnerCap { id, lending_market_id: _ } = lending_market_owner_cap;
object::delete(id);
}
-
- #[test_only]
- use sui::test_scenario::{Self, Scenario};
-
- #[test]
- fun test_create_lending_market() {
- use sui::test_scenario::{Self};
- use sui::test_utils::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
-
- let (owner_cap, lending_market) = create_lending_market(
- test_scenario::ctx(&mut scenario)
- );
-
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_scenario::end(scenario);
- }
-
- #[test_only]
- use suilend::mock_pyth::{PriceState};
-
- #[test_only]
- public struct State {
- clock: Clock,
- owner_cap: LendingMarketOwnerCap,
- lending_market: LendingMarket,
- prices: PriceState,
- type_to_index: Bag
- }
-
- #[test_only]
- public struct ReserveArgs has store {
- config: ReserveConfig,
- initial_deposit: u64
- }
-
- #[test]
- #[expected_failure(abort_code = EDuplicateReserve)]
- fun duplicate_reserves() {
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::reserve_config::{Self};
- use sui::test_utils::{Self};
- use suilend::mock_pyth::{Self};
- use suilend::mock_metadata::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
-
- let clock = clock::create_for_testing(test_scenario::ctx(&mut scenario));
- let metadata = mock_metadata::init_metadata(test_scenario::ctx(&mut scenario));
-
- let (owner_cap, mut lending_market) = create_lending_market(
- test_scenario::ctx(&mut scenario)
- );
-
- let mut prices = mock_pyth::init_state(test_scenario::ctx(&mut scenario));
- mock_pyth::register(&mut prices, test_scenario::ctx(&mut scenario));
- mock_pyth::register(&mut prices, test_scenario::ctx(&mut scenario));
-
- add_reserve(
- &owner_cap,
- &mut lending_market,
- mock_pyth::get_price_obj(&prices),
- reserve_config::default_reserve_config(),
- mock_metadata::get(&metadata),
- &clock,
- test_scenario::ctx(&mut scenario)
- );
-
- add_reserve(
- &owner_cap,
- &mut lending_market,
- mock_pyth::get_price_obj(&prices),
- reserve_config::default_reserve_config(),
- mock_metadata::get(&metadata),
- &clock,
- test_scenario::ctx(&mut scenario)
- );
-
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(metadata);
- test_scenario::end(scenario);
- }
-
- #[test_only]
- fun setup(mut reserve_args: Bag, scenario: &mut Scenario): State {
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::reserve_config::{Self};
- use sui::test_utils::{Self};
- use suilend::mock_pyth::{Self};
- use suilend::mock_metadata::{Self};
- use std::type_name::{Self};
-
-
- let clock = clock::create_for_testing(test_scenario::ctx(scenario));
- let metadata = mock_metadata::init_metadata(test_scenario::ctx(scenario));
-
- let (owner_cap, mut lending_market) = create_lending_market(
- test_scenario::ctx(scenario)
- );
-
- let mut prices = mock_pyth::init_state(test_scenario::ctx(scenario));
- mock_pyth::register(&mut prices, test_scenario::ctx(scenario));
- mock_pyth::register(&mut prices, test_scenario::ctx(scenario));
-
- let mut type_to_index = bag::new(test_scenario::ctx(scenario));
- bag::add(&mut type_to_index, type_name::get(), 0);
- bag::add(&mut type_to_index, type_name::get(), 1);
-
- add_reserve(
- &owner_cap,
- &mut lending_market,
- mock_pyth::get_price_obj(&prices),
- reserve_config::default_reserve_config(),
- mock_metadata::get(&metadata),
- &clock,
- test_scenario::ctx(scenario)
- );
-
- add_reserve(
- &owner_cap,
- &mut lending_market,
- mock_pyth::get_price_obj(&prices),
- reserve_config::default_reserve_config(),
- mock_metadata::get(&metadata),
- &clock,
- test_scenario::ctx(scenario)
- );
-
- if (bag::contains(&reserve_args, type_name::get())) {
- let ReserveArgs { config, initial_deposit } = bag::remove(
- &mut reserve_args,
- type_name::get()
- );
- let coins = coin::mint_for_testing(
- initial_deposit,
- test_scenario::ctx(scenario)
- );
-
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- 0,
- &clock,
- coins,
- test_scenario::ctx(scenario)
- );
-
- update_reserve_config(
- &owner_cap,
- &mut lending_market,
- 0,
- config
- );
-
- test_utils::destroy(ctokens);
- };
- if (bag::contains(&reserve_args, type_name::get())) {
- let ReserveArgs { config, initial_deposit } = bag::remove(
- &mut reserve_args,
- type_name::get()
- );
- let coins = coin::mint_for_testing(
- initial_deposit,
- test_scenario::ctx(scenario)
- );
-
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- 1,
- &clock,
- coins,
- test_scenario::ctx(scenario)
- );
-
- update_reserve_config(
- &owner_cap,
- &mut lending_market,
- 1,
- config
- );
-
- test_utils::destroy(ctokens);
- };
-
- test_utils::destroy(reserve_args);
- test_utils::destroy(metadata);
-
- return State {
- clock,
- owner_cap,
- lending_market,
- prices,
- type_to_index
- }
- }
-
- #[test]
- public fun test_deposit() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use std::type_name::{Self};
- use suilend::reserve_config::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { clock, owner_cap, mut lending_market, prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
-
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&ctokens) == 100 * 1_000_000, 0);
-
- let usdc_reserve = reserve(&lending_market);
- assert!(reserve::available_amount(usdc_reserve) == 200 * 1_000_000, 0);
-
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- assert!(obligation::deposited_ctoken_amount(obligation) == 100 * 1_000_000, 0);
-
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test]
- public fun test_redeem() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use std::type_name::{Self};
- use suilend::reserve_config::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { clock, owner_cap, mut lending_market, prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&ctokens) == 100 * 1_000_000, 0);
-
- let usdc_reserve = reserve(&lending_market);
- let old_available_amount = reserve::available_amount(usdc_reserve);
-
- let tokens = redeem_ctokens_and_withdraw_liquidity(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- ctokens,
- option::none(),
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&tokens) == 100 * 1_000_000, 0);
-
- let usdc_reserve = reserve(&lending_market);
- let new_available_amount = reserve::available_amount(usdc_reserve);
- assert!(new_available_amount == old_available_amount - 100 * 1_000_000, 0);
-
- test_utils::destroy(tokens);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
-
- #[test]
- public fun test_borrow_and_repay() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = reserve_config::default_reserve_config();
- let mut builder = reserve_config::from(
- &config,
- test_scenario::ctx(&mut scenario)
- );
-
- test_utils::destroy(config);
-
- reserve_config::set_borrow_fee_bps(&mut builder, 10);
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let mut sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 1 * 1_000_000_000,
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(coin::value(&sui) == 1 * 1_000_000_000, 0);
-
- // state checks
- let sui_reserve = reserve(&lending_market);
- assert!(reserve::borrowed_amount(sui_reserve) == decimal::from(1_001_000_000), 0);
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- assert!(obligation::borrowed_amount(obligation) == decimal::from(1_001_000_000), 0);
-
- repay(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- obligation_id(&obligation_owner_cap),
- &clock,
- &mut sui,
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(coin::value(&sui) == 0, 0);
- test_utils::destroy(sui);
-
- let sui_reserve = reserve(&lending_market);
- assert!(reserve::borrowed_amount(sui_reserve) == decimal::from(1_000_000), 0);
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- assert!(obligation::borrowed_amount(obligation) == decimal::from(1_000_000), 0);
-
- let mut sui = coin::mint_for_testing(1_000_000_000, test_scenario::ctx(&mut scenario));
- repay(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- obligation_id(&obligation_owner_cap),
- &clock,
- &mut sui,
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&sui) == 1_000_000_000 - 1_000_000, 0);
-
- let sui_reserve = reserve(&lending_market);
- assert!(reserve::borrowed_amount(sui_reserve) == decimal::from(0), 0);
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- assert!(obligation::borrowed_amount(obligation) == decimal::from(0), 0);
-
- test_scenario::next_tx(&mut scenario, owner);
-
- claim_fees(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- test_scenario::ctx(&mut scenario)
- );
-
- test_scenario::next_tx(&mut scenario, owner);
-
- let fees: Coin = test_scenario::take_from_address(&scenario, lending_market.fee_receiver);
- assert!(coin::value(&fees) == 1_000_000, 0);
-
- test_utils::destroy(fees);
-
- test_utils::destroy(sui);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test]
- public fun test_withdraw() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 2_500_000_000,
- test_scenario::ctx(&mut scenario)
- );
-
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- let old_deposited_amount = obligation::deposited_ctoken_amount(obligation);
-
- let usdc = withdraw_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 50 * 1_000_000,
- test_scenario::ctx(&mut scenario)
- );
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- let deposited_amount = obligation::deposited_ctoken_amount(obligation);
-
- assert!(coin::value(&usdc) == 50_000_000, 0);
- assert!(deposited_amount == old_deposited_amount - 50 * 1_000_000, 0);
-
- test_utils::destroy(sui);
- test_utils::destroy(usdc);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test]
- public fun test_liquidate() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
- use suilend::decimal::{sub};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 5 * 1_000_000_000,
- test_scenario::ctx(&mut scenario)
- );
- test_utils::destroy(sui);
-
- // set the open and close ltvs of the usdc reserve to 0
- let usdc_reserve = reserve(&lending_market);
- update_reserve_config(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- {
- let mut builder = reserve_config::from(
- reserve::config(usdc_reserve),
- test_scenario::ctx(&mut scenario)
- );
- reserve_config::set_open_ltv_pct(&mut builder, 0);
- reserve_config::set_close_ltv_pct(&mut builder, 0);
- reserve_config::set_max_close_ltv_pct(&mut builder, 0);
- reserve_config::set_liquidation_bonus_bps(&mut builder, 400);
- reserve_config::set_max_liquidation_bonus_bps(&mut builder, 400);
- reserve_config::set_protocol_liquidation_fee_bps(&mut builder, 600);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- }
- );
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
-
- let sui_reserve = reserve(&lending_market);
- let old_reserve_borrowed_amount = reserve::borrowed_amount(sui_reserve);
-
- let old_deposited_amount = obligation::deposited_ctoken_amount(obligation);
- let old_borrowed_amount = obligation::borrowed_amount(obligation);
-
- // liquidate the obligation
- let mut sui = coin::mint_for_testing(5 * 1_000_000_000, test_scenario::ctx(&mut scenario));
- let (usdc, exemption) = liquidate(
- &mut lending_market,
- obligation_id(&obligation_owner_cap),
- *bag::borrow(&type_to_index, type_name::get()),
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- &mut sui,
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(coin::value(&sui) == 4 * 1_000_000_000, 0);
- assert!(coin::value(&usdc) == 10 * 1_000_000 + 400_000, 0);
- assert!(exemption.amount == 10 * 1_000_000 + 400_000, 0);
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
-
- let sui_reserve = reserve(&lending_market);
- let reserve_borrowed_amount = reserve::borrowed_amount(sui_reserve);
-
- let deposited_amount = obligation::deposited_ctoken_amount(obligation);
- let borrowed_amount = obligation::borrowed_amount(obligation);
-
- assert!(reserve_borrowed_amount == sub(old_reserve_borrowed_amount, decimal::from(1_000_000_000)), 0);
- assert!(borrowed_amount == sub(old_borrowed_amount, decimal::from(1_000_000_000)), 0);
- assert!(deposited_amount == old_deposited_amount - 11 * 1_000_000, 0);
-
- // check to see if we can do a full redeem even with rate limiter is disabled
- update_rate_limiter_config(
- &owner_cap,
- &mut lending_market,
- &clock,
- rate_limiter::new_config(1, 0) // disabled
- );
-
- let tokens = redeem_ctokens_and_withdraw_liquidity(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- usdc,
- option::some(exemption),
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&tokens) == 10 * 1_000_000 + 400_000, 0);
-
- // claim fees
- test_scenario::next_tx(&mut scenario, owner);
- claim_fees(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- test_scenario::ctx(&mut scenario)
- );
-
- test_scenario::next_tx(&mut scenario, owner);
- let ctoken_fees: Coin> = test_scenario::take_from_address(
- &scenario,
- lending_market.fee_receiver
- );
- assert!(coin::value(&ctoken_fees) == 600_000, 0);
-
- test_utils::destroy(ctoken_fees);
- test_utils::destroy(sui);
- test_utils::destroy(tokens);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test_only]
- const MILLISECONDS_IN_DAY: u64 = 86_400_000;
-
- #[test]
- fun test_liquidity_mining() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::reserve_config::{Self, default_reserve_config};
- use suilend::mock_pyth::{Self};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
-
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- let usdc_rewards = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let sui_rewards = coin::mint_for_testing(100 * 1_000_000_000, test_scenario::ctx(&mut scenario));
-
- add_pool_reward(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- true,
- usdc_rewards,
- 0,
- 10 * MILLISECONDS_IN_DAY,
- &clock,
- test_scenario::ctx(&mut scenario)
- );
-
- add_pool_reward(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- true,
- sui_rewards,
- 4 * MILLISECONDS_IN_DAY,
- 14 * MILLISECONDS_IN_DAY,
- &clock,
- test_scenario::ctx(&mut scenario)
- );
-
- clock::set_for_testing(&mut clock, 1 * MILLISECONDS_IN_DAY);
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 1_000_000_000,
- test_scenario::ctx(&mut scenario)
- );
-
- clock::set_for_testing(&mut clock, 9 * MILLISECONDS_IN_DAY);
- let claimed_usdc = claim_rewards(
- &mut lending_market,
- &obligation_owner_cap,
- &clock,
- *bag::borrow(&type_to_index, type_name::get()),
- 0,
- true,
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&claimed_usdc) == 80 * 1_000_000, 0);
-
- // this fails because but rewards period is not over
- // claim_rewards_and_deposit(
- // &mut lending_market,
- // obligation_owner_cap.obligation_id,
- // &clock,
- // *bag::borrow(&type_to_index, type_name::get()),
- // 1,
- // true,
- // *bag::borrow(&type_to_index, type_name::get()),
- // test_scenario::ctx(&mut scenario)
- // );
-
- let remaining_sui_rewards = cancel_pool_reward(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- true,
- 1,
- &clock,
- test_scenario::ctx(&mut scenario)
- );
- assert!(coin::value(&remaining_sui_rewards) == 50 * 1_000_000_000, 0);
-
- claim_rewards_and_deposit(
- &mut lending_market,
- obligation_owner_cap.obligation_id,
- &clock,
- *bag::borrow(&type_to_index, type_name::get()),
- 1,
- true,
- *bag::borrow(&type_to_index, type_name::get()),
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(obligation::deposited_ctoken_amount(
- obligation(&lending_market, obligation_id(&obligation_owner_cap))
- ) == 49 * 1_000_000_000, 0);
- assert!(obligation::borrowed_amount(
- obligation(&lending_market, obligation_id(&obligation_owner_cap))
- ) == decimal::from(0), 0);
-
- let dust_sui_rewards = close_pool_reward(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- true,
- 1,
- &clock,
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(coin::value(&dust_sui_rewards) == 0, 0);
-
- test_utils::destroy(dust_sui_rewards);
- test_utils::destroy(remaining_sui_rewards);
- test_utils::destroy(sui);
- test_utils::destroy(owner_cap);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(claimed_usdc);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
-
- }
-
- #[test]
- public fun test_forgive_debt() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
- use suilend::decimal::{sub, eq};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: reserve_config::default_reserve_config(),
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 5 * 1_000_000_000,
- test_scenario::ctx(&mut scenario)
- );
- test_utils::destroy(sui);
-
- mock_pyth::update_price(&mut prices, 1, 2, &clock); // $10
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- // liquidate the obligation
- let mut sui = coin::mint_for_testing(1 * 1_000_000_000, test_scenario::ctx(&mut scenario));
- let (usdc, _exemption) = liquidate(
- &mut lending_market,
- obligation_id(&obligation_owner_cap),
- *bag::borrow(&type_to_index, type_name::get()),
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- &mut sui,
- test_scenario::ctx(&mut scenario)
- );
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- let sui_reserve = reserve(&lending_market);
- let old_reserve_borrowed_amount = reserve::borrowed_amount(sui_reserve);
- let old_borrowed_amount = obligation::borrowed_amount(obligation);
-
- forgive(
- &owner_cap,
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- obligation_id(&obligation_owner_cap),
- &clock,
- 1_000_000_000,
- );
-
- let obligation = obligation(&lending_market, obligation_id(&obligation_owner_cap));
- let sui_reserve = reserve(&lending_market);
- let reserve_borrowed_amount = reserve::borrowed_amount(sui_reserve);
- let borrowed_amount = obligation::borrowed_amount(obligation);
-
- assert!(eq(sub(old_borrowed_amount, borrowed_amount), decimal::from(1_000_000_000)), 0);
- assert!(eq(sub(old_reserve_borrowed_amount, reserve_borrowed_amount), decimal::from(1_000_000_000)), 0);
-
- test_utils::destroy(usdc);
- test_utils::destroy(sui);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test]
- public fun test_max_borrow() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = reserve_config::default_reserve_config();
- let mut builder = reserve_config::from(
- &config,
- test_scenario::ctx(&mut scenario)
- );
-
- test_utils::destroy(config);
-
- reserve_config::set_borrow_fee_bps(&mut builder, 10);
- // reserve_config::set_borrow_limit(&mut builder, 4 * 1_000_000_000);
- // reserve_config::set_borrow_limit_usd(&mut builder, 20);
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(100 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- U64_MAX,
- test_scenario::ctx(&mut scenario)
- );
-
- assert!(coin::value(&sui) == 4_995_004_995, 0);
-
- test_utils::destroy(sui);
- test_utils::destroy(obligation_owner_cap);
- test_utils::destroy(owner_cap);
- test_utils::destroy(lending_market);
- test_utils::destroy(clock);
- test_utils::destroy(prices);
- test_utils::destroy(type_to_index);
- test_scenario::end(scenario);
- }
-
- #[test]
- public fun test_max_withdraw() {
- use sui::test_utils::{Self};
- use suilend::test_usdc::{TEST_USDC};
- use suilend::test_sui::{TEST_SUI};
- use suilend::mock_pyth::{Self};
- use suilend::reserve_config::{Self, default_reserve_config};
-
- use std::type_name::{Self};
-
- let owner = @0x26;
- let mut scenario = test_scenario::begin(owner);
- let State { mut clock, owner_cap, mut lending_market, mut prices, type_to_index } = setup({
- let mut bag = bag::new(test_scenario::ctx(&mut scenario));
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_open_ltv_pct(&mut builder, 50);
- reserve_config::set_close_ltv_pct(&mut builder, 50);
- reserve_config::set_max_close_ltv_pct(&mut builder, 50);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000
- }
- );
- bag::add(
- &mut bag,
- type_name::get(),
- ReserveArgs {
- config: {
- let config = default_reserve_config();
- let mut builder = reserve_config::from(&config, test_scenario::ctx(&mut scenario));
- reserve_config::set_borrow_weight_bps(&mut builder, 20_000);
- sui::test_utils::destroy(config);
-
- reserve_config::build(builder, test_scenario::ctx(&mut scenario))
- },
- initial_deposit: 100 * 1_000_000_000
- }
- );
-
- bag
- }, &mut scenario);
-
- clock::set_for_testing(&mut clock, 1 * 1000);
-
- // set reserve parameters and prices
- mock_pyth::update_price(&mut prices, 1, 0, &clock); // $1
- mock_pyth::update_price(&mut prices, 1, 1, &clock); // $10
-
- // create obligation
- let obligation_owner_cap = create_obligation(
- &mut lending_market,
- test_scenario::ctx(&mut scenario)
- );
-
- let coins = coin::mint_for_testing(200 * 1_000_000, test_scenario::ctx(&mut scenario));
- let ctokens = deposit_liquidity_and_mint_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- coins,
- test_scenario::ctx(&mut scenario)
- );
-
- deposit_ctokens_into_obligation(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- ctokens,
- test_scenario::ctx(&mut scenario)
- );
-
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
- refresh_reserve_price(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &clock,
- mock_pyth::get_price_obj(&prices)
- );
-
- let sui = borrow(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- 2_500_000_000,
- test_scenario::ctx(&mut scenario)
- );
-
- update_rate_limiter_config(
- &owner_cap,
- &mut lending_market,
- &clock,
- rate_limiter::new_config(1, 10) // disabled
- );
-
- let cusdc = withdraw_ctokens(
- &mut lending_market,
- *bag::borrow(&type_to_index, type_name::get()),
- &obligation_owner_cap,
- &clock,
- U64_MAX,
- test_scenario::ctx(&mut scenario)
- );
- let usdc = redeem_ctokens_and_withdraw_liquidity