diff --git a/pool/src/auctions/auction.rs b/pool/src/auctions/auction.rs index 9213817..9760eef 100644 --- a/pool/src/auctions/auction.rs +++ b/pool/src/auctions/auction.rs @@ -5,10 +5,8 @@ use crate::{ storage, }; use cast::i128; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{ - contracttype, map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Map, Vec, -}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::{contracttype, map, panic_with_error, Address, Env, Map, Vec}; use super::{ backstop_interest_auction::{create_interest_auction_data, fill_interest_auction}, @@ -213,17 +211,13 @@ fn scale_auction( for (asset, amount) in auction_data.bid.iter() { // apply percent scalar and store remainder to base auction // round up to avoid rounding exploits - let to_fill_base = amount - .fixed_mul_ceil(percent_filled_i128, SCALAR_7) - .unwrap_optimized(); + let to_fill_base = amount.fixed_mul_ceil(e, &percent_filled_i128, &SCALAR_7); let remaining_base = amount - to_fill_base; if remaining_base > 0 { remaining_auction.bid.set(asset.clone(), remaining_base); } // apply block scalar to to_fill auction and don't store if 0 - let to_fill_scaled = to_fill_base - .fixed_mul_ceil(bid_modifier, SCALAR_7) - .unwrap_optimized(); + let to_fill_scaled = to_fill_base.fixed_mul_ceil(e, &bid_modifier, &SCALAR_7); if to_fill_scaled > 0 { to_fill_auction.bid.set(asset, to_fill_scaled); } @@ -231,17 +225,13 @@ fn scale_auction( for (asset, amount) in auction_data.lot.iter() { // apply percent scalar and store remainder to base auction // round down to avoid rounding exploits - let to_fill_base = amount - .fixed_mul_floor(percent_filled_i128, SCALAR_7) - .unwrap_optimized(); + let to_fill_base = amount.fixed_mul_floor(e, &percent_filled_i128, &SCALAR_7); let remaining_base = amount - to_fill_base; if remaining_base > 0 { remaining_auction.lot.set(asset.clone(), remaining_base); } // apply block scalar to to_fill auction and don't store if 0 - let to_fill_scaled = to_fill_base - .fixed_mul_floor(lot_modifier, SCALAR_7) - .unwrap_optimized(); + let to_fill_scaled = to_fill_base.fixed_mul_floor(e, &lot_modifier, &SCALAR_7); if to_fill_scaled > 0 { to_fill_auction.lot.set(asset, to_fill_scaled); } @@ -267,6 +257,7 @@ mod tests { use soroban_sdk::{ map, testutils::{Address as _, Ledger, LedgerInfo}, + unwrap::UnwrapOptimized, vec, Symbol, }; @@ -314,7 +305,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -327,7 +318,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -340,7 +331,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -467,7 +458,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -541,7 +532,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -555,7 +546,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -654,7 +645,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -668,7 +659,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -766,7 +757,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -780,7 +771,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; diff --git a/pool/src/auctions/backstop_interest_auction.rs b/pool/src/auctions/backstop_interest_auction.rs index d77519c..dc21c33 100644 --- a/pool/src/auctions/backstop_interest_auction.rs +++ b/pool/src/auctions/backstop_interest_auction.rs @@ -3,8 +3,8 @@ use crate::{ }; use cast::i128; use sep_41_token::TokenClient; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Vec}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::{map, panic_with_error, Address, Env, Vec}; use super::{AuctionData, AuctionType}; @@ -45,9 +45,11 @@ pub fn create_interest_auction_data( let reserve = pool.load_reserve(e, &lot_asset, false); if reserve.data.backstop_credit > 0 { let asset_to_base = pool.load_price(e, &reserve.asset); - interest_value += i128(asset_to_base) - .fixed_mul_floor(reserve.data.backstop_credit, reserve.scalar) - .unwrap_optimized(); + interest_value += i128(asset_to_base).fixed_mul_floor( + e, + &reserve.data.backstop_credit, + &reserve.scalar, + ); auction_data .lot .set(reserve.asset, reserve.data.backstop_credit); @@ -71,18 +73,15 @@ pub fn create_interest_auction_data( } let pool_backstop_data = backstop_client.pool_data(&e.current_contract_address()); - 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 backstop_token_value_base = + (pool_backstop_data + .usdc + .fixed_mul_floor(e, &oracle_scalar, &SCALAR_7) + * 5) + .fixed_div_floor(e, &pool_backstop_data.tokens, &SCALAR_7); let bid_amount = interest_value - .fixed_mul_floor(1_4000000, SCALAR_7) - .unwrap_optimized() - .fixed_div_floor(backstop_token_value_base, SCALAR_7) - .unwrap_optimized(); + .fixed_mul_floor(e, &1_4000000, &SCALAR_7) + .fixed_div_floor(e, &backstop_token_value_base, &SCALAR_7); auction_data.bid.set(backstop_token, bid_amount); auction_data @@ -329,7 +328,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_data_0.backstop_credit = 10_0000000; reserve_config_0.index = 0; @@ -343,7 +342,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_1.b_rate = 1_100_000_000_000; reserve_data_1.last_time = 12345; reserve_data_1.backstop_credit = 2_5000000; reserve_config_1.index = 1; @@ -357,7 +356,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1094,9 +1093,9 @@ mod tests { 100, ); assert_eq!(result.block, 151); - assert_eq!(result.bid.get_unchecked(backstop_token_id), 336_0010348); + assert_eq!(result.bid.get_unchecked(backstop_token_id), 336_0010346); assert_eq!(result.bid.len(), 1); - assert_eq!(result.lot.get_unchecked(underlying_0), 100_0000714); + assert_eq!(result.lot.get_unchecked(underlying_0), 100_0000713); assert_eq!(result.lot.get_unchecked(underlying_1), 25_0000178); assert_eq!(result.lot.get_unchecked(underlying_2), 71); assert_eq!(result.lot.len(), 3); @@ -1147,7 +1146,7 @@ mod tests { let (underlying_0, underlying_0_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); - reserve_data_0.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_data_0.b_supply = 200_000_0000000; reserve_data_0.d_supply = 100_000_0000000; reserve_data_0.last_time = 12345; @@ -1164,7 +1163,7 @@ mod tests { let (underlying_1, underlying_1_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_1, mut reserve_data_1) = testutils::default_reserve_meta(); - reserve_data_1.b_rate = 1_100_000_000; + reserve_data_1.b_rate = 1_100_000_000_000; reserve_data_0.b_supply = 10_000_0000000; reserve_data_0.b_supply = 7_000_0000000; reserve_data_1.last_time = 12345; @@ -1275,7 +1274,7 @@ mod tests { let (underlying_0, underlying_0_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); - reserve_data_0.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_data_0.b_supply = 200_000_0000000; reserve_data_0.d_supply = 100_000_0000000; reserve_data_0.last_time = 12345; @@ -1292,7 +1291,7 @@ mod tests { let (underlying_1, underlying_1_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_1, mut reserve_data_1) = testutils::default_reserve_meta(); - reserve_data_1.b_rate = 1_100_000_000; + reserve_data_1.b_rate = 1_100_000_000_000; reserve_data_0.b_supply = 10_000_0000000; reserve_data_0.b_supply = 7_000_0000000; reserve_data_1.last_time = 12345; diff --git a/pool/src/auctions/bad_debt_auction.rs b/pool/src/auctions/bad_debt_auction.rs index 7c517ed..623a60b 100644 --- a/pool/src/auctions/bad_debt_auction.rs +++ b/pool/src/auctions/bad_debt_auction.rs @@ -7,8 +7,8 @@ use crate::{ storage, }; use cast::i128; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Vec}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::{map, panic_with_error, Address, Env, Vec}; use super::{AuctionData, AuctionType}; @@ -52,10 +52,8 @@ pub fn create_bad_debt_auction_data( .unwrap_or(0); if liability_balance > 0 { let asset_to_base = pool.load_price(e, &reserve.asset); - let asset_balance = reserve.to_asset_from_d_token(liability_balance); - debt_value += i128(asset_to_base) - .fixed_mul_floor(asset_balance, reserve.scalar) - .unwrap_optimized(); + let asset_balance = reserve.to_asset_from_d_token(e, liability_balance); + debt_value += i128(asset_to_base).fixed_mul_floor(e, &asset_balance, &reserve.scalar); auction_data.bid.set(reserve.asset, liability_balance); } else { panic_with_error!(e, PoolError::InvalidBid); @@ -77,20 +75,16 @@ pub fn create_bad_debt_auction_data( let pool_backstop_data = backstop_client.pool_data(&e.current_contract_address()); let backstop_value_base = pool_backstop_data .usdc - .fixed_mul_floor(oracle_scalar, SCALAR_7) - .unwrap_optimized() // adjust for oracle scalar + .fixed_mul_floor(e, &oracle_scalar, &SCALAR_7) // 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) - .unwrap_optimized(); + let backstop_token_to_base = + backstop_value_base.fixed_div_floor(e, &pool_backstop_data.tokens, &SCALAR_7); // determine lot amount of backstop tokens needed to safely cover bad debt, or post // all backstop tokens if there isn't enough to cover the bad debt let mut lot_amount = debt_value - .fixed_mul_floor(1_4000000, SCALAR_7) - .unwrap_optimized() - .fixed_div_floor(backstop_token_to_base, SCALAR_7) - .unwrap_optimized(); + .fixed_mul_floor(e, &1_4000000, &SCALAR_7) + .fixed_div_floor(e, &backstop_token_to_base, &SCALAR_7); lot_amount = pool_backstop_data.tokens.min(lot_amount); auction_data.lot.set(backstop_token, lot_amount); auction_data @@ -156,7 +150,6 @@ mod tests { use sep_40_oracle::testutils::Asset; use soroban_sdk::{ testutils::{Address as _, Ledger, LedgerInfo}, - unwrap::UnwrapOptimized, vec, Symbol, }; @@ -383,7 +376,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -478,7 +471,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -586,7 +579,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -681,7 +674,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -776,7 +769,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -789,7 +782,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -802,7 +795,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -908,7 +901,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -921,7 +914,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -934,7 +927,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1041,7 +1034,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1054,7 +1047,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1067,7 +1060,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1180,7 +1173,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1193,7 +1186,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1206,7 +1199,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1314,7 +1307,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 11845; reserve_config_0.index = 0; testutils::create_reserve( @@ -1327,7 +1320,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 11845; reserve_config_1.index = 1; testutils::create_reserve( @@ -1340,7 +1333,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 11845; reserve_config_2.index = 1; testutils::create_reserve( @@ -1448,7 +1441,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1461,7 +1454,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1474,7 +1467,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1579,7 +1572,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1592,7 +1585,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1605,7 +1598,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1659,14 +1652,14 @@ mod tests { samwise_positions .liabilities .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 10_0000000 ); assert_eq!( samwise_positions .liabilities .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 2_5000000 ); let backstop_positions = storage::get_user_positions(&e, &backstop_address); @@ -1716,7 +1709,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1729,7 +1722,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1742,7 +1735,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1807,14 +1800,14 @@ mod tests { samwise_positions .liabilities .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 10_0000000 - 2_5000000 ); assert_eq!( samwise_positions .liabilities .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 2_5000000 - 0_6250000 ); let backstop_positions = storage::get_user_positions(&e, &backstop_address); @@ -1876,7 +1869,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1889,7 +1882,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1902,7 +1895,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -1966,14 +1959,14 @@ mod tests { samwise_positions .liabilities .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 10_0000000 - 2_5000000 ); assert_eq!( samwise_positions .liabilities .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 2_5000000 - 6250000 ); let backstop_positions = storage::get_user_positions(&e, &backstop_address); @@ -1981,14 +1974,14 @@ mod tests { backstop_positions .liabilities .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 2_5000000 ); assert_eq!( backstop_positions .liabilities .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 6250000 ); @@ -2046,7 +2039,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -2059,7 +2052,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -2072,7 +2065,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( @@ -2128,14 +2121,14 @@ mod tests { backstop_positions .liabilities .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 10_0000000 ); assert_eq!( backstop_positions .liabilities .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 2_5000000 ); }); @@ -2185,7 +2178,7 @@ mod tests { 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.d_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -2198,7 +2191,7 @@ mod tests { 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.d_rate = 1_200_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -2211,7 +2204,7 @@ mod tests { 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( diff --git a/pool/src/auctions/user_liquidation_auction.rs b/pool/src/auctions/user_liquidation_auction.rs index 51e6cf2..fc5b006 100644 --- a/pool/src/auctions/user_liquidation_auction.rs +++ b/pool/src/auctions/user_liquidation_auction.rs @@ -1,6 +1,5 @@ use cast::i128; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::unwrap::UnwrapOptimized; +use soroban_fixed_point_math::SorobanFixedPoint; use soroban_sdk::{map, panic_with_error, Address, Env, Vec}; use crate::auctions::auction::AuctionData; @@ -106,32 +105,38 @@ pub fn create_user_liq_auction_data( i128(percent_liquidated_to_check) * position_data.scalar / 100; // scale to decimal form with scalar decimals // ensure liquidation size is fair and the collateral is large enough to allow for the auction to price the liquidation - let avg_cf = position_data_inc - .collateral_base - .fixed_div_floor(position_data_inc.collateral_raw, position_data_inc.scalar) - .unwrap_optimized(); + let avg_cf = position_data_inc.collateral_base.fixed_div_floor( + e, + &position_data_inc.collateral_raw, + &position_data_inc.scalar, + ); // avg_lf is the inverse of the average liability factor - let avg_lf = position_data_inc - .liability_base - .fixed_div_floor(position_data_inc.liability_raw, position_data_inc.scalar) - .unwrap_optimized(); + let avg_lf = position_data_inc.liability_base.fixed_div_floor( + e, + &position_data_inc.liability_raw, + &position_data_inc.scalar, + ); let est_incentive = (position_data_inc.scalar - - avg_cf - .fixed_div_ceil(avg_lf, position_data_inc.scalar) - .unwrap_optimized()) - .fixed_div_ceil(2 * position_data_inc.scalar, position_data_inc.scalar) - .unwrap_optimized() - + position_data_inc.scalar; + - avg_cf.fixed_div_ceil(e, &avg_lf, &position_data_inc.scalar)) + .fixed_div_ceil( + e, + &(2 * position_data_inc.scalar), + &position_data_inc.scalar, + ) + position_data_inc.scalar; let est_withdrawn_collateral = position_data_inc .liability_raw - .fixed_mul_floor(percent_liquidated_i128_scaled, position_data_inc.scalar) - .unwrap_optimized() - .fixed_mul_floor(est_incentive, position_data_inc.scalar) - .unwrap_optimized(); - let mut est_withdrawn_collateral_pct = est_withdrawn_collateral - .fixed_div_ceil(position_data_inc.collateral_raw, position_data_inc.scalar) - .unwrap_optimized(); + .fixed_mul_floor( + e, + &percent_liquidated_i128_scaled, + &position_data_inc.scalar, + ) + .fixed_mul_floor(e, &est_incentive, &position_data_inc.scalar); + let mut est_withdrawn_collateral_pct = est_withdrawn_collateral.fixed_div_ceil( + e, + &position_data_inc.collateral_raw, + &position_data_inc.scalar, + ); // estimated lot exceedes the collateral available in the included positions if est_withdrawn_collateral_pct > position_data_inc.scalar { @@ -146,9 +151,8 @@ pub fn create_user_liq_auction_data( for (asset, amount) in positions_auctioned.collateral.iter() { let res_asset_address = reserve_list.get_unchecked(asset); - let b_tokens_removed = amount - .fixed_mul_ceil(est_withdrawn_collateral_pct, position_data.scalar) - .unwrap_optimized(); + let b_tokens_removed = + amount.fixed_mul_ceil(e, &est_withdrawn_collateral_pct, &position_data.scalar); liquidation_quote .lot .set(res_asset_address.clone(), b_tokens_removed); @@ -157,9 +161,8 @@ pub fn create_user_liq_auction_data( for (asset, amount) in positions_auctioned.liabilities.iter() { let res_asset_address = reserve_list.get_unchecked(asset); - let d_tokens_removed = amount - .fixed_mul_ceil(percent_liquidated_i128_scaled, position_data.scalar) - .unwrap_optimized(); + let d_tokens_removed = + amount.fixed_mul_ceil(e, &percent_liquidated_i128_scaled, &position_data.scalar); liquidation_quote .bid .set(res_asset_address.clone(), d_tokens_removed); @@ -180,19 +183,20 @@ pub fn create_user_liq_auction_data( // 95% liquidation is not too large. That is, if a user can be liquidated to 95%, they can // be liquidated fully. This helps prevent edge cases due to liquidation percentages // being harder to calculate between as it approaches 100. - if est_withdrawn_collateral < position_data.collateral_raw && new_data.is_hf_over(1_1500000) + if est_withdrawn_collateral < position_data.collateral_raw + && new_data.is_hf_over(e, 1_1500000) { panic_with_error!(e, PoolError::InvalidLiqTooLarge) }; full_liquidation_quote } else { // Post-liq health factor must be under 1.15 - if new_data.is_hf_over(1_1500000) { + if new_data.is_hf_over(e, 1_1500000) { panic_with_error!(e, PoolError::InvalidLiqTooLarge) }; // Post-liq heath factor must be over 1.03 - if new_data.is_hf_under(1_0300000) { + if new_data.is_hf_under(e, 1_0300000) { panic_with_error!(e, PoolError::InvalidLiqTooSmall) }; liquidation_quote @@ -447,8 +451,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -463,8 +467,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -545,8 +549,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -561,8 +565,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -643,8 +647,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -659,8 +663,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -741,8 +745,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -757,8 +761,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -839,7 +843,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -853,7 +857,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -952,7 +956,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -966,7 +970,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1071,7 +1075,7 @@ mod tests { 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.b_rate = 1_000_206_159; + reserve_data_0.b_rate = 1_000_206_159_000; reserve_config_0.c_factor = 0_9000000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1088,7 +1092,7 @@ mod tests { reserve_config_1.c_factor = 0_0000000; reserve_config_1.l_factor = 0_9000000; reserve_config_1.index = 1; - reserve_data_1.d_rate = 1000201748; + reserve_data_1.d_rate = 1_000_201_748_000; testutils::create_reserve( &e, &pool_address, @@ -1137,7 +1141,7 @@ mod tests { assert_eq!(result.block, 51); assert_eq!(result.bid.get_unchecked(underlying_1), 731_0913452); assert_eq!(result.bid.len(), 1); - assert_eq!(result.lot.get_unchecked(underlying_0), 5791_1010751); + assert_eq!(result.lot.get_unchecked(underlying_0), 5791_1010712); assert_eq!(result.lot.len(), 1); }); } @@ -1170,7 +1174,7 @@ mod tests { 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.b_rate = 1_000_206_159; + reserve_data_0.b_rate = 1_000_206_159_000; reserve_config_0.c_factor = 0_9000000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1188,7 +1192,7 @@ mod tests { reserve_config_1.l_factor = 0_9000000; reserve_config_1.index = 1; reserve_config_1.decimals = 6; - reserve_data_1.d_rate = 1000201748; + reserve_data_1.d_rate = 1_000_201_748_000; testutils::create_reserve( &e, &pool_address, @@ -1268,7 +1272,7 @@ mod tests { 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.b_rate = 1_000_206_159; + reserve_data_0.b_rate = 1_000_206_159_000; reserve_config_0.c_factor = 0_9000000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1285,7 +1289,7 @@ mod tests { reserve_config_1.c_factor = 0_5000000; reserve_config_1.l_factor = 0_8000000; reserve_config_1.index = 1; - reserve_data_1.d_rate = 1_050_001_748; + reserve_data_1.d_rate = 1_050_001_748_000; testutils::create_reserve( &e, &pool_address, @@ -1376,8 +1380,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1392,8 +1396,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -1531,7 +1535,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1545,7 +1549,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1646,7 +1650,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1660,7 +1664,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1761,7 +1765,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1775,7 +1779,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1873,8 +1877,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1889,8 +1893,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -1983,8 +1987,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1999,8 +2003,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -2093,8 +2097,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2109,8 +2113,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -2202,8 +2206,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2218,8 +2222,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -2306,8 +2310,8 @@ mod tests { 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.b_rate = 1_100_000_000; - reserve_data_0.d_rate = 1_150_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; + reserve_data_0.d_rate = 1_150_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2322,8 +2326,8 @@ mod tests { 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.b_rate = 1_200_000_000; - reserve_data_1.d_rate = 1_300_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; + reserve_data_1.d_rate = 1_300_000_000_000; reserve_config_1.c_factor = 0_8000000; reserve_config_1.l_factor = 0_7500000; reserve_config_1.index = 1; @@ -2410,7 +2414,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2424,7 +2428,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -2513,21 +2517,21 @@ mod tests { frodo_positions .collateral .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 30_5595329 ); assert_eq!( frodo_positions .collateral .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 1_5395739 ); assert_eq!( frodo_positions .liabilities .get(reserve_config_2.index) - .unwrap_optimized(), + .unwrap(), 1_2375000 ); let samwise_positions = storage::get_user_positions(&e, &samwise); @@ -2535,21 +2539,21 @@ mod tests { samwise_positions .collateral .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 90_9100000 - 30_5595329 ); assert_eq!( samwise_positions .collateral .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 04_5800000 - 1_5395739 ); assert_eq!( samwise_positions .liabilities .get(reserve_config_2.index) - .unwrap_optimized(), + .unwrap(), 02_7500000 - 1_2375000 ); }); @@ -2584,7 +2588,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2598,7 +2602,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -2685,7 +2689,7 @@ mod tests { let samwise_positions = storage::get_user_positions(&e, &samwise); let samwise_hf = PositionData::calculate_from_positions(&e, &mut pool, &samwise_positions) - .as_health_factor(); + .as_health_factor(&e); assert_eq!(samwise_hf, 1_1458977); }); } @@ -2719,7 +2723,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -2733,7 +2737,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -2822,14 +2826,14 @@ mod tests { frodo_positions .collateral .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 30_5595329 ); assert_eq!( frodo_positions .collateral .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 1_5395739 ); assert_eq!(frodo_positions.liabilities.len(), 0); @@ -2838,21 +2842,21 @@ mod tests { samwise_positions .collateral .get(reserve_config_0.index) - .unwrap_optimized(), + .unwrap(), 90_9100000 - 30_5595329 ); assert_eq!( samwise_positions .collateral .get(reserve_config_1.index) - .unwrap_optimized(), + .unwrap(), 04_5800000 - 1_5395739 ); assert_eq!( samwise_positions .liabilities .get(reserve_config_2.index) - .unwrap_optimized(), + .unwrap(), 02_7500000 - 0 ); }); diff --git a/pool/src/constants.rs b/pool/src/constants.rs index 95ee29f..812832f 100644 --- a/pool/src/constants.rs +++ b/pool/src/constants.rs @@ -1,7 +1,7 @@ /********** Numbers **********/ -/// Fixed-point scalar for 9 decimal numbers -pub const SCALAR_9: i128 = 1_000_000_000; +/// Fixed-point scalar for 12 decimal numbers +pub const SCALAR_12: i128 = 1_000_000_000_000; /// Fixed-point scalar for 7 decimal numbers pub const SCALAR_7: i128 = 1_0000000; diff --git a/pool/src/emissions/manager.rs b/pool/src/emissions/manager.rs index fb655f6..dacae4b 100644 --- a/pool/src/emissions/manager.rs +++ b/pool/src/emissions/manager.rs @@ -6,7 +6,7 @@ use crate::{ storage::{self, ReserveConfig, ReserveEmissionData}, }; use cast::{i128, u64}; -use soroban_fixed_point_math::FixedPoint; +use soroban_fixed_point_math::SorobanFixedPoint; use soroban_sdk::{ contracttype, map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Map, Vec, }; @@ -92,10 +92,8 @@ fn do_gulp_emissions(e: &Env, new_emissions: i128) { } for (res_config, res_asset_address, res_token_id, res_eps_share) in pool_emis_enabled { let new_reserve_emissions = i128(res_eps_share) - .fixed_div_floor(total_share, SCALAR_7) - .unwrap_optimized() - .fixed_mul_floor(new_emissions, SCALAR_7) - .unwrap_optimized(); + .fixed_div_floor(e, &total_share, &SCALAR_7) + .fixed_mul_floor(e, &new_emissions, &SCALAR_7); update_reserve_emission_eps( e, @@ -140,9 +138,11 @@ fn update_reserve_emission_eps( let time_since_last_emission = emission_data.expiration - e.ledger().timestamp(); // Eps is scaled by 14 decimals - let tokens_since_last_emission = i128(emission_data.eps) - .fixed_mul_floor(i128(time_since_last_emission), SCALAR_7) - .unwrap_optimized(); + let tokens_since_last_emission = i128(emission_data.eps).fixed_mul_floor( + e, + &i128(time_since_last_emission), + &SCALAR_7, + ); tokens_left_to_emit += tokens_since_last_emission; } diff --git a/pool/src/pool/actions.rs b/pool/src/pool/actions.rs index a04ce50..2284006 100644 --- a/pool/src/pool/actions.rs +++ b/pool/src/pool/actions.rs @@ -133,7 +133,7 @@ pub fn build_actions_from_request( RequestType::Supply => { let mut reserve = pool.load_reserve(e, &request.address, true); reserve.require_action_allowed(e, request.request_type); - let b_tokens_minted = reserve.to_b_token_down(request.amount); + let b_tokens_minted = reserve.to_b_token_down(e, request.amount); from_state.add_supply(e, &mut reserve, b_tokens_minted); actions.add_for_spender_transfer(&reserve.asset, request.amount); pool.cache_reserve(reserve); @@ -148,11 +148,11 @@ pub fn build_actions_from_request( RequestType::Withdraw => { let mut reserve = pool.load_reserve(e, &request.address, true); let cur_b_tokens = from_state.get_supply(reserve.config.index); - let mut to_burn = reserve.to_b_token_up(request.amount); + let mut to_burn = reserve.to_b_token_up(e, request.amount); let mut tokens_out = request.amount; if to_burn > cur_b_tokens { to_burn = cur_b_tokens; - tokens_out = reserve.to_asset_from_b_token(cur_b_tokens); + tokens_out = reserve.to_asset_from_b_token(e, cur_b_tokens); } from_state.remove_supply(e, &mut reserve, to_burn); actions.add_for_pool_transfer(&reserve.asset, tokens_out); @@ -168,12 +168,10 @@ pub fn build_actions_from_request( RequestType::SupplyCollateral => { let mut reserve = pool.load_reserve(e, &request.address, true); reserve.require_action_allowed(e, request.request_type); - let b_tokens_minted = reserve.to_b_token_down(request.amount); + let b_tokens_minted = reserve.to_b_token_down(e, request.amount); from_state.add_collateral(e, &mut reserve, b_tokens_minted); actions.add_for_spender_transfer(&reserve.asset, request.amount); - if reserve.to_asset_from_b_token(reserve.data.b_supply) - > reserve.config.collateral_cap - { + if reserve.total_supply(e) > reserve.config.collateral_cap { panic_with_error!(e, PoolError::ExceededCollateralCap); } pool.cache_reserve(reserve); @@ -188,11 +186,11 @@ pub fn build_actions_from_request( RequestType::WithdrawCollateral => { let mut reserve = pool.load_reserve(e, &request.address, true); let cur_b_tokens = from_state.get_collateral(reserve.config.index); - let mut to_burn = reserve.to_b_token_up(request.amount); + let mut to_burn = reserve.to_b_token_up(e, request.amount); let mut tokens_out = request.amount; if to_burn > cur_b_tokens { to_burn = cur_b_tokens; - tokens_out = reserve.to_asset_from_b_token(cur_b_tokens); + tokens_out = reserve.to_asset_from_b_token(e, cur_b_tokens); } from_state.remove_collateral(e, &mut reserve, to_burn); actions.add_for_pool_transfer(&reserve.asset, tokens_out); @@ -209,7 +207,7 @@ pub fn build_actions_from_request( RequestType::Borrow => { let mut reserve = pool.load_reserve(e, &request.address, true); reserve.require_action_allowed(e, request.request_type); - let d_tokens_minted = reserve.to_d_token_up(request.amount); + let d_tokens_minted = reserve.to_d_token_up(e, request.amount); from_state.add_liabilities(e, &mut reserve, d_tokens_minted); reserve.require_utilization_below_max(e); actions.add_for_pool_transfer(&reserve.asset, request.amount); @@ -226,9 +224,9 @@ pub fn build_actions_from_request( RequestType::Repay => { let mut reserve = pool.load_reserve(e, &request.address, true); let cur_d_tokens = from_state.get_liabilities(reserve.config.index); - let d_tokens_burnt = reserve.to_d_token_down(request.amount); + let d_tokens_burnt = reserve.to_d_token_down(e, request.amount); if d_tokens_burnt > cur_d_tokens { - let cur_underlying_borrowed = reserve.to_asset_from_d_token(cur_d_tokens); + let cur_underlying_borrowed = reserve.to_asset_from_d_token(e, cur_d_tokens); let amount_to_refund = request.amount - cur_underlying_borrowed; require_nonnegative(e, &amount_to_refund); actions.add_for_spender_transfer(&reserve.asset, request.amount); @@ -1132,7 +1130,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1146,7 +1144,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1277,7 +1275,7 @@ mod tests { 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.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_config_0.c_factor = 0_8500000; reserve_config_0.l_factor = 0_9000000; reserve_config_0.index = 0; @@ -1291,7 +1289,7 @@ mod tests { 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.b_rate = 1_200_000_000; + reserve_data_1.b_rate = 1_200_000_000_000; reserve_config_1.c_factor = 0_7500000; reserve_config_1.l_factor = 0_7500000; reserve_data_1.last_time = 12345; @@ -1402,7 +1400,7 @@ mod tests { let (underlying_0, underlying_0_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); - reserve_data_0.b_rate = 1_100_000_000; + reserve_data_0.b_rate = 1_100_000_000_000; reserve_data_0.last_time = 12345; reserve_config_0.index = 0; testutils::create_reserve( @@ -1416,7 +1414,7 @@ mod tests { let (underlying_1, underlying_1_client) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_1, mut reserve_data_1) = testutils::default_reserve_meta(); - reserve_data_1.b_rate = 1_100_000_000; + reserve_data_1.b_rate = 1_100_000_000_000; reserve_data_1.last_time = 12345; reserve_config_1.index = 1; testutils::create_reserve( @@ -1430,7 +1428,7 @@ mod tests { let (underlying_2, underlying_2_client) = 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.b_rate = 1_100_000_000_000; reserve_data_2.last_time = 12345; reserve_config_2.index = 1; testutils::create_reserve( diff --git a/pool/src/pool/config.rs b/pool/src/pool/config.rs index e969b37..0b32453 100644 --- a/pool/src/pool/config.rs +++ b/pool/src/pool/config.rs @@ -1,5 +1,5 @@ use crate::{ - constants::{SCALAR_7, SCALAR_9, SECONDS_PER_WEEK}, + constants::{SCALAR_12, SCALAR_7, SECONDS_PER_WEEK}, errors::PoolError, storage::{ self, has_queued_reserve_set, PoolConfig, QueuedReserveInit, ReserveConfig, ReserveData, @@ -123,15 +123,15 @@ fn initialize_reserve(e: &Env, asset: &Address, config: &ReserveConfig) -> u32 { || reserve_config.r_three != config.r_three || reserve_config.util != config.util { - reserve.data.ir_mod = SCALAR_9; + reserve.data.ir_mod = SCALAR_7; } reserve.store(e); } else { index = storage::push_res_list(e, asset); let init_data = ReserveData { - b_rate: SCALAR_9, - d_rate: SCALAR_9, - ir_mod: SCALAR_9, + b_rate: SCALAR_12, + d_rate: SCALAR_12, + ir_mod: SCALAR_7, d_supply: 0, b_supply: 0, last_time: e.ledger().timestamp(), @@ -705,10 +705,10 @@ mod tests { // validate interest was accrued let res_data = storage::get_res_data(&e, &underlying); - assert!(res_data.d_rate > 1_000_000_000); + assert!(res_data.d_rate > 1_000_000_000_000); assert!(res_data.backstop_credit > 0); assert_eq!(res_data.last_time, 10000); - assert!(res_data.ir_mod != 1_000_000_000); + assert!(res_data.ir_mod != 1_0000000); }); } @@ -781,10 +781,10 @@ mod tests { assert_eq!(res_config_updated.index, reserve_config.index); let res_data = storage::get_res_data(&e, &underlying); - assert!(res_data.d_rate > 1_000_000_000); + assert!(res_data.d_rate > 1_000_000_000_000); assert!(res_data.backstop_credit > 0); assert_eq!(res_data.last_time, 10000); - assert_eq!(res_data.ir_mod, 1_000_000_000); + assert_eq!(res_data.ir_mod, 1_0000000); }); } diff --git a/pool/src/pool/gulp.rs b/pool/src/pool/gulp.rs index c61c6d9..f00ce8a 100644 --- a/pool/src/pool/gulp.rs +++ b/pool/src/pool/gulp.rs @@ -17,11 +17,11 @@ pub fn execute_gulp(e: &Env, asset: &Address) -> (i128, i128) { let mut reserve = Reserve::load(e, &pool_config, asset); let pool_token_balance = TokenClient::new(e, asset).balance(&e.current_contract_address()); let reserve_token_balance = - reserve.total_supply() + reserve.data.backstop_credit - reserve.total_liabilities(); + reserve.total_supply(e) + reserve.data.backstop_credit - reserve.total_liabilities(e); let token_balance_delta = pool_token_balance - reserve_token_balance; - let pre_gulp_b_rate = reserve.data.b_rate; - reserve.gulp(pool_config.bstop_rate, token_balance_delta); + let pre_gulp_b_rate = reserve.data.b_rate; + reserve.gulp(e, pool_config.bstop_rate, token_balance_delta); // If the reserve's b_rate hasn't changed the token delta is not significant if pre_gulp_b_rate == reserve.data.b_rate { @@ -42,10 +42,61 @@ mod tests { testutils::{Address as _, Ledger, LedgerInfo}, Address, Env, }; + #[test] fn test_execute_gulp() { let e = Env::default(); - e.mock_all_auths_allowing_non_root_auth(); + e.mock_all_auths(); + e.ledger().set(LedgerInfo { + timestamp: 100, + protocol_version: 22, + sequence_number: 1234, + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 10, + min_persistent_entry_ttl: 10, + max_entry_ttl: 3110400, + }); + let bombadil = Address::generate(&e); + let pool = testutils::create_pool(&e); + let (oracle, _) = testutils::create_mock_oracle(&e); + + let (underlying, underlying_client) = testutils::create_token_contract(&e, &bombadil); + let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); + reserve_data.b_rate = 1_000_000_000_000; + reserve_data.d_rate = 1_000_000_000_000; + reserve_data.d_supply = 500 * SCALAR_7; + reserve_data.b_supply = 1000 * SCALAR_7; + reserve_data.backstop_credit = 0; + reserve_data.last_time = 100; + testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); + + let additional_tokens = 10 * SCALAR_7; + underlying_client.mint(&pool, &additional_tokens); + e.as_contract(&pool, || { + let pool_config = PoolConfig { + oracle, + bstop_rate: 0_1000000, + status: 0, + max_positions: 4, + }; + storage::set_pool_config(&e, &pool_config); + + let (token_delta_result, new_b_rate) = execute_gulp(&e, &underlying); + assert_eq!(token_delta_result, additional_tokens); + assert_eq!(new_b_rate, 1_009_000_000_000); + + let new_reserve_data = storage::get_res_data(&e, &underlying); + assert_eq!(new_reserve_data.b_rate, new_b_rate); + assert_eq!(new_reserve_data.last_time, 100); + assert_eq!(new_reserve_data.backstop_credit, 1_0000000); + }); + } + + #[test] + fn test_execute_gulp_accrues_interest() { + let e = Env::default(); + e.mock_all_auths(); e.ledger().set(LedgerInfo { timestamp: 100, protocol_version: 22, @@ -61,10 +112,17 @@ mod tests { let (oracle, _) = testutils::create_mock_oracle(&e); let (underlying, underlying_client) = testutils::create_token_contract(&e, &bombadil); - let (reserve_config, reserve_data) = testutils::default_reserve_meta(); + let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); + reserve_data.b_rate = 1_000_000_000_000; + reserve_data.d_rate = 1_000_000_000_000; + reserve_data.d_supply = 500 * SCALAR_7; + reserve_data.b_supply = 1000 * SCALAR_7; + reserve_data.backstop_credit = 0; + reserve_data.last_time = 0; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); - underlying_client.mint(&pool, &(1000 * SCALAR_7)); + let additional_tokens = 10 * SCALAR_7; + underlying_client.mint(&pool, &additional_tokens); e.as_contract(&pool, || { let pool_config = PoolConfig { oracle, @@ -73,18 +131,20 @@ mod tests { max_positions: 4, }; storage::set_pool_config(&e, &pool_config); + let (token_delta_result, new_b_rate) = execute_gulp(&e, &underlying); - assert_eq!(token_delta_result, 10000000000); - assert_eq!(new_b_rate, 10000000130); - let reserve_data = storage::get_res_data(&e, &underlying); - assert_eq!(reserve_data.b_rate, new_b_rate); - assert_eq!(reserve_data.last_time, 100); - assert_eq!(reserve_data.backstop_credit, 100_0000000 + 14) // 14 from interest + assert_eq!(token_delta_result, additional_tokens); + assert_eq!(new_b_rate, 1_009_000_062_000); + + let new_reserve_data = storage::get_res_data(&e, &underlying); + assert_eq!(new_reserve_data.b_rate, new_b_rate); + assert_eq!(new_reserve_data.last_time, 100); + assert_eq!(new_reserve_data.backstop_credit, 1_0000000 + 68); }); } #[test] - fn test_execute_gulp_zero_delta() { + fn test_execute_gulp_zero_delta_skips() { let e = Env::default(); e.mock_all_auths_allowing_non_root_auth(); e.ledger().set(LedgerInfo { @@ -102,7 +162,13 @@ mod tests { let (oracle, _) = testutils::create_mock_oracle(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); - let (reserve_config, reserve_data) = testutils::default_reserve_meta(); + let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); + reserve_data.b_rate = 1_000_000_000_000; + reserve_data.d_rate = 1_000_000_000_000; + reserve_data.d_supply = 500 * SCALAR_7; + reserve_data.b_supply = 1000 * SCALAR_7; + reserve_data.backstop_credit = 0; + reserve_data.last_time = 0; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); e.as_contract(&pool, || { @@ -113,12 +179,16 @@ mod tests { max_positions: 4, }; storage::set_pool_config(&e, &pool_config); + let (token_delta_result, new_b_rate) = execute_gulp(&e, &underlying); - let reserve = storage::get_res_data(&e, &underlying); assert_eq!(token_delta_result, 0); - assert_eq!(new_b_rate, 1000000130); // Increase of 130 from interest - assert_eq!(reserve.b_rate, reserve_data.b_rate); // B rate should not change - assert_eq!(reserve.last_time, 0); // Last time should not change + assert_eq!(new_b_rate, 1_000_000_062_000); + + // data not set + let new_reserve_data = storage::get_res_data(&e, &underlying); + assert_eq!(new_reserve_data.b_rate, 1_000_000_000_000); + assert_eq!(new_reserve_data.last_time, 0); + assert_eq!(new_reserve_data.backstop_credit, 0); }); } @@ -143,13 +213,14 @@ mod tests { let (underlying, underlying_client) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.b_rate = 1_623_456_890; - reserve_data.d_rate = 1_323_456_890; - reserve_data.d_supply = 99_711 * SCALAR_7; - reserve_data.b_supply = 23_493_4 * SCALAR_7; - // reserve_data.last_time = 100; + reserve_data.b_rate = 1_623_456_890_000; + reserve_data.d_rate = 1_323_456_890_000; + reserve_data.d_supply = 990_711 * SCALAR_7; + reserve_data.b_supply = 123_493_400 * SCALAR_7; + reserve_data.last_time = 0; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); - underlying_client.mint(&pool, &(1000)); + + underlying_client.mint(&pool, &1000); e.as_contract(&pool, || { let pool_config = PoolConfig { oracle, @@ -158,14 +229,15 @@ mod tests { max_positions: 4, }; storage::set_pool_config(&e, &pool_config); - let pre_gulp_reserve = storage::get_res_data(&e, &underlying); + let (token_delta_result, new_b_rate) = execute_gulp(&e, &underlying); - let reserve = storage::get_res_data(&e, &underlying); assert_eq!(token_delta_result, 0); - assert_eq!(new_b_rate, 1623456943); // Increase of 145 from interest - assert_eq!(reserve.backstop_credit, 0); - assert_eq!(reserve.b_rate, pre_gulp_reserve.b_rate); - assert_eq!(reserve.last_time, pre_gulp_reserve.last_time); + assert_eq!(new_b_rate, 1_623_456_890_316); // from interest + // validate not stored + let new_reserve_data = storage::get_res_data(&e, &underlying); + assert_eq!(new_reserve_data.backstop_credit, 0); + assert_eq!(new_reserve_data.b_rate, reserve_data.b_rate); + assert_eq!(new_reserve_data.last_time, 0); }); } } diff --git a/pool/src/pool/health_factor.rs b/pool/src/pool/health_factor.rs index bc96dac..8d086fb 100644 --- a/pool/src/pool/health_factor.rs +++ b/pool/src/pool/health_factor.rs @@ -1,5 +1,5 @@ -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{unwrap::UnwrapOptimized, Env}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::Env; use crate::{constants::SCALAR_7, storage}; @@ -43,30 +43,26 @@ impl PositionData { if b_token_balance > 0 { // append users effective collateral to collateral_base - let asset_collateral = reserve.to_effective_asset_from_b_token(b_token_balance); - collateral_base += asset_to_base - .fixed_mul_floor(asset_collateral, reserve.scalar) - .unwrap_optimized(); - collateral_raw += asset_to_base - .fixed_mul_floor( - reserve.to_asset_from_b_token(b_token_balance), - reserve.scalar, - ) - .unwrap_optimized(); + let asset_collateral = reserve.to_effective_asset_from_b_token(e, b_token_balance); + collateral_base += + asset_to_base.fixed_mul_floor(e, &asset_collateral, &reserve.scalar); + collateral_raw += asset_to_base.fixed_mul_floor( + e, + &reserve.to_asset_from_b_token(e, b_token_balance), + &reserve.scalar, + ); } if d_token_balance > 0 { // append users effective liability to liability_base - let asset_liability = reserve.to_effective_asset_from_d_token(d_token_balance); - liability_base += asset_to_base - .fixed_mul_ceil(asset_liability, reserve.scalar) - .unwrap_optimized(); - liability_raw += asset_to_base - .fixed_mul_ceil( - reserve.to_asset_from_d_token(d_token_balance), - reserve.scalar, - ) - .unwrap_optimized(); + let asset_liability = reserve.to_effective_asset_from_d_token(e, d_token_balance); + liability_base += + asset_to_base.fixed_mul_ceil(e, &asset_liability, &reserve.scalar); + liability_raw += asset_to_base.fixed_mul_ceil( + e, + &reserve.to_asset_from_d_token(e, d_token_balance), + &reserve.scalar, + ); } pool.cache_reserve(reserve); @@ -82,20 +78,19 @@ impl PositionData { } /// Return the health factor as a ratio - pub fn as_health_factor(&self) -> i128 { + pub fn as_health_factor(&self, e: &Env) -> i128 { self.collateral_base - .fixed_div_floor(self.liability_base, self.scalar) - .unwrap_optimized() + .fixed_div_floor(e, &self.liability_base, &self.scalar) } // Check if the position data is over a maximum health factor // Note: max must be 7 decimals - pub fn is_hf_over(&self, max: i128) -> bool { + pub fn is_hf_over(&self, e: &Env, max: i128) -> bool { if self.liability_base == 0 { return true; } - let min_health_factor = self.scalar.fixed_mul_ceil(max, SCALAR_7).unwrap_optimized(); - if self.as_health_factor() > min_health_factor { + let min_health_factor = self.scalar.fixed_mul_ceil(e, &max, &SCALAR_7); + if self.as_health_factor(e) > min_health_factor { return true; } false @@ -103,15 +98,12 @@ impl PositionData { /// Check if the position data is under a minimum health factor /// Note: min must be 7 decimals - pub fn is_hf_under(&self, min: i128) -> bool { + pub fn is_hf_under(&self, e: &Env, min: i128) -> bool { if self.liability_base == 0 { return false; } - let min_health_factor = self - .scalar - .fixed_mul_floor(min, SCALAR_7) - .unwrap_optimized(); - if self.as_health_factor() < min_health_factor { + let min_health_factor = self.scalar.fixed_mul_floor(e, &min, &SCALAR_7); + if self.as_health_factor(e) < min_health_factor { return true; } false @@ -150,8 +142,8 @@ mod tests { reserve_config.l_factor = 0_8000000; reserve_data.b_supply = 100_000_000_000; reserve_data.d_supply = 70_000_000_000; - reserve_data.b_rate = 1_100_000_000; - reserve_data.d_rate = 1_150_000_000; + reserve_data.b_rate = 1_100_000_000_000; + reserve_data.d_rate = 1_150_000_000_000; reserve_config.index = 1; testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); @@ -161,8 +153,8 @@ mod tests { reserve_config.index = 2; reserve_data.b_supply = 10_000_000; reserve_data.d_supply = 5_000_000; - reserve_data.b_rate = 1_001_100_000; - reserve_data.d_rate = 1_001_200_000; + reserve_data.b_rate = 1_001_100_000_000; + reserve_data.d_rate = 1_001_200_000_000; testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); oracle_client.set_data( @@ -215,6 +207,7 @@ mod tests { #[test] fn test_as_health_factor_rounds_floor() { + let e = Env::default(); let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 0, @@ -224,12 +217,14 @@ mod tests { }; // actual: 1.002577659 - let result = position_data.as_health_factor(); + let result = position_data.as_health_factor(&e); assert_eq!(result, 1_0025776); } #[test] fn test_is_hf_under() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 12_0000000, @@ -238,13 +233,15 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_under(1_0000100); + let result = position_data.is_hf_under(&e, 1_0000100); // no panic assert_eq!(result, false); } #[test] fn test_is_hf_under_odd_scalar() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_12345, collateral_raw: 12_00000, @@ -253,13 +250,15 @@ mod tests { scalar: 1_00000, }; - let result = position_data.is_hf_under(1_0000100); + let result = position_data.is_hf_under(&e, 1_0000100); // no panic assert_eq!(result, false); } #[test] fn test_is_hf_under_no_liabilites() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 12_0000000, @@ -268,13 +267,15 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_under(1_0000100); + let result = position_data.is_hf_under(&e, 1_0000100); // no panic assert_eq!(result, false); } #[test] fn test_is_hf_under_true() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 12_0000000, @@ -283,13 +284,15 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_under(1_0000100); + let result = position_data.is_hf_under(&e, 1_0000100); // panic assert!(result); } #[test] fn test_is_hf_over() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 12_0000000, @@ -298,13 +301,15 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_over(1_1000000); + let result = position_data.is_hf_over(&e, 1_1000000); // no panic assert_eq!(result, false); } #[test] fn test_is_hf_over_odd_scalar() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567_000, collateral_raw: 12_0000000_000, @@ -313,13 +318,15 @@ mod tests { scalar: 1_0000000_000, }; - let result = position_data.is_hf_over(1_1000000); + let result = position_data.is_hf_over(&e, 1_1000000); // no panic assert_eq!(result, false); } #[test] fn test_is_hf_over_no_liabilites() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 9_1234567, collateral_raw: 12_0000000, @@ -328,12 +335,14 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_over(1_0000100); + let result = position_data.is_hf_over(&e, 1_0000100); // panic assert!(result); } #[test] fn test_is_hf_over_true() { + let e = Env::default(); + let position_data = PositionData { collateral_base: 19_1234567, collateral_raw: 22_0000000, @@ -342,7 +351,7 @@ mod tests { scalar: 1_0000000, }; - let result = position_data.is_hf_over(1_0000100); + let result = position_data.is_hf_over(&e, 1_0000100); // panic assert!(result); } diff --git a/pool/src/pool/interest.rs b/pool/src/pool/interest.rs index 4abb023..beba6c7 100644 --- a/pool/src/pool/interest.rs +++ b/pool/src/pool/interest.rs @@ -1,9 +1,9 @@ use cast::i128; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{unwrap::UnwrapOptimized, Env}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::Env; use crate::{ - constants::{SCALAR_7, SCALAR_9, SECONDS_PER_YEAR}, + constants::{SCALAR_12, SCALAR_7, SECONDS_PER_YEAR}, storage::ReserveConfig, }; @@ -29,59 +29,42 @@ pub fn calc_accrual( let cur_ir: i128; let target_util: i128 = i128(config.util); if cur_util <= target_util { - let util_scalar = cur_util - .fixed_div_ceil(target_util, SCALAR_7) - .unwrap_optimized(); - let base_rate = util_scalar - .fixed_mul_ceil(i128(config.r_one), SCALAR_7) - .unwrap_optimized() - + i128(config.r_base); + let util_scalar = cur_util.fixed_div_ceil(e, &target_util, &SCALAR_7); + let base_rate = + util_scalar.fixed_mul_ceil(e, &i128(config.r_one), &SCALAR_7) + i128(config.r_base); - cur_ir = base_rate - .fixed_mul_ceil(ir_mod, SCALAR_9) - .unwrap_optimized(); + cur_ir = base_rate.fixed_mul_ceil(e, &ir_mod, &SCALAR_7); } else if cur_util <= 0_9500000 { - let util_scalar = (cur_util - target_util) - .fixed_div_ceil(0_9500000 - target_util, SCALAR_7) - .unwrap_optimized(); - let base_rate = util_scalar - .fixed_mul_ceil(i128(config.r_two), SCALAR_7) - .unwrap_optimized() + let util_scalar = + (cur_util - target_util).fixed_div_ceil(e, &(0_9500000 - target_util), &SCALAR_7); + let base_rate = util_scalar.fixed_mul_ceil(e, &i128(config.r_two), &SCALAR_7) + i128(config.r_one) + i128(config.r_base); - cur_ir = base_rate - .fixed_mul_ceil(ir_mod, SCALAR_9) - .unwrap_optimized(); + cur_ir = base_rate.fixed_mul_ceil(e, &ir_mod, &SCALAR_7); } else { - let util_scalar = (cur_util - 0_9500000) - .fixed_div_ceil(0_0500000, SCALAR_7) - .unwrap_optimized(); - let extra_rate = util_scalar - .fixed_mul_ceil(i128(config.r_three), SCALAR_7) - .unwrap_optimized(); - - let intersection = ir_mod - .fixed_mul_ceil(i128(config.r_two + config.r_one + config.r_base), SCALAR_9) - .unwrap_optimized(); + let util_scalar = (cur_util - 0_9500000).fixed_div_ceil(e, &0_0500000, &SCALAR_7); + let extra_rate = util_scalar.fixed_mul_ceil(e, &i128(config.r_three), &SCALAR_7); + + let intersection = ir_mod.fixed_mul_ceil( + e, + &i128(config.r_two + config.r_one + config.r_base), + &SCALAR_7, + ); cur_ir = extra_rate + intersection; } // update rate_modifier - // scale delta blocks and util dif to 9 decimals - let delta_time_scaled = i128(e.ledger().timestamp() - last_time) * SCALAR_9; - let util_dif_scaled = (cur_util - target_util) * 100; + let delta_time = i128(e.ledger().timestamp() - last_time); + // util dif 7 decimals + let util_dif = cur_util - target_util; let new_ir_mod: i128; - if util_dif_scaled >= 0 { + if util_dif >= 0 { // rate modifier increasing - let util_error = delta_time_scaled - .fixed_mul_floor(util_dif_scaled, SCALAR_9) - .unwrap_optimized(); - let rate_dif = util_error - .fixed_mul_floor(i128(config.reactivity), SCALAR_7) - .unwrap_optimized(); + let util_error = delta_time * util_dif; + let rate_dif = util_error.fixed_mul_floor(e, &i128(config.reactivity), &SCALAR_7); let next_ir_mod = ir_mod + rate_dif; - let ir_mod_max = 10 * SCALAR_9; + let ir_mod_max = 10 * SCALAR_7; if next_ir_mod > ir_mod_max { new_ir_mod = ir_mod_max; } else { @@ -89,14 +72,10 @@ pub fn calc_accrual( } } else { // rate modifier decreasing - let util_error = delta_time_scaled - .fixed_mul_ceil(util_dif_scaled, SCALAR_9) - .unwrap_optimized(); - let rate_dif = util_error - .fixed_mul_ceil(i128(config.reactivity), SCALAR_7) - .unwrap_optimized(); + let util_error = delta_time * util_dif; + let rate_dif = util_error.fixed_mul_ceil(e, &i128(config.reactivity), &SCALAR_7); let next_ir_mod = ir_mod + rate_dif; - let ir_mod_min = SCALAR_9 / 10; + let ir_mod_min = SCALAR_7 / 10; if next_ir_mod < ir_mod_min { new_ir_mod = ir_mod_min; } else { @@ -105,12 +84,12 @@ pub fn calc_accrual( } // calc accrual amount over blocks + // scale delta_time to 12 decimals so time_weight is scaled to 12 decimals + let delta_time_scaled = delta_time * SCALAR_12; let time_weight = delta_time_scaled / SECONDS_PER_YEAR; ( - SCALAR_9 - + time_weight - .fixed_mul_ceil(cur_ir * 100, SCALAR_9) - .unwrap_optimized(), + // accrual scaled to 12 decimals + SCALAR_12 + time_weight.fixed_mul_ceil(e, &cur_ir, &SCALAR_7), new_ir_mod, ) } @@ -139,7 +118,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 1_000_000_000; + let ir_mod: i128 = 1_0000000; e.ledger().set(LedgerInfo { timestamp: 500, @@ -154,8 +133,8 @@ mod tests { let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_6565656, ir_mod, 0); - assert_eq!(accrual, 1_000_000_853); - assert_eq!(ir_mod, 0_999_906_566); + assert_eq!(accrual, 1_000_000_852_536); + assert_eq!(ir_mod, 0_9999066); } #[test] @@ -177,7 +156,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 1_000_000_000; + let ir_mod: i128 = 1_0000000; e.ledger().set(LedgerInfo { timestamp: 500, @@ -192,8 +171,8 @@ mod tests { let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_7979797, ir_mod, 0); - assert_eq!(accrual, 1_000_002_853); - assert_eq!(ir_mod, 1_000_047_979); + assert_eq!(accrual, 1_000_002_853_078); + assert_eq!(ir_mod, 1_0000479); } #[test] @@ -215,7 +194,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 1_000_000_000; + let ir_mod: i128 = 1_0000000; e.ledger().set(LedgerInfo { timestamp: 500, @@ -230,8 +209,8 @@ mod tests { let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_9696969, ir_mod, 0); - assert_eq!(accrual, 1_000_018_247); - assert_eq!(ir_mod, 1_000_219_696); + assert_eq!(accrual, 1_000_018_247_510); + assert_eq!(ir_mod, 1_0002196); } #[test] @@ -253,7 +232,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 9_997_000_000; + let ir_mod: i128 = 9_9970000; e.ledger().set(LedgerInfo { timestamp: 12345, @@ -268,7 +247,7 @@ mod tests { let (_accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_9696969, ir_mod, 0); - assert_eq!(ir_mod, 10_000_000_000); + assert_eq!(ir_mod, 10_0000000); } #[test] @@ -290,7 +269,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 0_150_000_000; + let ir_mod: i128 = 0_1500000; e.ledger().set(LedgerInfo { timestamp: 10000 * 5, @@ -305,11 +284,11 @@ mod tests { let (_accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_2020202, ir_mod, 0); - assert_eq!(ir_mod, 0_100_000_000); + assert_eq!(ir_mod, 0_1000000); } #[test] - fn test_calc_accrual_rounds_up() { + fn test_calc_ir_mod_reactivity_0() { let e = Env::default(); let reserve_config = ReserveConfig { @@ -322,12 +301,50 @@ mod tests { r_one: 0_0500000, r_two: 0_5000000, r_three: 1_5000000, + reactivity: 0, + collateral_cap: 1000000000000000000, + index: 0, + enabled: true, + }; + let ir_mod: i128 = 1_0000000; + + e.ledger().set(LedgerInfo { + timestamp: 500, + protocol_version: 22, + sequence_number: 100, + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 10, + min_persistent_entry_ttl: 10, + max_entry_ttl: 3110400, + }); + + let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_6565656, ir_mod, 0); + + assert_eq!(accrual, 1_000_000_852_536); + assert_eq!(ir_mod, 1_0000000); + } + + #[test] + fn test_calc_accrual_rounds_up() { + let e = Env::default(); + + let reserve_config = ReserveConfig { + decimals: 7, + c_factor: 0_7500000, + l_factor: 0_7500000, + util: 0_7500000, + max_util: 0_9500000, + r_base: 0_0001000, + r_one: 0_0500000, + r_two: 0_5000000, + r_three: 1_5000000, reactivity: 0_0000020, collateral_cap: 1000000000000000000, index: 0, enabled: true, }; - let ir_mod: i128 = 0_100_000_000; + let ir_mod: i128 = 0_1000000; e.ledger().set(LedgerInfo { timestamp: 501, @@ -340,10 +357,10 @@ mod tests { max_entry_ttl: 3110400, }); - let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_0500000, ir_mod, 500); + let (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_0000005, ir_mod, 500); - assert_eq!(accrual, 1_000_000_001); - assert_eq!(ir_mod, 0_100_000_000); + assert_eq!(accrual, 1_000_000_000_001); + assert_eq!(ir_mod, 0_1000000); } #[test] @@ -365,7 +382,7 @@ mod tests { index: 0, enabled: true, }; - let ir_mod: i128 = 1_000_000_000; + let ir_mod: i128 = 1_0000000; e.ledger().set(LedgerInfo { timestamp: 500, @@ -383,13 +400,13 @@ mod tests { let (accrual_2, ir_mod_2) = calc_accrual(&e, &reserve_config, 0_7565656, ir_mod, 0); let (accrual_3, ir_mod_3) = calc_accrual(&e, &reserve_config, 0_9565656, ir_mod, 0); - assert_eq!(accrual_0, 1_000_003_964); - assert_eq!(ir_mod_0, 0_999_250_000); - assert_eq!(accrual_1, 1_000_003_964); - assert_eq!(ir_mod_1, 0_999_906_566); - assert_eq!(accrual_2, 1_000_003_964); - assert_eq!(ir_mod_2, 1_000_006_565); - assert_eq!(accrual_3, 1_000_003_964); - assert_eq!(ir_mod_3, 1_000_206_565); + assert_eq!(accrual_0, 1_000_003_963_724); + assert_eq!(ir_mod_0, 0_9992500); + assert_eq!(accrual_1, 1_000_003_963_724); + assert_eq!(ir_mod_1, 0_9999066); + assert_eq!(accrual_2, 1_000_003_963_724); + assert_eq!(ir_mod_2, 1_0000065); + assert_eq!(accrual_3, 1_000_003_963_724); + assert_eq!(ir_mod_3, 1_0002065); } } diff --git a/pool/src/pool/pool.rs b/pool/src/pool/pool.rs index 4236571..f1f8032 100644 --- a/pool/src/pool/pool.rs +++ b/pool/src/pool/pool.rs @@ -230,12 +230,12 @@ mod tests { let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); reserve_config.index = 1; - reserve_data.d_rate = 1_001_000_000; + reserve_data.d_rate = 1_001_000_000_000; testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); reserve_config.index = 2; - reserve_data.d_rate = 1_002_000_000; + reserve_data.d_rate = 1_002_000_000_000; testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); let pool_config = PoolConfig { @@ -318,12 +318,12 @@ mod tests { let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); reserve_config.index = 1; - reserve_data.d_rate = 1_001_000_000; + reserve_data.d_rate = 1_001_000_000_000; testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); reserve_config.index = 2; - reserve_data.d_rate = 1_002_000_000; + reserve_data.d_rate = 1_002_000_000_000; testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); let pool_config = PoolConfig { diff --git a/pool/src/pool/reserve.rs b/pool/src/pool/reserve.rs index 771d214..4478c09 100644 --- a/pool/src/pool/reserve.rs +++ b/pool/src/pool/reserve.rs @@ -1,9 +1,9 @@ use cast::i128; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{contracttype, panic_with_error, unwrap::UnwrapOptimized, Address, Env}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::{contracttype, panic_with_error, Address, Env}; use crate::{ - constants::{SCALAR_7, SCALAR_9}, + constants::{SCALAR_12, SCALAR_7}, errors::PoolError, pool::actions::RequestType, storage::{self, PoolConfig, ReserveConfig, ReserveData}, @@ -11,7 +11,7 @@ use crate::{ use super::interest::calc_accrual; -#[derive(Clone)] +#[derive(Clone, Debug)] #[contracttype] pub struct Reserve { pub asset: Address, // the underlying asset address @@ -52,7 +52,7 @@ impl Reserve { return reserve; } - let cur_util = reserve.utilization(); + let cur_util = reserve.utilization(e); if cur_util == 0 { // if there are no assets borrowed, we don't need to update the reserve reserve.data.last_time = e.ledger().timestamp(); @@ -68,13 +68,11 @@ impl Reserve { ); reserve.data.ir_mod = new_ir_mod; - let pre_update_liabilities = reserve.total_liabilities(); - reserve.data.d_rate = loan_accrual - .fixed_mul_ceil(reserve.data.d_rate, SCALAR_9) - .unwrap_optimized(); - let accrued_interest = reserve.total_liabilities() - pre_update_liabilities; + let pre_update_liabilities = reserve.total_liabilities(e); + reserve.data.d_rate = loan_accrual.fixed_mul_ceil(e, &reserve.data.d_rate, &SCALAR_12); + let accrued_interest = reserve.total_liabilities(e) - pre_update_liabilities; - reserve.gulp(pool_config.bstop_rate, accrued_interest); + reserve.gulp(e, pool_config.bstop_rate, accrued_interest); reserve.data.last_time = e.ledger().timestamp(); reserve @@ -90,35 +88,34 @@ impl Reserve { /// ### Arguments /// * bstop_rate - The backstop take rate for the pool /// * accrued - The amount of additional underlying tokens - pub fn gulp(&mut self, bstop_rate: u32, accrued: i128) { - let pre_update_supply = self.total_supply(); + pub fn gulp(&mut self, e: &Env, bstop_rate: u32, accrued: i128) { + let pre_update_supply = self.total_supply(e); if accrued > 0 { // credit the backstop underlying from the accrued interest based on the backstop rate // update the accrued interest to reflect the amount the pool accrued let mut new_backstop_credit: i128 = 0; if bstop_rate > 0 { - new_backstop_credit = accrued - .fixed_mul_floor(i128(bstop_rate), SCALAR_7) - .unwrap_optimized(); + new_backstop_credit = accrued.fixed_mul_floor(e, &i128(bstop_rate), &SCALAR_7); self.data.backstop_credit += new_backstop_credit; } - self.data.b_rate = (pre_update_supply + accrued - new_backstop_credit) - .fixed_div_floor(self.data.b_supply, SCALAR_9) - .unwrap_optimized(); + self.data.b_rate = (pre_update_supply + accrued - new_backstop_credit).fixed_div_floor( + e, + &self.data.b_supply, + &SCALAR_12, + ); } } /// Fetch the current utilization rate for the reserve normalized to 7 decimals - pub fn utilization(&self) -> i128 { - self.total_liabilities() - .fixed_div_ceil(self.total_supply(), SCALAR_7) - .unwrap_optimized() + pub fn utilization(&self, e: &Env) -> i128 { + self.total_liabilities(e) + .fixed_div_ceil(e, &self.total_supply(e), &SCALAR_7) } /// Require that the utilization rate is below the maximum allowed, or panic. pub fn require_utilization_below_max(&self, e: &Env) { - if self.utilization() > i128(self.config.max_util) { + if self.utilization(e) > i128(self.config.max_util) { panic_with_error!(e, PoolError::InvalidUtilRate) } } @@ -140,13 +137,13 @@ impl Reserve { } /// Fetch the total liabilities for the reserve in underlying tokens - pub fn total_liabilities(&self) -> i128 { - self.to_asset_from_d_token(self.data.d_supply) + pub fn total_liabilities(&self, e: &Env) -> i128 { + self.to_asset_from_d_token(e, self.data.d_supply) } /// Fetch the total supply for the reserve in underlying tokens - pub fn total_supply(&self) -> i128 { - self.to_asset_from_b_token(self.data.b_supply) + pub fn total_supply(&self, e: &Env) -> i128 { + self.to_asset_from_b_token(e, self.data.b_supply) } /********** Conversion Functions **********/ @@ -155,20 +152,16 @@ impl Reserve { /// /// ### Arguments /// * `d_tokens` - The amount of tokens to convert - pub fn to_asset_from_d_token(&self, d_tokens: i128) -> i128 { - d_tokens - .fixed_mul_ceil(self.data.d_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_asset_from_d_token(&self, e: &Env, d_tokens: i128) -> i128 { + d_tokens.fixed_mul_ceil(e, &self.data.d_rate, &SCALAR_12) } /// Convert b_tokens to the corresponding asset value /// /// ### Arguments /// * `b_tokens` - The amount of tokens to convert - pub fn to_asset_from_b_token(&self, b_tokens: i128) -> i128 { - b_tokens - .fixed_mul_floor(self.data.b_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_asset_from_b_token(&self, e: &Env, b_tokens: i128) -> i128 { + b_tokens.fixed_mul_floor(e, &self.data.b_rate, &SCALAR_12) } /// Convert d_tokens to their corresponding effective asset value. This @@ -176,11 +169,9 @@ impl Reserve { /// /// ### Arguments /// * `d_tokens` - The amount of tokens to convert - pub fn to_effective_asset_from_d_token(&self, d_tokens: i128) -> i128 { - let assets = self.to_asset_from_d_token(d_tokens); - assets - .fixed_div_ceil(i128(self.config.l_factor), SCALAR_7) - .unwrap_optimized() + pub fn to_effective_asset_from_d_token(&self, e: &Env, d_tokens: i128) -> i128 { + let assets = self.to_asset_from_d_token(e, d_tokens); + assets.fixed_div_ceil(e, &i128(self.config.l_factor), &SCALAR_7) } /// Convert b_tokens to the corresponding effective asset value. This @@ -188,51 +179,41 @@ impl Reserve { /// /// ### Arguments /// * `b_tokens` - The amount of tokens to convert - pub fn to_effective_asset_from_b_token(&self, b_tokens: i128) -> i128 { - let assets = self.to_asset_from_b_token(b_tokens); - assets - .fixed_mul_floor(i128(self.config.c_factor), SCALAR_7) - .unwrap_optimized() + pub fn to_effective_asset_from_b_token(&self, e: &Env, b_tokens: i128) -> i128 { + let assets = self.to_asset_from_b_token(e, b_tokens); + assets.fixed_mul_floor(e, &i128(self.config.c_factor), &SCALAR_7) } /// Convert asset tokens to the corresponding d token value - rounding up /// /// ### Arguments /// * `amount` - The amount of tokens to convert - pub fn to_d_token_up(&self, amount: i128) -> i128 { - amount - .fixed_div_ceil(self.data.d_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_d_token_up(&self, e: &Env, amount: i128) -> i128 { + amount.fixed_div_ceil(e, &self.data.d_rate, &SCALAR_12) } /// Convert asset tokens to the corresponding d token value - rounding down /// /// ### Arguments /// * `amount` - The amount of tokens to convert - pub fn to_d_token_down(&self, amount: i128) -> i128 { - amount - .fixed_div_floor(self.data.d_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_d_token_down(&self, e: &Env, amount: i128) -> i128 { + amount.fixed_div_floor(e, &self.data.d_rate, &SCALAR_12) } /// Convert asset tokens to the corresponding b token value - round up /// /// ### Arguments /// * `amount` - The amount of tokens to convert - pub fn to_b_token_up(&self, amount: i128) -> i128 { - amount - .fixed_div_ceil(self.data.b_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_b_token_up(&self, e: &Env, amount: i128) -> i128 { + amount.fixed_div_ceil(e, &self.data.b_rate, &SCALAR_12) } /// Convert asset tokens to the corresponding b token value - round down /// /// ### Arguments /// * `amount` - The amount of tokens to convert - pub fn to_b_token_down(&self, amount: i128) -> i128 { - amount - .fixed_div_floor(self.data.b_rate, SCALAR_9) - .unwrap_optimized() + pub fn to_b_token_down(&self, e: &Env, amount: i128) -> i128 { + amount.fixed_div_floor(e, &self.data.b_rate, &SCALAR_12) } } @@ -241,6 +222,7 @@ mod tests { use super::*; use crate::testutils; use soroban_sdk::testutils::{Address as _, Ledger, LedgerInfo}; + #[test] fn test_load_reserve() { let e = Env::default(); @@ -263,8 +245,8 @@ mod tests { let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.d_rate = 1_345_678_123; - reserve_data.b_rate = 1_123_456_789; + reserve_data.d_rate = 1_345_678_123_000; + reserve_data.b_rate = 1_123_456_789_000; reserve_data.d_supply = 65_0000000; reserve_data.b_supply = 99_0000000; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); @@ -279,17 +261,70 @@ mod tests { storage::set_pool_config(&e, &pool_config); let reserve = Reserve::load(&e, &pool_config, &underlying); - // (accrual: 1_002_957_369, util: .7864353) - assert_eq!(reserve.data.d_rate, 1_349_657_800); - assert_eq!(reserve.data.b_rate, 1_125_547_124); - assert_eq!(reserve.data.ir_mod, 1_044_981_563); + // (accrual: 1_002_957_375_248, util: .7864353) + assert_eq!(reserve.data.d_rate, 1_349_657_798_173); + assert_eq!(reserve.data.b_rate, 1_125_547_124_242); + assert_eq!(reserve.data.ir_mod, 1_0449815); assert_eq!(reserve.data.d_supply, 65_0000000); assert_eq!(reserve.data.b_supply, 99_0000000); - assert_eq!(reserve.data.backstop_credit, 0_0517358); + assert_eq!(reserve.data.backstop_credit, 0_0517357); assert_eq!(reserve.data.last_time, 617280); }); } + #[test] + fn test_load_reserve_accrues_b_rate() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 1000, + protocol_version: 22, + sequence_number: 123456, + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 10, + min_persistent_entry_ttl: 10, + max_entry_ttl: 3110400, + }); + + let bombadil = Address::generate(&e); + let pool = testutils::create_pool(&e); + let oracle = Address::generate(&e); + + // setup load reserve with minimal interest gained (5s / low util / high supply) + // to validate b/d rate is still safely accrued + let (underlying, _) = testutils::create_token_contract(&e, &bombadil); + let (mut reserve_config, mut reserve_data) = testutils::default_reserve_meta(); + reserve_config.decimals = 18; + let scalar = 10i128.pow(reserve_config.decimals); + reserve_data.d_rate = 1_500_000_000_000; + reserve_data.b_rate = 1_300_000_000_000; + reserve_data.ir_mod = SCALAR_7; + reserve_data.d_supply = 100_000_000 * scalar; + reserve_data.b_supply = 10_000_000_000 * scalar; + reserve_data.last_time = 995; + testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); + + let pool_config = PoolConfig { + oracle, + bstop_rate: 0_2000000, + status: 0, + max_positions: 5, + }; + e.as_contract(&pool, || { + storage::set_pool_config(&e, &pool_config); + let reserve = Reserve::load(&e, &pool_config, &underlying); + + // validate that b and d rates are updated + assert_eq!(reserve.data.last_time, 1000); + assert_eq!(reserve.data.b_rate, 1_300_000_000_020); + assert_eq!(reserve.data.d_rate, 1_500_000_002_562); + assert_eq!(reserve.data.ir_mod, 9999927); + assert_eq!(reserve.data.backstop_credit, 0_051240000_000000000); + }); + } + #[test] fn test_load_reserve_zero_supply() { let e = Env::default(); @@ -328,10 +363,9 @@ mod tests { storage::set_pool_config(&e, &pool_config); let reserve = Reserve::load(&e, &pool_config, &underlying); - // (accrual: 1_002_957_369, util: .7864352)q assert_eq!(reserve.data.d_rate, 0); assert_eq!(reserve.data.b_rate, 0); - assert_eq!(reserve.data.ir_mod, 1_000_000_000); + assert_eq!(reserve.data.ir_mod, 10000000); assert_eq!(reserve.data.d_supply, 0); assert_eq!(reserve.data.b_supply, 0); assert_eq!(reserve.data.backstop_credit, 0); @@ -407,8 +441,8 @@ mod tests { let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.d_rate = 1_345_678_123; - reserve_data.b_rate = 1_123_456_789; + reserve_data.d_rate = 1_345_678_123_000; + reserve_data.b_rate = 1_123_456_789_000; reserve_data.d_supply = 65_0000000; reserve_data.b_supply = 99_0000000; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); @@ -423,10 +457,10 @@ mod tests { storage::set_pool_config(&e, &pool_config); let reserve = Reserve::load(&e, &pool_config, &underlying); - // (accrual: 1_002_957_369, util: .7864353) - assert_eq!(reserve.data.d_rate, 1_349_657_800); - assert_eq!(reserve.data.b_rate, 1_126_069_708); - assert_eq!(reserve.data.ir_mod, 1_044_981_563); + // (accrual: 1_002_957_375_248, util: .7864353) + assert_eq!(reserve.data.d_rate, 1_349_657_798_173); + assert_eq!(reserve.data.b_rate, 1_126_069_707_070); + assert_eq!(reserve.data.ir_mod, 1_0449815); assert_eq!(reserve.data.d_supply, 65_0000000); assert_eq!(reserve.data.b_supply, 99_0000000); assert_eq!(reserve.data.backstop_credit, 0); @@ -456,8 +490,8 @@ mod tests { let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.d_rate = 1_345_678_123; - reserve_data.b_rate = 1_123_456_789; + reserve_data.d_rate = 1_345_678_123_000; + reserve_data.b_rate = 1_123_456_789_000; reserve_data.d_supply = 65_0000000; reserve_data.b_supply = 99_0000000; testutils::create_reserve(&e, &pool, &underlying, &reserve_config, &reserve_data); @@ -466,7 +500,7 @@ mod tests { oracle, bstop_rate: 0_2000000, status: 0, - max_positions: 4, + max_positions: 5, }; e.as_contract(&pool, || { storage::set_pool_config(&e, &pool_config); @@ -475,13 +509,13 @@ mod tests { let reserve_data = storage::get_res_data(&e, &underlying); - // (accrual: 1_002_957_369, util: .7864353) - assert_eq!(reserve_data.d_rate, 1_349_657_800); - assert_eq!(reserve_data.b_rate, 1_125_547_124); - assert_eq!(reserve_data.ir_mod, 1_044_981_563); + // (accrual: 1_002_957_375_248, util: .7864353) + assert_eq!(reserve_data.d_rate, 1_349_657_798_173); + assert_eq!(reserve_data.b_rate, 1_125_547_124_242); + assert_eq!(reserve_data.ir_mod, 1_0449815); assert_eq!(reserve_data.d_supply, 65_0000000); assert_eq!(reserve_data.b_supply, 99_0000000); - assert_eq!(reserve_data.backstop_credit, 0_0517358); + assert_eq!(reserve_data.backstop_credit, 0_0517357); assert_eq!(reserve_data.last_time, 617280); }); } @@ -491,12 +525,12 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_345_678_123; - reserve.data.b_rate = 1_123_456_789; + reserve.data.d_rate = 1_345_678_123_000; + reserve.data.b_rate = 1_123_456_789_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.utilization(); + let result = reserve.utilization(&e); assert_eq!(result, 0_7864353); } @@ -533,11 +567,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_321_834_961; + reserve.data.d_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_asset_from_d_token(1_1234567); + let result = reserve.to_asset_from_d_token(&e, 1_1234567); assert_eq!(result, 1_4850244); } @@ -547,11 +581,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.b_rate = 1_321_834_961; + reserve.data.b_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_asset_from_b_token(1_1234567); + let result = reserve.to_asset_from_b_token(&e, 1_1234567); assert_eq!(result, 1_4850243); } @@ -561,12 +595,12 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_321_834_961; + reserve.data.d_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; reserve.config.l_factor = 1_1000000; - let result = reserve.to_effective_asset_from_d_token(1_1234567); + let result = reserve.to_effective_asset_from_d_token(&e, 1_1234567); assert_eq!(result, 1_3500222); } @@ -576,12 +610,12 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.b_rate = 1_321_834_961; + reserve.data.b_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; reserve.config.c_factor = 0_8500000; - let result = reserve.to_effective_asset_from_b_token(1_1234567); + let result = reserve.to_effective_asset_from_b_token(&e, 1_1234567); assert_eq!(result, 1_2622706); } @@ -591,11 +625,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_823_912_692; + reserve.data.d_rate = 1_823_912_692_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.total_liabilities(); + let result = reserve.total_liabilities(&e); assert_eq!(result, 118_5543250); } @@ -605,11 +639,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.b_rate = 1_823_912_692; + reserve.data.b_rate = 1_823_912_692_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.total_supply(); + let result = reserve.total_supply(&e); assert_eq!(result, 180_5673565); } @@ -619,11 +653,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_321_834_961; + reserve.data.d_rate = 1_321_834_961_999; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_d_token_up(1_4850243); + let result = reserve.to_d_token_up(&e, 1_4850243); assert_eq!(result, 1_1234567); } @@ -633,11 +667,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.d_rate = 1_321_834_961; + reserve.data.d_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_d_token_down(1_4850243); + let result = reserve.to_d_token_down(&e, 1_4850243); assert_eq!(result, 1_1234566); } @@ -647,11 +681,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.b_rate = 1_321_834_961; + reserve.data.b_rate = 1_321_834_961_999; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_b_token_up(1_4850243); + let result = reserve.to_b_token_up(&e, 1_4850243); assert_eq!(result, 1_1234567); } @@ -661,11 +695,11 @@ mod tests { let e = Env::default(); let mut reserve = testutils::default_reserve(&e); - reserve.data.b_rate = 1_321_834_961; + reserve.data.b_rate = 1_321_834_961_000; reserve.data.b_supply = 99_0000000; reserve.data.d_supply = 65_0000000; - let result = reserve.to_b_token_down(1_4850243); + let result = reserve.to_b_token_down(&e, 1_4850243); assert_eq!(result, 1_1234566); } @@ -723,9 +757,9 @@ mod tests { let mut reserve = testutils::default_reserve(&e); reserve.data.backstop_credit = 0_1234567; - reserve.gulp(0_2000000, 100_0000000); + reserve.gulp(&e, 0_2000000, 100_0000000); assert_eq!(reserve.data.backstop_credit, 20_0000000 + 0_1234567); - assert_eq!(reserve.data.b_rate, 1_800000000); + assert_eq!(reserve.data.b_rate, 1_800_000_000_000); assert_eq!(reserve.data.last_time, 0); } @@ -748,9 +782,9 @@ mod tests { let mut reserve = testutils::default_reserve(&e); reserve.data.backstop_credit = 0_1234567; - reserve.gulp(0_2000000, -10_0000000); + reserve.gulp(&e, 0_2000000, -10_0000000); assert_eq!(reserve.data.backstop_credit, 0_1234567); - assert_eq!(reserve.data.b_rate, 1000000000); + assert_eq!(reserve.data.b_rate, 1_000_000_000_000); assert_eq!(reserve.data.last_time, 0); } } diff --git a/pool/src/pool/submit.rs b/pool/src/pool/submit.rs index 35f72e6..43ecbde 100644 --- a/pool/src/pool/submit.rs +++ b/pool/src/pool/submit.rs @@ -46,7 +46,7 @@ pub fn execute_submit( if actions.check_health && from_state.has_liabilities() && PositionData::calculate_from_positions(e, &mut pool, &from_state.positions) - .is_hf_under(1_0000100) + .is_hf_under(e, 1_0000100) { panic_with_error!(e, PoolError::InvalidHf); } @@ -82,7 +82,7 @@ pub fn execute_submit_with_flash_loan( // requests. { let mut reserve = pool.load_reserve(e, &flash_loan.asset, true); - let d_tokens_minted = reserve.to_d_token_up(flash_loan.amount); + let d_tokens_minted = reserve.to_d_token_up(e, flash_loan.amount); from_state.add_liabilities(e, &mut reserve, d_tokens_minted); reserve.require_utilization_below_max(e); @@ -104,7 +104,7 @@ pub fn execute_submit_with_flash_loan( // min is 1.0000100 to prevent rounding errors if from_state.has_liabilities() && PositionData::calculate_from_positions(e, &mut pool, &from_state.positions) - .is_hf_under(1_0000100) + .is_hf_under(e, 1_0000100) { panic_with_error!(e, PoolError::InvalidHf); } diff --git a/pool/src/pool/user.rs b/pool/src/pool/user.rs index 541b363..69d07c7 100644 --- a/pool/src/pool/user.rs +++ b/pool/src/pool/user.rs @@ -1,7 +1,7 @@ use soroban_fixed_point_math::SorobanFixedPoint; use soroban_sdk::{contracttype, panic_with_error, Address, Env, Map}; -use crate::{constants::SCALAR_9, emissions, storage, validator::require_nonnegative, PoolError}; +use crate::{constants::SCALAR_12, emissions, storage, validator::require_nonnegative, PoolError}; use super::{Pool, Reserve}; @@ -107,8 +107,8 @@ impl User { self.remove_liabilities(e, reserve, amount); // determine amount of funds in underlying that have defaulted // and deduct them from the b_rate - let default_amount = reserve.to_asset_from_d_token(amount); - let b_rate_loss = default_amount.fixed_div_floor(&e, &reserve.data.b_supply, &SCALAR_9); + let default_amount = reserve.to_asset_from_d_token(e, amount); + let b_rate_loss = default_amount.fixed_div_floor(&e, &reserve.data.b_supply, &SCALAR_12); reserve.data.b_rate -= b_rate_loss; if reserve.data.b_rate < 0 { reserve.data.b_rate = 0; @@ -263,7 +263,7 @@ impl User { mod tests { use super::*; use crate::{constants::SCALAR_7, storage, testutils, ReserveEmissionData, UserEmissionData}; - use soroban_fixed_point_math::FixedPoint; + use soroban_fixed_point_math::SorobanFixedPoint; use soroban_sdk::{ map, testutils::{Address as _, Ledger, LedgerInfo}, @@ -417,17 +417,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_10000000000000) - .fixed_div_floor(starting_d_supply_0, SCALAR_7) - .unwrap(); + + (1000i128 * 0_10000000000000).fixed_div_floor( + &e, + &starting_d_supply_0, + &SCALAR_7, + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } @@ -506,17 +510,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_1000000) - .fixed_div_floor(starting_d_supply_0, SCALAR_7 * SCALAR_7) - .unwrap(); + + (1000i128 * 0_1000000).fixed_div_floor( + &e, + &starting_d_supply_0, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } @@ -550,9 +558,9 @@ mod tests { let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); - reserve_0.data.d_rate = 1_500_000_000; + reserve_0.data.d_rate = 1_500_000_000_000; reserve_0.data.d_supply = 500_0000000; - reserve_0.data.b_rate = 1_250_000_000; + reserve_0.data.b_rate = 1_250_000_000_000; reserve_0.data.b_supply = 750_0000000; let mut user = User { @@ -566,17 +574,17 @@ mod tests { assert_eq!(user.get_liabilities(0), 20_0000000); let d_supply = reserve_0.data.d_supply; - let total_supply = reserve_0.total_supply(); - let underlying_default_amount = reserve_0.to_asset_from_d_token(20_0000000); + let total_supply = reserve_0.total_supply(&e); + let underlying_default_amount = reserve_0.to_asset_from_d_token(&e, 20_0000000); user.default_liabilities(&e, &mut reserve_0, 20_0000000); assert_eq!(user.get_liabilities(0), 0); assert_eq!(reserve_0.data.d_supply, d_supply - 20_0000000); assert_eq!( - reserve_0.total_supply(), + reserve_0.total_supply(&e), total_supply - underlying_default_amount ); - assert_eq!(reserve_0.data.b_rate, 1_210_000_000); + assert_eq!(reserve_0.data.b_rate, 1_210_000_000_000); assert_eq!(reserve_0.data.b_supply, 750_0000000); }); } @@ -589,9 +597,9 @@ mod tests { let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); - reserve_0.data.d_rate = 1_500_000_000; + reserve_0.data.d_rate = 1_500_000_000_000; reserve_0.data.d_supply = 500_0000000; - reserve_0.data.b_rate = 0_100_000_000; + reserve_0.data.b_rate = 0_100_000_000_000; reserve_0.data.b_supply = 750_0000000; let mut user = User { @@ -609,7 +617,7 @@ mod tests { assert_eq!(user.get_liabilities(0), 0); assert_eq!(reserve_0.data.d_supply, d_supply - 100_0000000); - assert_eq!(reserve_0.total_supply(), 0); + assert_eq!(reserve_0.total_supply(&e), 0); assert_eq!(reserve_0.data.b_rate, 0); assert_eq!(reserve_0.data.b_supply, 750_0000000); }); @@ -728,17 +736,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_1000000) - .fixed_div_floor(starting_b_token_supply, SCALAR_7 * SCALAR_7) - .unwrap(); + + (1000i128 * 0_1000000).fixed_div_floor( + &e, + &starting_b_token_supply, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } @@ -818,17 +830,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_1000000) - .fixed_div_floor(starting_b_token_supply, SCALAR_7 * SCALAR_7) - .unwrap(); + + (1000i128 * 0_1000000).fixed_div_floor( + &e, + &starting_b_token_supply, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } @@ -968,17 +984,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_1000000) - .fixed_div_floor(starting_b_token_supply, SCALAR_7 * SCALAR_7) - .unwrap(); + + (1000i128 * 0_1000000).fixed_div_floor( + &e, + &starting_b_token_supply, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } @@ -1058,17 +1078,21 @@ mod tests { let new_emis_res_data = storage::get_res_emis_data(&e, &res_0_d_token_index).unwrap(); let new_index = 10000000000 - + (1000i128 * 0_1000000) - .fixed_div_floor(starting_b_token_supply, SCALAR_7 * SCALAR_7) - .unwrap(); + + (1000i128 * 0_1000000).fixed_div_floor( + &e, + &starting_b_token_supply, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(new_emis_res_data.last_time, 10001000); assert_eq!(new_emis_res_data.index, new_index); let user_emis_data = storage::get_user_emissions(&e, &samwise, &res_0_d_token_index).unwrap(); let new_accrual = 0 - + (new_index - emis_user_data.index) - .fixed_mul_floor(1000, SCALAR_7 * SCALAR_7) - .unwrap(); + + (new_index - emis_user_data.index).fixed_mul_floor( + &e, + &1000, + &(SCALAR_7 * SCALAR_7), + ); assert_eq!(user_emis_data.accrued, new_accrual); }); } diff --git a/pool/src/storage.rs b/pool/src/storage.rs index 9737b6e..d3ab990 100644 --- a/pool/src/storage.rs +++ b/pool/src/storage.rs @@ -39,7 +39,7 @@ pub struct PoolEmissionConfig { } /// The configuration information about a reserve asset -#[derive(Clone)] +#[derive(Clone, Debug)] #[contracttype] pub struct ReserveConfig { pub index: u32, // the index of the reserve in the list @@ -65,14 +65,14 @@ pub struct QueuedReserveInit { } /// The data for a reserve asset -#[derive(Clone)] +#[derive(Clone, Debug)] #[contracttype] pub struct ReserveData { - pub d_rate: i128, // the conversion rate from dToken to underlying expressed in 9 decimals - pub b_rate: i128, // the conversion rate from bToken to underlying expressed with the underlying's decimals - pub ir_mod: i128, // the interest rate curve modifier - pub b_supply: i128, // the total supply of b tokens - pub d_supply: i128, // the total supply of d tokens + pub d_rate: i128, // the conversion rate from dToken to underlying with 12 decimals + pub b_rate: i128, // the conversion rate from bToken to underlying with 12 decimals + pub ir_mod: i128, // the interest rate curve modifier with 7 decimals + pub b_supply: i128, // the total supply of b tokens, in the underlying token's decimals + pub d_supply: i128, // the total supply of d tokens, in the underlying token's decimals pub backstop_credit: i128, // the amount of underlying tokens currently owed to the backstop pub last_time: u64, // the last block the data was updated } diff --git a/pool/src/testutils.rs b/pool/src/testutils.rs index ba332bf..bf17ff6 100644 --- a/pool/src/testutils.rs +++ b/pool/src/testutils.rs @@ -1,7 +1,7 @@ #![cfg(test)] use crate::{ - constants::{SCALAR_7, SCALAR_9}, + constants::{SCALAR_12, SCALAR_7}, pool::Reserve, storage::{self, ReserveConfig, ReserveData}, PoolContract, @@ -9,10 +9,8 @@ use crate::{ use blend_contract_sdk::emitter::{Client as EmitterClient, WASM as EmitterWASM}; use sep_40_oracle::testutils::{MockPriceOracleClient, MockPriceOracleWASM}; use sep_41_token::testutils::{MockTokenClient, MockTokenWASM}; -use soroban_fixed_point_math::FixedPoint; -use soroban_sdk::{ - testutils::Address as _, unwrap::UnwrapOptimized, vec, Address, BytesN, Env, IntoVal, String, -}; +use soroban_fixed_point_math::SorobanFixedPoint; +use soroban_sdk::{testutils::Address as _, vec, Address, BytesN, Env, IntoVal, String}; use backstop::{BackstopClient, BackstopContract}; use mock_pool_factory::{MockPoolFactory, MockPoolFactoryClient, PoolInitMeta}; @@ -219,9 +217,9 @@ pub(crate) fn default_reserve(e: &Env) -> Reserve { enabled: true, }, data: ReserveData { - b_rate: 1_000_000_000, - d_rate: 1_000_000_000, - ir_mod: 1_000_000_000, + b_rate: SCALAR_12, + d_rate: SCALAR_12, + ir_mod: SCALAR_7, b_supply: 100_0000000, d_supply: 75_0000000, last_time: 0, @@ -249,9 +247,9 @@ pub(crate) fn default_reserve_meta() -> (ReserveConfig, ReserveData) { enabled: true, }, ReserveData { - b_rate: 1_000_000_000, - d_rate: 1_000_000_000, - ir_mod: 1_000_000_000, + b_rate: SCALAR_12, + d_rate: SCALAR_12, + ir_mod: SCALAR_7, b_supply: 100_0000000, d_supply: 75_0000000, last_time: 0, @@ -285,12 +283,11 @@ pub(crate) fn create_reserve( // mint pool assets to set expected b_rate let total_supply = reserve_data .b_supply - .fixed_mul_floor(reserve_data.b_rate, SCALAR_9) - .unwrap_optimized(); - let total_liabilities = reserve_data - .d_supply - .fixed_mul_floor(reserve_data.d_rate, SCALAR_9) - .unwrap_optimized(); + .fixed_mul_floor(e, &reserve_data.b_rate, &SCALAR_12); + let total_liabilities = + reserve_data + .d_supply + .fixed_mul_floor(e, &reserve_data.d_rate, &SCALAR_12); let to_mint_pool = total_supply - total_liabilities + reserve_data.backstop_credit; underlying_client .mock_all_auths() diff --git a/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs b/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs index a4c0e8b..1d2fc31 100644 --- a/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs +++ b/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs @@ -12,7 +12,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, token::TokenClient}; use test_suites::{ assertions::assert_approx_eq_abs, create_fixture_with_data, - test_fixture::{PoolFixture, TestFixture, TokenIndex, SCALAR_7, SCALAR_9}, + test_fixture::{PoolFixture, TestFixture, TokenIndex, SCALAR_7, SCALAR_12}, }; #[derive(Arbitrary, Debug)] diff --git a/test-suites/fuzz/lib.rs b/test-suites/fuzz/lib.rs index 81ba36f..4b1ef59 100644 --- a/test-suites/fuzz/lib.rs +++ b/test-suites/fuzz/lib.rs @@ -10,7 +10,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, token::TokenClient}; use test_suites::{ assertions::assert_approx_eq_abs, create_fixture_with_data, - test_fixture::{PoolFixture, TestFixture, TokenIndex, SCALAR_7, SCALAR_9}, + test_fixture::{PoolFixture, TestFixture, TokenIndex, SCALAR_7, SCALAR_12}, }; #[derive(Arbitrary, Debug)] diff --git a/test-suites/src/setup.rs b/test-suites/src/setup.rs index 38ac4ba..8435c44 100644 --- a/test-suites/src/setup.rs +++ b/test-suites/src/setup.rs @@ -47,6 +47,7 @@ pub fn create_fixture_with_data<'a>(wasm: bool) -> TestFixture<'a> { weth_config.c_factor = 0_800_0000; weth_config.l_factor = 0_800_0000; weth_config.util = 0_700_0000; + weth_config.collateral_cap = i128::MAX; fixture.create_pool_reserve(0, TokenIndex::WETH, &weth_config); // enable emissions for pool diff --git a/test-suites/src/test_fixture.rs b/test-suites/src/test_fixture.rs index be11f1f..29eac46 100644 --- a/test-suites/src/test_fixture.rs +++ b/test-suites/src/test_fixture.rs @@ -18,7 +18,7 @@ use soroban_sdk::testutils::{Address as _, BytesN as _, EnvTestConfig, Ledger, L use soroban_sdk::{vec as svec, Address, BytesN, Env, Map, String, Symbol}; pub const SCALAR_7: i128 = 1_000_0000; -pub const SCALAR_9: i128 = 1_000_000_000; +pub const SCALAR_12: i128 = 1_000_000_000_000; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum TokenIndex { diff --git a/test-suites/tests/test_flashloan.rs b/test-suites/tests/test_flashloan.rs index 5edf792..fba1d17 100644 --- a/test-suites/tests/test_flashloan.rs +++ b/test-suites/tests/test_flashloan.rs @@ -8,7 +8,7 @@ use soroban_sdk::{ use test_suites::{ create_fixture_with_data, moderc3156::create_flashloan_receiver, - test_fixture::{TokenIndex, SCALAR_7, SCALAR_9}, + test_fixture::{TokenIndex, SCALAR_12, SCALAR_7}, }; #[test] @@ -114,7 +114,7 @@ fn test_flashloan() { let flash_loan_events = vec![&fixture.env, events.get_unchecked(0)]; let flash_loan_d_tokens_minted = flash_loan .amount - .fixed_div_ceil(xlm_res_data.data.d_rate, SCALAR_9) + .fixed_div_ceil(xlm_res_data.data.d_rate, SCALAR_12) .unwrap(); let flash_loan_event_data: soroban_sdk::Vec = vec![ &fixture.env, @@ -141,7 +141,7 @@ fn test_flashloan() { let supply_event = vec![&fixture.env, events.get_unchecked(1)]; let supply_b_tokens_minted = supply_amount - .fixed_div_floor(stable_res_data.data.b_rate, SCALAR_9) + .fixed_div_floor(stable_res_data.data.b_rate, SCALAR_12) .unwrap(); let supply_event_data: soroban_sdk::Vec = vec![ &fixture.env, @@ -167,7 +167,7 @@ fn test_flashloan() { let repay_event = vec![&fixture.env, events.get_unchecked(2)]; let repay_d_tokens_burned = repay_amount - .fixed_div_floor(xlm_res_data.data.d_rate, SCALAR_9) + .fixed_div_floor(xlm_res_data.data.d_rate, SCALAR_12) .unwrap(); let repay_event_data: soroban_sdk::Vec = vec![ &fixture.env, diff --git a/test-suites/tests/test_liquidation.rs b/test-suites/tests/test_liquidation.rs index a1924ca..791325c 100644 --- a/test-suites/tests/test_liquidation.rs +++ b/test-suites/tests/test_liquidation.rs @@ -929,7 +929,7 @@ fn test_liquidations() { assert_eq!(positions.liabilities.get(0).unwrap(), bad_debt); }); // check d_supply - let d_supply = 19104605847; + let d_supply = 19104605828; fixture.env.as_contract(&pool_fixture.pool.address, || { let key = PoolDataKey::ResData(fixture.tokens[TokenIndex::STABLE].address.clone()); let data = fixture diff --git a/test-suites/tests/test_overflow_flag.rs b/test-suites/tests/test_overflow_flag.rs index 804f94e..ad363c8 100644 --- a/test-suites/tests/test_overflow_flag.rs +++ b/test-suites/tests/test_overflow_flag.rs @@ -1,31 +1,86 @@ #![cfg(test)] +use std::i128; + use pool::{Request, RequestType}; use soroban_sdk::{testutils::Address as AddressTestTrait, vec, Address, Vec}; use test_suites::{ create_fixture_with_data, - test_fixture::{TokenIndex, SCALAR_7}, + test_fixture::{TokenIndex, SCALAR_12, SCALAR_7}, }; #[test] -#[should_panic(expected = "Error(WasmVm, InvalidAction)")] -fn test_pool_deposit_overflow_panics() { - let fixture = create_fixture_with_data(true); +fn test_pool_overflow() { + let fixture = create_fixture_with_data(false); let pool_fixture = &fixture.pools[0]; - let pool_balance = fixture.tokens[TokenIndex::STABLE].balance(&pool_fixture.pool.address); - fixture.tokens[TokenIndex::STABLE].burn(&pool_fixture.pool.address, &pool_balance); + + // overflow can occur when a user's oracle balance is >i128::MAX + // during a health check + + let weth = &fixture.tokens[TokenIndex::WETH]; + let stable = &fixture.tokens[TokenIndex::STABLE]; + + // check pool balance to ensure balance does not overflow first + // 50% util, leave some room for interest accumulation + let pool_weth_balance = weth.balance(&pool_fixture.pool.address); + let max_weth_deposit = i128::MAX - 2 * pool_weth_balance - 5 * SCALAR_12; + + // under collateral cap for stable + let max_stable_deposit = 999_000_000_000_000000; // Create a user let samwise = Address::generate(&fixture.env); - fixture.tokens[TokenIndex::STABLE].mint(&samwise, &(i128::MAX)); - let request = Request { - request_type: RequestType::Supply as u32, - address: fixture.tokens[TokenIndex::STABLE].address.clone(), - amount: i128::MAX - 10, - }; + weth.mint(&samwise, &max_weth_deposit); + stable.mint(&samwise, &(2 * max_stable_deposit)); + + // deposit tokens into large deposit + let deposit_requests = vec![ + &fixture.env, + Request { + request_type: RequestType::SupplyCollateral as u32, + address: weth.address.clone(), + amount: max_weth_deposit, + }, + Request { + request_type: RequestType::SupplyCollateral as u32, + address: stable.address.clone(), + amount: max_stable_deposit, + }, + ]; + pool_fixture + .pool + .submit(&samwise, &samwise, &samwise, &deposit_requests); + + // allow some time to pass + fixture.jump_with_sequence(60 * 60 * 24); + // validate a health check would overflow if it is >i128::MAX + let borrow_request = vec![ + &fixture.env, + Request { + request_type: RequestType::Borrow as u32, + address: stable.address.clone(), + amount: SCALAR_7, + }, + ]; + let borrow_res = pool_fixture + .pool + .try_submit(&samwise, &samwise, &samwise, &borrow_request); + assert_eq!(borrow_res.is_err(), true); + + // validate the funds can still be withdrawn + let withdraw_requests = vec![ + &fixture.env, + Request { + request_type: RequestType::WithdrawCollateral as u32, + address: weth.address.clone(), + amount: i128::MAX, + }, + ]; pool_fixture .pool - .submit(&samwise, &samwise, &samwise, &vec![&fixture.env, request]); + .submit(&samwise, &samwise, &samwise, &withdraw_requests); + // util is ~=0% so assert at most 1 stroop was lost to rounding + assert!(weth.balance(&samwise) >= max_weth_deposit - 1); } // This test ensures that an accessible underflow in the auction flow cannot be hit due to the overflow-checks flag being set diff --git a/test-suites/tests/test_pool.rs b/test-suites/tests/test_pool.rs index 6ef9473..4d75278 100644 --- a/test-suites/tests/test_pool.rs +++ b/test-suites/tests/test_pool.rs @@ -10,7 +10,7 @@ use test_suites::{ assertions::assert_approx_eq_abs, create_fixture_with_data, pool::default_reserve_metadata, - test_fixture::{TokenIndex, SCALAR_7, SCALAR_9}, + test_fixture::{TokenIndex, SCALAR_12, SCALAR_7}, }; /// Test user exposed functions on the lending pool for basic user functionality, auth, and events. @@ -113,7 +113,7 @@ fn test_pool_user() { assert_eq!(weth.balance(&pool_fixture.pool.address), pool_weth_balance); assert_eq!(weth.allowance(&sam, &pool_fixture.pool.address), 0); sam_weth_btoken_balance += amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.supply.get_unchecked(weth_pool_index), @@ -163,7 +163,7 @@ fn test_pool_user() { assert_eq!(weth.balance(&sam), sam_weth_balance); assert_eq!(weth.balance(&pool_fixture.pool.address), pool_weth_balance); let pool_tokens = amount - .fixed_div_ceil(reserve_data.b_rate, SCALAR_9) + .fixed_div_ceil(reserve_data.b_rate, SCALAR_12) .unwrap(); sam_weth_btoken_balance -= pool_tokens; assert_approx_eq_abs( @@ -245,7 +245,7 @@ fn test_pool_user() { assert_eq!(xlm.balance(&sam), sam_xlm_balance); assert_eq!(xlm.balance(&pool_fixture.pool.address), pool_xlm_balance); sam_xlm_btoken_balance += amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.collateral.get_unchecked(xlm_pool_index), @@ -316,7 +316,7 @@ fn test_pool_user() { assert_eq!(weth.balance(&sam), sam_weth_balance); assert_eq!(weth.balance(&pool_fixture.pool.address), pool_weth_balance); sam_weth_dtoken_balance += amount - .fixed_div_ceil(reserve_data.d_rate, SCALAR_9) + .fixed_div_ceil(reserve_data.d_rate, SCALAR_12) .unwrap(); assert_eq!( result.liabilities.get_unchecked(weth_pool_index), @@ -413,7 +413,7 @@ fn test_pool_user() { let event = vec![&fixture.env, events.get_unchecked(events.len() - 5)]; let xlm_reserve_data = fixture.read_reserve_data(0, TokenIndex::XLM); let est_xlm = sam_xlm_btoken_balance - .fixed_mul_floor(xlm_reserve_data.b_rate, SCALAR_9) + .fixed_mul_floor(xlm_reserve_data.b_rate, SCALAR_12) .unwrap(); pool_xlm_balance -= est_xlm; sam_xlm_balance += est_xlm; @@ -447,7 +447,7 @@ fn test_pool_user() { ); let weth_reserve_data = fixture.read_reserve_data(0, TokenIndex::WETH); let est_weth = sam_weth_dtoken_balance - .fixed_mul_ceil(weth_reserve_data.d_rate, SCALAR_9) + .fixed_mul_ceil(weth_reserve_data.d_rate, SCALAR_12) .unwrap(); pool_weth_balance += est_weth; sam_weth_balance -= est_weth; @@ -525,7 +525,7 @@ fn test_pool_user() { ) ] ); - assert_eq!(result, 2940_3117289); // ~ 4.99k / (100k + 4.99k) * 0.12 (xlm eps) * 5d23hr59m in seconds + assert_eq!(result, 2940_3117269); // ~ 4.99k / (100k + 4.99k) * 0.12 (xlm eps) * 5d23hr59m in seconds assert_eq!(blnd.balance(&sam), sam_blnd_balance + result); } diff --git a/test-suites/tests/test_wasm_happy_path.rs b/test-suites/tests/test_wasm_happy_path.rs index 9438724..5f1166c 100644 --- a/test-suites/tests/test_wasm_happy_path.rs +++ b/test-suites/tests/test_wasm_happy_path.rs @@ -6,7 +6,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address}; use test_suites::{ assertions::assert_approx_eq_abs, create_fixture_with_data, - test_fixture::{TokenIndex, SCALAR_7, SCALAR_9}, + test_fixture::{TokenIndex, SCALAR_12, SCALAR_7}, }; /// Smoke test for managing positions, tracking emissions, and accruing interest @@ -66,7 +66,7 @@ fn test_wasm_happy_path() { pool_stable_balance ); merry_stable_btoken_balance += amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.collateral.get_unchecked(stable_pool_index), @@ -95,7 +95,7 @@ fn test_wasm_happy_path() { assert_eq!(xlm.balance(&sam), sam_xlm_balance); assert_eq!(xlm.balance(&pool_fixture.pool.address), pool_xlm_balance); sam_xlm_btoken_balance += amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.collateral.get_unchecked(xlm_pool_index), @@ -127,7 +127,7 @@ fn test_wasm_happy_path() { pool_stable_balance ); sam_stable_dtoken_balance += amount - .fixed_div_floor(reserve_data.d_rate, SCALAR_9) + .fixed_div_floor(reserve_data.d_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.liabilities.get_unchecked(stable_pool_index), @@ -156,7 +156,7 @@ fn test_wasm_happy_path() { assert_eq!(xlm.balance(&merry), merry_xlm_balance); assert_eq!(xlm.balance(&pool_fixture.pool.address), pool_xlm_balance); merry_xlm_dtoken_balance += amount - .fixed_div_floor(reserve_data.d_rate, SCALAR_9) + .fixed_div_floor(reserve_data.d_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.liabilities.get_unchecked(xlm_pool_index), @@ -212,7 +212,7 @@ fn test_wasm_happy_path() { .pool .claim(&frodo, &vec![&fixture.env, 0, 3], &frodo); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 4665_6412742); + assert_eq!(claim_amount, 4665_6412730); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -228,7 +228,7 @@ fn test_wasm_happy_path() { .pool .claim(&sam, &vec![&fixture.env, 0, 3], &sam); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 730943587256); + assert_eq!(claim_amount, 730943587268); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -262,7 +262,7 @@ fn test_wasm_happy_path() { pool_stable_balance ); sam_stable_dtoken_balance -= amount - .fixed_div_floor(reserve_data.d_rate, SCALAR_9) + .fixed_div_floor(reserve_data.d_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.liabilities.get_unchecked(stable_pool_index), @@ -291,7 +291,7 @@ fn test_wasm_happy_path() { assert_eq!(xlm.balance(&merry), merry_xlm_balance); assert_eq!(xlm.balance(&pool_fixture.pool.address), pool_xlm_balance); merry_xlm_dtoken_balance -= amount - .fixed_div_floor(reserve_data.d_rate, SCALAR_9) + .fixed_div_floor(reserve_data.d_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.liabilities.get_unchecked(xlm_pool_index), @@ -320,7 +320,7 @@ fn test_wasm_happy_path() { assert_eq!(xlm.balance(&sam), sam_xlm_balance); assert_eq!(xlm.balance(&pool_fixture.pool.address), pool_xlm_balance); sam_xlm_btoken_balance -= amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.collateral.get_unchecked(xlm_pool_index), @@ -352,7 +352,7 @@ fn test_wasm_happy_path() { pool_stable_balance ); merry_stable_btoken_balance -= amount - .fixed_div_floor(reserve_data.b_rate, SCALAR_9) + .fixed_div_floor(reserve_data.b_rate, SCALAR_12) .unwrap(); assert_approx_eq_abs( result.collateral.get_unchecked(stable_pool_index), @@ -376,7 +376,7 @@ fn test_wasm_happy_path() { .pool .claim(&frodo, &vec![&fixture.env, 0, 3], &frodo); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 11673_1666080); + assert_eq!(claim_amount, 11673_1666149); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -404,7 +404,7 @@ fn test_wasm_happy_path() { .pool .claim(&sam, &vec![&fixture.env, 0, 3], &sam); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 90908_8333918); + assert_eq!(claim_amount, 90908_8333849); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -445,7 +445,7 @@ fn test_wasm_happy_path() { .pool .claim(&frodo, &vec![&fixture.env, 0, 3], &frodo); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 1073628_1820163); + assert_eq!(claim_amount, 1073628_1826492); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -456,7 +456,7 @@ fn test_wasm_happy_path() { .pool .claim(&sam, &vec![&fixture.env, 0, 3], &sam); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 8361251_8179829); + assert_eq!(claim_amount, 8361251_8173502); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -464,7 +464,7 @@ fn test_wasm_happy_path() { // Sam repays his STABLE loan let amount = sam_stable_dtoken_balance - .fixed_mul_ceil(1_100_000_000, SCALAR_9) + .fixed_mul_ceil(1_100_000_000_000, SCALAR_12) .unwrap(); let result = pool_fixture.pool.submit( &sam, @@ -481,7 +481,7 @@ fn test_wasm_happy_path() { ); let reserve_data = fixture.read_reserve_data(0, TokenIndex::STABLE); let est_amount = sam_stable_dtoken_balance - .fixed_mul_ceil(reserve_data.d_rate, SCALAR_9) + .fixed_mul_ceil(reserve_data.d_rate, SCALAR_12) .unwrap(); pool_stable_balance += est_amount; sam_stable_balance -= est_amount; @@ -496,7 +496,7 @@ fn test_wasm_happy_path() { // Merry repays his XLM loan let amount = merry_xlm_dtoken_balance - .fixed_mul_ceil(1_250_000_000, SCALAR_9) + .fixed_mul_ceil(1_250_000_000_000, SCALAR_12) .unwrap(); let result = pool_fixture.pool.submit( &merry, @@ -513,7 +513,7 @@ fn test_wasm_happy_path() { ); let reserve_data = fixture.read_reserve_data(0, TokenIndex::XLM); let est_amount = merry_xlm_dtoken_balance - .fixed_mul_ceil(reserve_data.d_rate, SCALAR_9) + .fixed_mul_ceil(reserve_data.d_rate, SCALAR_12) .unwrap(); pool_xlm_balance += est_amount; merry_xlm_balance -= est_amount; @@ -529,7 +529,7 @@ fn test_wasm_happy_path() { // Sam withdraws all of his XLM let reserve_data = fixture.read_reserve_data(0, TokenIndex::XLM); let amount = sam_xlm_btoken_balance - .fixed_mul_ceil(reserve_data.b_rate, SCALAR_9) + .fixed_mul_ceil(reserve_data.b_rate, SCALAR_12) .unwrap(); let result = pool_fixture.pool.submit( &sam, @@ -558,13 +558,13 @@ fn test_wasm_happy_path() { let expected_gulp_amount = 100 * SCALAR_7; stable.mint(&pool_fixture.pool.address, &expected_gulp_amount); let gulp_amount = pool_fixture.pool.gulp(&stable.address); - assert_eq!(gulp_amount, expected_gulp_amount + 147); // 147 stroops from accumlated rounding loss + assert_eq!(gulp_amount, expected_gulp_amount + 4); // 4 stroops from rounding loss pool_stable_balance += expected_gulp_amount; // rounding loss does not effect the b_rate // Merry withdraws all of his STABLE let reserve_data = fixture.read_reserve_data(0, TokenIndex::STABLE); let amount = merry_stable_btoken_balance - .fixed_mul_ceil(reserve_data.b_rate, SCALAR_9) + .fixed_mul_ceil(reserve_data.b_rate, SCALAR_12) .unwrap(); let result = pool_fixture.pool.submit( &merry,