diff --git a/pool/src/auctions/auction.rs b/pool/src/auctions/auction.rs index 9b6c52dd..cb84b5e4 100644 --- a/pool/src/auctions/auction.rs +++ b/pool/src/auctions/auction.rs @@ -130,10 +130,7 @@ pub fn delete_liquidation(e: &Env, user: &Address) { storage::del_auction(e, &(AuctionType::UserLiquidation as u32), user); } -/// Fills the auction from the invoker. The filler is expected to maintain allowances to both -/// the pool and the backstop module. -/// -/// TODO: Use auth-next to avoid required allowances +/// Fills the auction from the invoker. /// /// ### Arguments /// * `pool` - The pool diff --git a/pool/src/auctions/backstop_interest_auction.rs b/pool/src/auctions/backstop_interest_auction.rs index 0cf837a0..dded3605 100644 --- a/pool/src/auctions/backstop_interest_auction.rs +++ b/pool/src/auctions/backstop_interest_auction.rs @@ -18,6 +18,7 @@ pub fn create_interest_auction_data( } let mut pool = Pool::load(e); + let oracle_scalar = 10i128.pow(pool.load_price_decimals(e)); let mut auction_data = AuctionData { lot: map![e], bid: map![e], @@ -48,13 +49,15 @@ pub fn create_interest_auction_data( panic_with_error!(e, PoolError::BadRequest); } - let usdc_token = storage::get_usdc_token(e); - let usdc_to_base = pool.load_price(e, &usdc_token); let backstop_client = BackstopClient::new(&e, &storage::get_backstop(e)); let pool_backstop_data = backstop_client.pool_data(&e.current_contract_address()); - let backstop_token_value_base = (pool_backstop_data.usdc * 5) - .fixed_div_floor(pool_backstop_data.tokens, usdc_to_base) - .unwrap_optimized(); + let backstop_token_value_base = (pool_backstop_data + .usdc + .fixed_mul_floor(oracle_scalar, SCALAR_7) + .unwrap_optimized() + * 5) + .fixed_div_floor(pool_backstop_data.tokens, SCALAR_7) + .unwrap_optimized(); let bid_amount = interest_value .fixed_mul_floor(1_4000000, SCALAR_7) .unwrap_optimized() @@ -396,6 +399,129 @@ mod tests { }); } + #[test] + fn test_create_interest_auction_14_decimal_oracle() { + let e = Env::default(); + e.mock_all_auths(); + e.budget().reset_unlimited(); // setup exhausts budget + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 10, + min_persistent_entry_ttl: 10, + max_entry_ttl: 2000000, + }); + + let bombadil = Address::generate(&e); + + let pool_address = create_pool(&e); + let (usdc_id, _) = testutils::create_usdc_token(&e, &pool_address, &bombadil); + let (blnd_id, _) = testutils::create_blnd_token(&e, &pool_address, &bombadil); + + let (backstop_token_id, _) = create_comet_lp_pool(&e, &bombadil, &blnd_id, &usdc_id); + let (backstop_address, backstop_client) = testutils::create_backstop(&e); + testutils::setup_backstop( + &e, + &pool_address, + &backstop_address, + &backstop_token_id, + &usdc_id, + &blnd_id, + ); + backstop_client.deposit(&bombadil, &pool_address, &(50 * SCALAR_7)); + backstop_client.update_tkn_val(); + let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); + + let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); + reserve_data_0.last_time = 12345; + reserve_data_0.backstop_credit = 100_0000000; + reserve_data_0.b_supply = 1000_0000000; + reserve_data_0.d_supply = 750_0000000; + reserve_config_0.index = 0; + testutils::create_reserve( + &e, + &pool_address, + &underlying_0, + &reserve_config_0, + &reserve_data_0, + ); + + let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_1, mut reserve_data_1) = testutils::default_reserve_meta(); + reserve_data_1.last_time = 12345; + reserve_data_1.backstop_credit = 25_0000000; + reserve_data_1.b_supply = 250_0000000; + reserve_data_1.d_supply = 187_5000000; + reserve_config_1.index = 1; + testutils::create_reserve( + &e, + &pool_address, + &underlying_1, + &reserve_config_1, + &reserve_data_1, + ); + + let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_2, mut reserve_data_2) = testutils::default_reserve_meta(); + reserve_data_2.last_time = 12345; + reserve_config_2.index = 1; + testutils::create_reserve( + &e, + &pool_address, + &underlying_2, + &reserve_config_2, + &reserve_data_2, + ); + + oracle_client.set_data( + &bombadil, + &Asset::Other(Symbol::new(&e, "USD")), + &vec![ + &e, + Asset::Stellar(underlying_0.clone()), + Asset::Stellar(underlying_1.clone()), + Asset::Stellar(underlying_2), + Asset::Stellar(usdc_id.clone()), + ], + &14, + &300, + ); + oracle_client.set_price_stable(&vec![ + &e, + 2_0000000_0000000, + 4_0000000_0000000, + 100_0000000_0000000, + 1_0000000_0000000, + ]); + + let pool_config = PoolConfig { + oracle: oracle_id, + bstop_rate: 0_1000000, + status: 0, + max_positions: 4, + }; + e.as_contract(&pool_address, || { + storage::set_pool_config(&e, &pool_config); + + let result = create_interest_auction_data( + &e, + &backstop_address, + &vec![&e, underlying_0.clone(), underlying_1.clone()], + ); + assert_eq!(result.block, 51); + assert_eq!(result.bid.get_unchecked(backstop_token_id), 336_0000000); + assert_eq!(result.bid.len(), 1); + assert_eq!(result.lot.get_unchecked(underlying_0), 100_0000000); + assert_eq!(result.lot.get_unchecked(underlying_1), 25_0000000); + assert_eq!(result.lot.len(), 2); + }); + } + #[test] fn test_create_interest_auction_applies_interest() { let e = Env::default(); diff --git a/pool/src/auctions/bad_debt_auction.rs b/pool/src/auctions/bad_debt_auction.rs index ed94e9e3..a050a558 100644 --- a/pool/src/auctions/bad_debt_auction.rs +++ b/pool/src/auctions/bad_debt_auction.rs @@ -23,6 +23,7 @@ pub fn create_bad_debt_auction_data(e: &Env, backstop: &Address) -> AuctionData }; let mut pool = Pool::load(e); + let oracle_scalar = 10i128.pow(pool.load_price_decimals(e)); let backstop_positions = storage::get_user_positions(e, backstop); let reserve_list = storage::get_res_list(e); let mut debt_value = 0; @@ -47,11 +48,10 @@ pub fn create_bad_debt_auction_data(e: &Env, backstop: &Address) -> AuctionData // TODO: Remove backstop_token getter call if WASM cache is not implemented let backstop_token = backstop_client.backstop_token(); let pool_backstop_data = backstop_client.pool_data(&e.current_contract_address()); - let usdc_token = storage::get_usdc_token(e); - let usdc_to_base = pool.load_price(e, &usdc_token); - let backstop_value_base = usdc_to_base - .fixed_mul_floor(pool_backstop_data.usdc, SCALAR_7) - .unwrap_optimized() + let backstop_value_base = pool_backstop_data + .usdc + .fixed_mul_floor(oracle_scalar, SCALAR_7) + .unwrap_optimized() // adjust for oracle scalar * 5; // Since the backstop LP token is an 80/20 split of USDC/BLND, we multiply by 5 to get the value of the BLND portion let backstop_token_to_base = backstop_value_base .fixed_div_floor(pool_backstop_data.tokens, SCALAR_7) @@ -338,6 +338,146 @@ mod tests { }); } + #[test] + fn test_create_bad_debt_auction_oracle_14_decimals() { + let e = Env::default(); + e.mock_all_auths_allowing_non_root_auth(); + e.budget().reset_unlimited(); // setup exhausts budget + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 10, + min_persistent_entry_ttl: 10, + max_entry_ttl: 2000000, + }); + + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let pool_address = create_pool(&e); + + let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); + let (usdc, usdc_client) = testutils::create_usdc_token(&e, &pool_address, &bombadil); + let (lp_token, lp_token_client) = + testutils::create_comet_lp_pool(&e, &bombadil, &blnd, &usdc); + let (backstop_address, backstop_client) = testutils::create_backstop(&e); + testutils::setup_backstop( + &e, + &pool_address, + &backstop_address, + &lp_token, + &usdc, + &blnd, + ); + // mint lp tokens + blnd_client.mint(&samwise, &500_001_0000000); + blnd_client.approve(&samwise, &lp_token, &i128::MAX, &99999); + usdc_client.mint(&samwise, &12_501_0000000); + usdc_client.approve(&samwise, &lp_token, &i128::MAX, &99999); + lp_token_client.join_pool( + &50_000_0000000, + &vec![&e, 500_001_0000000, 12_501_0000000], + &samwise, + ); + backstop_client.deposit(&samwise, &pool_address, &50_000_0000000); + backstop_client.update_tkn_val(); + + let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); + + let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); + reserve_data_0.d_rate = 1_100_000_000; + reserve_data_0.last_time = 12345; + reserve_config_0.index = 0; + testutils::create_reserve( + &e, + &pool_address, + &underlying_0, + &reserve_config_0, + &reserve_data_0, + ); + + let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_1, mut reserve_data_1) = testutils::default_reserve_meta(); + reserve_data_1.d_rate = 1_200_000_000; + reserve_data_1.last_time = 12345; + reserve_config_1.index = 1; + testutils::create_reserve( + &e, + &pool_address, + &underlying_1, + &reserve_config_1, + &reserve_data_1, + ); + + let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config_2, mut reserve_data_2) = testutils::default_reserve_meta(); + reserve_data_2.b_rate = 1_100_000_000; + reserve_data_2.last_time = 12345; + reserve_config_2.index = 1; + testutils::create_reserve( + &e, + &pool_address, + &underlying_2, + &reserve_config_2, + &reserve_data_2, + ); + + oracle_client.set_data( + &bombadil, + &Asset::Other(Symbol::new(&e, "USD")), + &vec![ + &e, + Asset::Stellar(underlying_0.clone()), + Asset::Stellar(underlying_1.clone()), + Asset::Stellar(underlying_2), + Asset::Stellar(usdc), + ], + &14, + &300, + ); + oracle_client.set_price_stable(&vec![ + &e, + 2_0000000_0000000, + 4_0000000_0000000, + 100_0000000_0000000, + 1_0000000_0000000, + ]); + + let positions: Positions = Positions { + collateral: map![&e], + liabilities: map![ + &e, + (reserve_config_0.index, 10_0000000), + (reserve_config_1.index, 2_5000000) + ], + supply: map![&e], + }; + + let pool_config = PoolConfig { + oracle: oracle_id, + bstop_rate: 0_1000000, + status: 0, + max_positions: 4, + }; + e.as_contract(&pool_address, || { + storage::set_pool_config(&e, &pool_config); + storage::set_user_positions(&e, &backstop_address, &positions); + + let result = create_bad_debt_auction_data(&e, &backstop_address); + + assert_eq!(result.block, 51); + assert_eq!(result.bid.get_unchecked(underlying_0), 10_0000000); + assert_eq!(result.bid.get_unchecked(underlying_1), 2_5000000); + assert_eq!(result.bid.len(), 2); + assert_eq!(result.lot.get_unchecked(lp_token), 38_0800000); + assert_eq!(result.lot.len(), 1); + }); + } + #[test] fn test_create_bad_debt_auction_max_balance() { let e = Env::default(); diff --git a/pool/src/auctions/user_liquidation_auction.rs b/pool/src/auctions/user_liquidation_auction.rs index 2c76ac45..7d68af67 100644 --- a/pool/src/auctions/user_liquidation_auction.rs +++ b/pool/src/auctions/user_liquidation_auction.rs @@ -9,7 +9,6 @@ use crate::{errors::PoolError, storage}; use super::AuctionType; -// TODO: Revalidate math with alternative decimal reserve pub fn create_user_liq_auction_data( e: &Env, user: &Address, diff --git a/test-suites/src/test_fixture.rs b/test-suites/src/test_fixture.rs index 8f92c449..1b596fb0 100644 --- a/test-suites/src/test_fixture.rs +++ b/test-suites/src/test_fixture.rs @@ -85,7 +85,7 @@ impl TestFixture<'_> { let (blnd_id, blnd_client) = create_stellar_token(&e, &bombadil); let (eth_id, eth_client) = create_token(&e, &bombadil, 9, "wETH"); let (usdc_id, usdc_client) = create_stellar_token(&e, &bombadil); - let (xlm_id, xlm_client) = create_stellar_token(&e, &bombadil); // TODO: make native + let (xlm_id, xlm_client) = create_stellar_token(&e, &bombadil); let (stable_id, stable_client) = create_token(&e, &bombadil, 6, "STABLE"); // deploy Blend Protocol contracts diff --git a/test-suites/tests/test_liquidation.rs b/test-suites/tests/test_liquidation.rs index ae22cc0c..6a27543b 100644 --- a/test-suites/tests/test_liquidation.rs +++ b/test-suites/tests/test_liquidation.rs @@ -313,7 +313,7 @@ fn test_liquidations() { frodo_stable_balance - usdc_bid_amount + stable_interest_lot_amount .fixed_div_floor(2 * 10i128.pow(6), 10i128.pow(6)) - .unwrap(), // - usdc_donate_bid_amount TODO: add donate diff when donating is implemented + .unwrap(), 10i128.pow(6), ); assert_approx_eq_abs(