diff --git a/pallets/apollo-platform/src/benchmarking.rs b/pallets/apollo-platform/src/benchmarking.rs index f2d49aab51..8f32494ab2 100644 --- a/pallets/apollo-platform/src/benchmarking.rs +++ b/pallets/apollo-platform/src/benchmarking.rs @@ -62,6 +62,8 @@ fn setup_benchmark() -> Result<(), &'static str> { let dai_owner: T::AccountId = assets::AssetOwners::::get::(DAI.into()).unwrap(); let ceres_owner: T::AccountId = assets::AssetOwners::::get::(CERES_ASSET_ID.into()).unwrap(); + let apollo_owner: T::AccountId = + assets::AssetOwners::::get::(APOLLO_ASSET_ID.into()).unwrap(); // Register assets Assets::::register_asset_id( @@ -77,19 +79,6 @@ fn setup_benchmark() -> Result<(), &'static str> { ) .unwrap(); - Assets::::register_asset_id( - owner.clone(), - APOLLO_ASSET_ID.into(), - AssetSymbol(b"APOLLO".to_vec()), - AssetName(b"Apollo".to_vec()), - DEFAULT_BALANCE_PRECISION, - Balance::from(0u32), - true, - None, - None, - ) - .unwrap(); - // Mint assets to Alice Assets::::mint( RawOrigin::Signed(xor_owner).into(), @@ -116,7 +105,7 @@ fn setup_benchmark() -> Result<(), &'static str> { .unwrap(); Assets::::mint( - owner_origin.clone(), + RawOrigin::Signed(apollo_owner.clone()).into(), APOLLO_ASSET_ID.into(), owner.clone(), balance!(500), @@ -124,7 +113,7 @@ fn setup_benchmark() -> Result<(), &'static str> { .unwrap(); Assets::::mint( - owner_origin.clone(), + RawOrigin::Signed(apollo_owner).into(), APOLLO_ASSET_ID.into(), pallet_account, balance!(100000), @@ -268,6 +257,8 @@ benchmarks! { let lending_amount = balance!(100); + setup_benchmark::()?; + ApolloPlatform::::add_pool( RawOrigin::Signed(caller).into(), asset_id.into(), @@ -286,7 +277,7 @@ benchmarks! { lending_amount ).unwrap() } verify { - assert_last_event::(Event::Lended(alice, asset_id.into(), lending_amount).into()); + assert_last_event::(Event::Lent(alice, asset_id.into(), lending_amount).into()); } borrow { @@ -306,7 +297,7 @@ benchmarks! { let lending_amount_alice = balance!(300); let lending_amount_bob = balance!(200000); - let collateral_amount = balance!(101.00000000000000001); + let collateral_amount = balance!(99.009900990099009999); let borrow_amount = balance!(100); setup_benchmark::()?; @@ -720,4 +711,38 @@ benchmarks! { verify { assert_last_event::(Event::PoolRemoved(caller, asset_id.into()).into()); } + + edit_pool_info { + let caller = pallet::AuthorityAccount::::get(); + let asset_id = XOR; + let initial_parameter_value = balance!(1); + let edit_parameter_value = balance!(0.8); + + ApolloPlatform::::add_pool( + RawOrigin::Signed(caller.clone()).into(), + asset_id.into(), + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + ).unwrap(); + }: { + ApolloPlatform::::edit_pool_info( + RawOrigin::Signed(caller.clone()).into(), + asset_id.into(), + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + ).unwrap() + } + verify { + assert_last_event::(Event::PoolInfoEdited(caller, asset_id.into()).into()); + } } diff --git a/pallets/apollo-platform/src/lib.rs b/pallets/apollo-platform/src/lib.rs index e46a2c3425..ba14664392 100644 --- a/pallets/apollo-platform/src/lib.rs +++ b/pallets/apollo-platform/src/lib.rs @@ -109,7 +109,7 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(PhantomData); - /// Lended asset -> AccountId -> LendingPosition + /// Lent asset -> AccountId -> LendingPosition #[pallet::storage] #[pallet::getter(fn user_lending_info)] pub type UserLendingInfo = StorageDoubleMap< @@ -216,8 +216,8 @@ pub mod pallet { pub enum Event { /// Pool added [who, asset_id] PoolAdded(AccountIdOf, AssetIdOf), - /// Lended [who, asset_id, amount] - Lended(AccountIdOf, AssetIdOf, Balance), + /// Lent [who, asset_id, amount] + Lent(AccountIdOf, AssetIdOf, Balance), /// Borrowed [who, collateral_asset, collateral_amount, borrow_asset, borrow_amount] Borrowed(AccountIdOf, AssetIdOf, Balance, AssetIdOf, Balance), /// ClaimedLendingRewards [who, asset_id, amount] @@ -236,6 +236,8 @@ pub mod pallet { Liquidated(AccountIdOf, AssetIdOf), /// Pool removed [who, asset_id] PoolRemoved(AccountIdOf, AssetIdOf), + /// Pool info edited [who, asset_id] + PoolInfoEdited(AccountIdOf, AssetIdOf), } #[pallet::error] @@ -248,7 +250,7 @@ pub mod pallet { InvalidPoolParameters, /// Pool does not exist PoolDoesNotExist, - /// The amount that is being lended is invalid + /// The amount that is being lent is invalid InvalidLendingAmount, /// Collateral token does not exists CollateralTokenDoesNotExist, @@ -258,8 +260,8 @@ pub mod pallet { SameCollateralAndBorrowingAssets, /// No liquidity for borrowing asset NoLiquidityForBorrowingAsset, - /// Nothing lended - NothingLended, + /// Nothing lent + NothingLent, /// Invalid collateral amount InvalidCollateralAmount, /// Can not transfer borrowing amount @@ -458,7 +460,7 @@ pub mod pallet { pool_info.total_liquidity += lending_amount; >::insert(lending_asset, pool_info); - Self::deposit_event(Event::Lended(user, lending_asset, lending_amount)); + Self::deposit_event(Event::Lent(user, lending_asset, lending_amount)); Ok(().into()) } @@ -501,7 +503,7 @@ pub mod pallet { >::get(collateral_asset).ok_or(Error::::PoolDoesNotExist)?; ensure!(!collateral_pool_info.is_removed, Error::::PoolIsRemoved); let mut user_lending_info = >::get(collateral_asset, user.clone()) - .ok_or(Error::::NothingLended)?; + .ok_or(Error::::NothingLent)?; let collateral_asset_price = Self::get_price(collateral_asset); // Calculate required collateral asset in dollars @@ -609,10 +611,10 @@ pub mod pallet { let block_number = >::block_number(); let pool_info = PoolData::::get(asset_id).ok_or(Error::::PoolDoesNotExist)?; - // Check if user has lended or borrowed rewards + // Check if user has lent or borrowed rewards if is_lending { let mut lend_user_info = >::get(asset_id, user.clone()) - .ok_or(Error::::NothingLended)?; + .ok_or(Error::::NothingLent)?; let interests = Self::calculate_lending_earnings(&lend_user_info, &pool_info, block_number); lend_user_info.lending_interest += interests.0 + interests.1; @@ -693,7 +695,7 @@ pub mod pallet { let mut pool_info = >::get(withdrawn_asset).ok_or(Error::::PoolDoesNotExist)?; let mut user_info = >::get(withdrawn_asset, user.clone()) - .ok_or(Error::::NothingLended)?; + .ok_or(Error::::NothingLent)?; ensure!( withdrawn_amount <= user_info.lending_amount, @@ -776,6 +778,9 @@ pub mod pallet { user_info.borrowing_rewards += interest_and_reward.1; user_info.last_borrowing_block = block_number; + // Total repaid + let mut total_repaid: Balance = amount_to_repay; + if amount_to_repay <= user_info.borrowing_interest { // If user is repaying only part or whole interest user_info.borrowing_interest = @@ -878,9 +883,12 @@ pub mod pallet { user_info.borrowing_interest, borrowing_asset, )?; + + // Updating total repaid + total_repaid = total_borrowed_amount; } - Self::deposit_event(Event::Repaid(user, borrowing_asset, amount_to_repay)); + Self::deposit_event(Event::Repaid(user, borrowing_asset, total_repaid)); Ok(().into()) } @@ -971,27 +979,76 @@ pub mod pallet { return Err(Error::::InvalidLiquidation.into()); } - // Distribute liquidated collaterals to users and reserves + // Calculate total borrow and total collateral in dollars let mut total_borrowed: Balance = 0; + + // Distributing and calculating total borrwed for (collateral_asset, user_info) in user_infos.iter() { + // Calculate collateral in dollars + let collateral_asset_price = Self::get_price(*collateral_asset); + let collateral_amount_in_dollars = + (FixedWrapper::from(user_info.collateral_amount) + * FixedWrapper::from(collateral_asset_price)) + .try_into_balance() + .unwrap_or(0); + + // Calculate user's borrowed amount + let borrow_asset_price = Self::get_price(asset_id); + let user_borrowed_in_dollars = (FixedWrapper::from(user_info.borrowing_amount) + * FixedWrapper::from(borrow_asset_price)) + .try_into_balance() + .unwrap_or(0); + + // Calculating amount to distribute in dollars and converting to collateral token amount + let amount_to_distribute_in_dollars = + collateral_amount_in_dollars.saturating_sub(user_borrowed_in_dollars); + let amount_to_distribute = (FixedWrapper::from(amount_to_distribute_in_dollars) + / FixedWrapper::from(collateral_asset_price)) + .try_into_balance() + .unwrap_or(0); + + // Distributing the amount calculated as sufficit of collateral asset in dollars over borrowed amount in dollars let _ = Self::distribute_protocol_interest( *collateral_asset, - user_info.collateral_amount, + amount_to_distribute, asset_id, ); + + // Amount to exchange + let amount_to_exchange = (FixedWrapper::from(user_borrowed_in_dollars) + / FixedWrapper::from(collateral_asset_price)) + .try_into_balance() + .unwrap_or(0); + + // Exchange collateral asset into borrowed asset on Pallet + T::LiquidityProxyPallet::exchange( + DEXId::Polkaswap.into(), + &Self::account_id(), + &Self::account_id(), + collateral_asset, + &asset_id, + SwapAmount::with_desired_input(amount_to_exchange, Balance::zero()), + LiquiditySourceFilter::empty(DEXId::Polkaswap.into()), + )?; + + // Updating collateral pool total_collateral amount and total_liquidity let mut collateral_pool_info = PoolData::::get(*collateral_asset).unwrap_or_default(); collateral_pool_info.total_collateral = collateral_pool_info .total_collateral .saturating_sub(user_info.collateral_amount); - total_borrowed += user_info.borrowing_amount; + >::insert(*collateral_asset, collateral_pool_info); + // Add user's borrowed amount tied with this asset to total_borrowed in given asset + total_borrowed += user_info.borrowing_amount; } + // Updating total_borrowed and total_liquidity for given asset let mut borrow_pool_info = PoolData::::get(asset_id).unwrap_or_default(); borrow_pool_info.total_borrowed = borrow_pool_info .total_borrowed .saturating_sub(total_borrowed); + borrow_pool_info.total_liquidity += total_borrowed; >::insert(asset_id, borrow_pool_info); >::remove(asset_id, user.clone()); @@ -1047,6 +1104,56 @@ pub mod pallet { Self::deposit_event(Event::PoolRemoved(user, asset_id_to_remove)); Ok(()) } + + /// Edit pool info + #[pallet::call_index(10)] + #[pallet::weight(::WeightInfo::edit_pool_info())] + pub fn edit_pool_info( + origin: OriginFor, + asset_id: AssetIdOf, + new_loan_to_value: Balance, + new_liquidation_threshold: Balance, + new_optimal_utilization_rate: Balance, + new_base_rate: Balance, + new_slope_rate_1: Balance, + new_slope_rate_2: Balance, + new_reserve_factor: Balance, + ) -> DispatchResult { + let user = ensure_signed(origin)?; + + if user != AuthorityAccount::::get() { + return Err(Error::::Unauthorized.into()); + } + + // Check parameters + if new_loan_to_value > balance!(1) + || new_liquidation_threshold > balance!(1) + || new_optimal_utilization_rate > balance!(1) + || new_reserve_factor > balance!(1) + { + return Err(Error::::InvalidPoolParameters.into()); + } + + let mut pool_info = PoolData::::get(asset_id).ok_or(Error::::PoolDoesNotExist)?; + + // Check if pool is removed + ensure!(!pool_info.is_removed, Error::::PoolIsRemoved); + + // Update pool info + pool_info.loan_to_value = new_loan_to_value; + pool_info.liquidation_threshold = new_liquidation_threshold; + pool_info.optimal_utilization_rate = new_optimal_utilization_rate; + pool_info.base_rate = new_base_rate; + pool_info.slope_rate_1 = new_slope_rate_1; + pool_info.slope_rate_2 = new_slope_rate_2; + pool_info.reserve_factor = new_reserve_factor; + + // Saving new pool info + >::insert(asset_id, pool_info); + + Self::deposit_event(Event::PoolInfoEdited(user, asset_id)); + Ok(()) + } } /// Validate unsigned call to this pallet. @@ -1300,6 +1407,15 @@ pub mod pallet { .try_into_balance() .unwrap_or(0); + // Transfer amount to developer fund + Assets::::transfer_from( + &asset_id, + &Self::account_id(), + &AuthorityAccount::::get(), + developer_amount, + ) + .map_err(|_| Error::::CanNotTransferAmountToDevelopers)?; + // Transfer APOLLO to treasury T::LiquidityProxyPallet::exchange( DEXId::Polkaswap.into(), @@ -1329,15 +1445,6 @@ pub mod pallet { outcome.amount, )?; - // Transfer amount to developer fund - Assets::::transfer_from( - &asset_id, - &Self::account_id(), - &AuthorityAccount::::get(), - developer_amount, - ) - .map_err(|_| Error::::CanNotTransferAmountToDevelopers)?; - Ok(().into()) } diff --git a/pallets/apollo-platform/src/mock.rs b/pallets/apollo-platform/src/mock.rs index 6ae2f876a5..decda8ddbd 100644 --- a/pallets/apollo-platform/src/mock.rs +++ b/pallets/apollo-platform/src/mock.rs @@ -455,13 +455,22 @@ impl LiquidityProxyTrait for MockLiquidityProxy { amount.amount(), ); - // Transfer from exchange account (output asset) - let _ = Assets::transfer( - RawOrigin::Signed(exchange_account()).into(), - *output_asset_id, - receiver.clone(), - amount.amount(), - ); + if input_asset_id == &DAI && output_asset_id != &APOLLO_ASSET_ID { + let _ = Assets::transfer( + RawOrigin::Signed(exchange_account()).into(), + *output_asset_id, + receiver.clone(), + amount.amount() * balance!(0.1) / balance!(1), + ); + } else { + // Transfer from exchange account (output asset) + let _ = Assets::transfer( + RawOrigin::Signed(exchange_account()).into(), + *output_asset_id, + receiver.clone(), + amount.amount(), + ); + } Ok(SwapOutcome::new(amount.amount(), Default::default())) } diff --git a/pallets/apollo-platform/src/tests.rs b/pallets/apollo-platform/src/tests.rs index c20de91f25..1f6840c70c 100644 --- a/pallets/apollo-platform/src/tests.rs +++ b/pallets/apollo-platform/src/tests.rs @@ -828,7 +828,7 @@ mod test { } #[test] - fn borrow_nothing_lended() { + fn borrow_nothing_lent() { let mut ext = ExtBuilder::default().build(); ext.execute_with(|| { assert_ok!(assets::Pallet::::mint_to( @@ -872,7 +872,7 @@ mod test { assert_err!( ApolloPlatform::borrow(RuntimeOrigin::signed(alice()), DOT, XOR, balance!(100)), - Error::::NothingLended + Error::::NothingLent ); }); } @@ -1258,7 +1258,7 @@ mod test { } #[test] - fn get_lending_rewards_nothing_lended() { + fn get_lending_rewards_nothing_lent() { let mut ext = ExtBuilder::default().build(); ext.execute_with(|| { assert_ok!(ApolloPlatform::add_pool( @@ -1275,7 +1275,7 @@ mod test { assert_err!( ApolloPlatform::get_rewards(RuntimeOrigin::signed(alice()), XOR, true), - Error::::NothingLended + Error::::NothingLent ); }); } @@ -1855,7 +1855,7 @@ mod test { } #[test] - fn withdraw_nothing_lended() { + fn withdraw_nothing_lent() { let mut ext = ExtBuilder::default().build(); ext.execute_with(|| { assert_ok!(ApolloPlatform::add_pool( @@ -1872,7 +1872,7 @@ mod test { assert_err!( ApolloPlatform::withdraw(RuntimeOrigin::signed(alice()), XOR, balance!(100)), - Error::::NothingLended + Error::::NothingLent ); }); } @@ -2457,27 +2457,27 @@ mod test { let borrowing_interest_one_more_block = calculate_borrowing_interest(alice(), XOR, DOT, 150); - let repayed_amount = borrowing_interest_one_more_block.0; + let repaid_amount = borrowing_interest_one_more_block.0; // Reserve amounts (treasury, burn, developer) let (treasury_reserve, _, developer_reserve) = - calculate_reserve_amounts(XOR, repayed_amount); + calculate_reserve_amounts(XOR, repaid_amount); assert_ok!(ApolloPlatform::repay( RuntimeOrigin::signed(alice()), DOT, XOR, - repayed_amount + repaid_amount )); // Check borrowing asset pool values after repay let borrowing_asset_pool_info = pallet::PoolData::::get(XOR).unwrap(); let reserves_amount = (FixedWrapper::from(borrowing_asset_pool_info.reserve_factor) - * FixedWrapper::from(repayed_amount)) + * FixedWrapper::from(repaid_amount)) .try_into_balance() .unwrap_or(0); - let rewards_amount = repayed_amount - reserves_amount; + let rewards_amount = repaid_amount - reserves_amount; assert_eq!(borrowing_asset_pool_info.rewards, rewards_amount); assert_eq!(borrowing_asset_pool_info.total_borrowed, balance!(200)); @@ -2488,7 +2488,7 @@ mod test { let borrowing_user_debt = borrow_user_info.get(&DOT).unwrap(); let borrowing_interest = borrowing_user_debt.borrowing_interest; - let new_alice_balance = balance!(200) - repayed_amount; + let new_alice_balance = balance!(200) - repaid_amount; assert_eq!(borrowing_interest, balance!(0)); @@ -2634,7 +2634,7 @@ mod test { let borrowing_interest_one_more_block = calculate_borrowing_interest(alice(), XOR, DOT, 150); - let repayed_amount = borrowing_interest_one_more_block.0 + balance!(1); + let repaid_amount = borrowing_interest_one_more_block.0 + balance!(1); // Reserve amounts (treasury, burn, developer) let (treasury_reserve, _, developer_reserve) = @@ -2644,14 +2644,14 @@ mod test { RuntimeOrigin::signed(alice()), DOT, XOR, - repayed_amount + repaid_amount )); let borrow_user_info = pallet::UserBorrowingInfo::::get(XOR, alice()).unwrap(); let borrowing_user_debt = borrow_user_info.get(&DOT).unwrap(); let borrowing_interest = borrowing_user_debt.borrowing_interest; - let new_alice_balance = balance!(200) - repayed_amount; + let new_alice_balance = balance!(200) - repaid_amount; // Check Alice position values after repay assert_eq!(borrowing_user_debt.borrowing_amount, balance!(199)); @@ -2828,7 +2828,7 @@ mod test { let borrowing_interest_one_more_block = calculate_borrowing_interest(alice(), XOR, DOT, 150); - let repayed_amount = borrowing_interest_one_more_block.0 + balance!(200); + let repaid_amount = borrowing_interest_one_more_block.0 + balance!(200); // Reserve amounts (treasury, burn, developer) let (treasury_reserve, _, developer_reserve) = @@ -2838,7 +2838,7 @@ mod test { RuntimeOrigin::signed(alice()), DOT, XOR, - repayed_amount + repaid_amount )); // Check borrowing asset pool values after repay @@ -2858,7 +2858,7 @@ mod test { let borrow_user_info = pallet::UserBorrowingInfo::::get(XOR, alice()); - let new_alice_balance = balance!(300) - repayed_amount; + let new_alice_balance = balance!(300) - repaid_amount; // Check if Alice's position exists after repay assert_eq!(borrow_user_info, None); @@ -3908,7 +3908,253 @@ mod test { } #[test] - fn liquidate_ok() { + fn liquidate_with_protocol_interest_ok() { + let mut ext = ExtBuilder::default().build(); + ext.execute_with(|| { + static_set_dex(); + init_exchange(); + + assert_ok!(assets::Pallet::::mint_to( + &DOT, + &alice(), + &alice(), + balance!(200) + )); + + assert_ok!(assets::Pallet::::mint_to( + &XOR, + &alice(), + &bob(), + balance!(300000) + )); + + assert_ok!(assets::Pallet::::mint_to( + &DAI, + &alice(), + &alice(), + balance!(10000) + )); + + assert_ok!(ApolloPlatform::add_pool( + RuntimeOrigin::signed(ApolloPlatform::authority_account()), + XOR, + balance!(0.8), + balance!(0.7), + balance!(1), + balance!(1), + balance!(1), + balance!(1), + balance!(0.2), + )); + + assert_ok!(ApolloPlatform::add_pool( + RuntimeOrigin::signed(ApolloPlatform::authority_account()), + DOT, + balance!(0.8), + balance!(0.7), + balance!(1), + balance!(1), + balance!(1), + balance!(1), + balance!(0.2), + )); + + assert_ok!(ApolloPlatform::add_pool( + RuntimeOrigin::signed(ApolloPlatform::authority_account()), + DAI, + balance!(0.8), + balance!(0.7), + balance!(1), + balance!(1), + balance!(1), + balance!(1), + balance!(0.2), + )); + + assert_ok!(ApolloPlatform::lend( + RuntimeOrigin::signed(alice()), + DOT, + balance!(200), + )); + + assert_ok!(ApolloPlatform::lend( + RuntimeOrigin::signed(alice()), + DAI, + balance!(1500), + )); + + assert_ok!(ApolloPlatform::lend( + RuntimeOrigin::signed(bob()), + XOR, + balance!(300000), + )); + + assert_ok!(ApolloPlatform::borrow( + RuntimeOrigin::signed(alice()), + DOT, + XOR, + balance!(100) + )); + + assert_ok!(ApolloPlatform::borrow( + RuntimeOrigin::signed(alice()), + DAI, + XOR, + balance!(100) + )); + + let dot_collateral_asset_pool_info_before_lq = + pallet::PoolData::::get(DOT).unwrap(); + + let dai_collateral_asset_pool_info_before_lq = + pallet::PoolData::::get(DAI).unwrap(); + + let borrowing_pool_before_lq = pallet::PoolData::::get(XOR).unwrap(); + + let borrow_user_info_before_lq = + pallet::UserBorrowingInfo::::get(XOR, alice()).unwrap(); + let borrow_user_info_dot_coll_before_lq = borrow_user_info_before_lq.get(&DOT).unwrap(); + let borrow_user_info_dai_coll_before_lq = borrow_user_info_before_lq.get(&DAI).unwrap(); + + assert_eq!( + borrow_user_info_dot_coll_before_lq.collateral_amount, + balance!(125) + ); + assert_eq!( + borrow_user_info_dai_coll_before_lq.collateral_amount, + balance!(1250) + ); + + assert_eq!(borrowing_pool_before_lq.total_borrowed, balance!(200)); + + assert_eq!( + dot_collateral_asset_pool_info_before_lq.total_collateral, + balance!(125) + ); + + assert_eq!( + dai_collateral_asset_pool_info_before_lq.total_collateral, + balance!(1250) + ); + + assert_eq!( + assets::Pallet::::free_balance(&XOR, &alice()).unwrap(), + balance!(200) + ); + + assert_eq!( + assets::Pallet::::free_balance(&XOR, &get_pallet_account()).unwrap(), + balance!(299800) + ); + + assert_eq!( + assets::Pallet::::free_balance(&DOT, &alice()).unwrap(), + balance!(0) + ); + + assert_eq!( + assets::Pallet::::free_balance(&DOT, &get_pallet_account()).unwrap(), + balance!(200) + ); + + assert_eq!( + assets::Pallet::::free_balance(&DAI, &alice()).unwrap(), + balance!(8500) + ); + + assert_eq!( + assets::Pallet::::free_balance(&DAI, &get_pallet_account()).unwrap(), + balance!(1500) + ); + + assert_ok!(ApolloPlatform::liquidate( + RuntimeOrigin::signed(ApolloPlatform::authority_account()), + alice(), + XOR + )); + + let (treasury_reserve_dot, _, developer_amount_dot) = + calculate_reserve_amounts(DOT, balance!(25)); + + let (treasury_reserve_dai, _, developer_amount_dai) = + calculate_reserve_amounts(DAI, balance!(250)); + + let borrowing_asset_pool_info_after_lq = pallet::PoolData::::get(XOR).unwrap(); + + let dot_collateral_asset_pool_info_after_lq = + pallet::PoolData::::get(DOT).unwrap(); + + let dai_collateral_asset_pool_info_after_lq = + pallet::PoolData::::get(DAI).unwrap(); + + let borrow_user_info_after_lq = pallet::UserBorrowingInfo::::get(XOR, alice()); + + assert_eq!( + assets::Pallet::::free_balance(&XOR, &get_pallet_account()).unwrap(), + balance!(300000) + ); + + assert_eq!( + assets::Pallet::::free_balance(&DAI, &get_pallet_account()).unwrap(), + balance!(250) + ); + + assert_eq!( + dot_collateral_asset_pool_info_after_lq.total_collateral, + balance!(0) + ); + + assert_eq!( + dai_collateral_asset_pool_info_after_lq.total_collateral, + balance!(0) + ); + + assert_eq!( + borrowing_asset_pool_info_after_lq.total_borrowed, + balance!(0) + ); + + assert_eq!( + borrowing_asset_pool_info_after_lq.total_liquidity, + borrowing_pool_before_lq.total_liquidity + borrowing_pool_before_lq.total_borrowed + ); + + assert_eq!( + dai_collateral_asset_pool_info_before_lq.total_liquidity, + dai_collateral_asset_pool_info_after_lq.total_liquidity + ); + + assert_eq!(borrow_user_info_after_lq, None); + + // Treasury + assert_eq!( + assets::Pallet::::free_balance(&APOLLO_ASSET_ID, &get_treasury_account()) + .unwrap(), + treasury_reserve_dot + treasury_reserve_dai + ); + + // Developer / Authority + assert_eq!( + assets::Pallet::::free_balance(&DOT, &get_authority_account()).unwrap(), + developer_amount_dot + ); + + assert_eq!( + assets::Pallet::::free_balance(&DAI, &get_authority_account()).unwrap(), + developer_amount_dai + ); + + // Exchange + assert_eq!( + assets::Pallet::::free_balance(&CERES_ASSET_ID, &exchange_account()) + .unwrap(), + balance!(998) + ); + }); + } + + #[test] + fn liquidate_without_protocol_interest_ok() { let mut ext = ExtBuilder::default().build(); ext.execute_with(|| { static_set_dex(); @@ -4074,10 +4320,10 @@ mod test { )); let (treasury_reserve_dot, _, developer_amount_dot) = - calculate_reserve_amounts(DOT, balance!(100)); + calculate_reserve_amounts(DOT, balance!(0)); let (treasury_reserve_dai, _, developer_amount_dai) = - calculate_reserve_amounts(DAI, balance!(1000)); + calculate_reserve_amounts(DAI, balance!(0)); let borrowing_asset_pool_info_after_lq = pallet::PoolData::::get(XOR).unwrap(); @@ -4104,7 +4350,17 @@ mod test { balance!(0) ); - assert_eq!(borrowing_asset_pool_info_after_lq.rewards, balance!(990)); + assert_eq!(borrowing_asset_pool_info_after_lq.rewards, balance!(0)); + + assert_eq!( + borrowing_asset_pool_info_after_lq.total_liquidity, + borrowing_pool_before_lq.total_liquidity + borrowing_pool_before_lq.total_borrowed + ); + + assert_eq!( + dai_collateral_asset_pool_info_before_lq.total_liquidity, + dai_collateral_asset_pool_info_after_lq.total_liquidity + ); assert_eq!(borrow_user_info_after_lq, None); @@ -4130,7 +4386,7 @@ mod test { assert_eq!( assets::Pallet::::free_balance(&CERES_ASSET_ID, &exchange_account()) .unwrap(), - balance!(978) + balance!(1000) ); }); } @@ -4249,4 +4505,104 @@ mod test { } }); } + + #[test] + fn edit_pool_info_ok() { + let mut ext = ExtBuilder::default().build(); + ext.execute_with(|| { + let user = RuntimeOrigin::signed(ApolloPlatform::authority_account()); + let asset_id = XOR; + let initial_parameter_value = balance!(1); + let edit_parameter_value = balance!(0.8); + + assert_ok!(ApolloPlatform::add_pool( + user.clone(), + asset_id, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + )); + + let pool_info_before_edit = pallet::PoolData::::get(asset_id).unwrap(); + + assert_ok!(ApolloPlatform::edit_pool_info( + user, + asset_id, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + )); + + let pool_info_after_edit = pallet::PoolData::::get(asset_id).unwrap(); + + // Asserting pool info basic lending rate not changed + assert_eq!( + pool_info_before_edit.basic_lending_rate, + pool_info_after_edit.basic_lending_rate + ); + + // Asserting pool info borrowing rewards rate not changed + assert_eq!( + pool_info_before_edit.borrowing_rewards_rate, + pool_info_after_edit.borrowing_rewards_rate + ); + + // Asserting pool info parameters are changed + assert_eq!(pool_info_after_edit.loan_to_value, edit_parameter_value); + assert_eq!( + pool_info_after_edit.optimal_utilization_rate, + edit_parameter_value + ); + assert_eq!(pool_info_after_edit.base_rate, edit_parameter_value); + assert_eq!(pool_info_after_edit.slope_rate_1, edit_parameter_value); + assert_eq!(pool_info_after_edit.slope_rate_2, edit_parameter_value); + assert_eq!(pool_info_after_edit.reserve_factor, edit_parameter_value); + }); + } + + #[test] + fn edit_pool_info_unauthorized() { + let mut ext = ExtBuilder::default().build(); + ext.execute_with(|| { + let user = RuntimeOrigin::signed(ApolloPlatform::authority_account()); + let asset_id = XOR; + let initial_parameter_value = balance!(1); + let edit_parameter_value = balance!(0.8); + + assert_ok!(ApolloPlatform::add_pool( + user, + asset_id, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + initial_parameter_value, + )); + + assert_err!( + ApolloPlatform::edit_pool_info( + RuntimeOrigin::signed(alice()), + asset_id, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + edit_parameter_value, + ), + Error::::Unauthorized + ); + }); + } } diff --git a/pallets/apollo-platform/src/weights.rs b/pallets/apollo-platform/src/weights.rs index f07627b9df..7853e8dd94 100644 --- a/pallets/apollo-platform/src/weights.rs +++ b/pallets/apollo-platform/src/weights.rs @@ -44,6 +44,7 @@ pub trait WeightInfo { fn change_rewards_per_block() -> Weight; fn liquidate() -> Weight; fn remove_pool() -> Weight; + fn edit_pool_info() -> Weight; } /// Weight functions for `apollo_platform`. @@ -275,6 +276,19 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: ApolloPlatform AuthorityAccount (r:1 w:0) + /// Proof Skipped: ApolloPlatform AuthorityAccount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ApolloPlatform PoolData (r:1 w:1) + /// Proof Skipped: ApolloPlatform PoolData (max_values: None, max_size: None, mode: Measured) + fn edit_pool_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `481` + // Estimated: `3932` + // Minimum execution time: 8_660 nanoseconds. + Weight::from_parts(10_127_000, 3932) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } } // For backwards compatibility and tests @@ -505,4 +519,17 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(1)) } + /// Storage: ApolloPlatform AuthorityAccount (r:1 w:0) + /// Proof Skipped: ApolloPlatform AuthorityAccount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ApolloPlatform PoolData (r:1 w:1) + /// Proof Skipped: ApolloPlatform PoolData (max_values: None, max_size: None, mode: Measured) + fn edit_pool_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `481` + // Estimated: `3932` + // Minimum execution time: 8_660 nanoseconds. + Weight::from_parts(10_127_000, 3932) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } } \ No newline at end of file