diff --git a/pallets/bidding/src/lib.rs b/pallets/bidding/src/lib.rs index 2b29eb73..fd74af4d 100644 --- a/pallets/bidding/src/lib.rs +++ b/pallets/bidding/src/lib.rs @@ -1,17 +1,17 @@ //! # Bidding pallet //! -//! The Bidding pallet provide functionality to assembble investors and associate them to an +//! The Bidding pallet provides functionality to assembble investors and associate them to an //! onboarded asset //! //! ## Overview //! -//! The pallet check each epoch time if new assets are avalaible to make a bid with an assembled +//! The pallet checks each epoch time if new assets are avalaible to make a bid with an assembled //! list of investors according multiple characteristics //! //! #### Dispatchable Functions //! //! * 'force_process_onboarded_asset' - extrinsic to manually launch the process of onboarded assets -//! * 'process_finalised_assets' - extrinsic to manually launch the process of onboarded assets +//! * 'force_process_onboarded_asset' - extrinsic to manually launch the process of finalised assets //! //! #### Functions //! * 'process_finalised_finalised_assets' - execute the token distribution between investors for the finalised assets @@ -74,21 +74,21 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - // No enough fund for the house + /// Not enough fund for the house HousingFundNotEnough( T::NftCollectionId, T::NftItemId, Housing_Fund::BalanceOf, BlockNumberOf, ), - // The bidding on the house is successful + /// Bidding on the house is successful HouseBiddingSucceeded( T::NftCollectionId, T::NftItemId, Housing_Fund::BalanceOf, BlockNumberOf, ), - // The bidding on the house failed + /// Bidding on the house failed HouseBiddingFailed( T::NftCollectionId, T::NftItemId, @@ -96,7 +96,7 @@ pub mod pallet { BlockNumberOf, Vec<(Housing_Fund::AccountIdOf, Housing_Fund::BalanceOf)>, ), - /// A list of investor cannot be assembled for an onboarded asset + /// Failed to assemble a list of investors for an onboarded asset FailedToAssembleInvestors( T::NftCollectionId, T::NftItemId, @@ -105,7 +105,7 @@ pub mod pallet { ), /// No new onboarded houses found NoHousesOnboardedFound(BlockNumberOf), - /// Selected investors don't have enough to bid for the asset + /// Selected investors don't have enough fund to bid for the asset NotEnoughAmongEligibleInvestors( T::NftCollectionId, T::NftItemId, @@ -153,7 +153,7 @@ use frame_support::pallet_prelude::*; impl Pallet { fn begin_block(now: T::BlockNumber) -> Weight { - let max_block_weight= Weight::from_ref_time(1000_u64); + let max_block_weight = Weight::from_ref_time(1000_u64); if (now % T::NewAssetScanPeriod::get()).is_zero() { Self::process_onboarded_assets().ok(); @@ -163,7 +163,6 @@ impl Pallet { max_block_weight } - /// Process finalised assets to distribute tokens among investors for assets /// Process finalised assets to distribute tokens among investors for assets pub fn process_finalised_assets() -> DispatchResultWithPostInfo { // We retrieve houses with finalised status @@ -173,7 +172,7 @@ impl Pallet { // If no houses are found, an event is raised let block = >::block_number(); Self::deposit_event(Event::NoHousesFinalisedFound(block)); - return Ok(().into()) + return Ok(().into()); } let houses_iter = houses.iter(); @@ -208,85 +207,79 @@ impl Pallet { Ok(().into()) } - /// Process onboarded assets to make make a bid on them and define a investors list /// Process onboarded assets to make make a bid on them and define a investors list pub fn process_onboarded_assets() -> DispatchResultWithPostInfo { let houses = Onboarding::Pallet::::get_onboarded_houses(); + let block_number = >::block_number(); if houses.is_empty() { - let block = >::block_number(); - Self::deposit_event(Event::NoHousesOnboardedFound(block)); - return Ok(().into()) + Self::deposit_event(Event::NoHousesOnboardedFound(block_number)); + return Ok(().into()); } - let houses_iter = houses.iter(); - - for item in houses_iter { + for (collection_id, item_id, house) in houses.into_iter() { // Checks on price format - if item.2.price.is_none() { - continue + if house.price.is_none() { + continue; } - let amount_wrap = Self::convert_balance(item.2.price.unwrap()); + let amount_wrap = Self::convert_balance(house.price.unwrap()); if amount_wrap.is_none() { - continue + continue; } let amount = amount_wrap.unwrap(); - Self::deposit_event(Event::ProcessingAsset(item.0, item.1, amount)); + Self::deposit_event(Event::ProcessingAsset(collection_id, item_id, amount)); // Check if Housing Fund has enough fund for the asset if !Housing_Fund::Pallet::::check_available_fund(amount) { - let block = >::block_number(); - Self::deposit_event(Event::HousingFundNotEnough(item.0, item.1, amount, block)); - continue + Self::deposit_event(Event::HousingFundNotEnough(collection_id, item_id, amount, block_number)); + continue; } // Retrives the ivestors list and their contributions - let investors_shares = Self::create_investor_list(amount); + let investor_shares = Self::create_investor_list(amount); // Checki that the investor list creation was successful - if investors_shares.is_empty() { - let block = >::block_number(); + if investor_shares.is_empty() { Self::deposit_event(Event::FailedToAssembleInvestors( - item.0, item.1, amount, block, + collection_id, item_id, amount, block_number, )); - continue + continue; } Self::deposit_event(Event::InvestorListCreationSuccessful( - item.0, - item.1, + collection_id, + item_id, amount, - investors_shares.clone(), + investor_shares.clone(), )); let result = Housing_Fund::Pallet::::house_bidding( - item.0, - item.1, + collection_id, + item_id, amount, - investors_shares.clone(), + investor_shares.clone(), ); - let block_number = >::block_number(); match result { Ok(_) => { Self::deposit_event(Event::HouseBiddingSucceeded( - item.0, - item.1, + collection_id, + item_id, amount, block_number, )); }, Err(_e) => { Self::deposit_event(Event::HouseBiddingFailed( - item.0, - item.1, + collection_id, + item_id, amount, block_number, - investors_shares, + investor_shares, )); - continue + continue; }, } @@ -297,7 +290,7 @@ impl Pallet { } /// Create the list of investor and their contribution for a given asset's price - /// It follows the rules: + /// It follows the following rules: /// - the oldest contribution comes first /// - no more than T::MaximumSharePerInvestor share per investor /// - no less than T::MinimumSharePerInvestor share per investor @@ -316,17 +309,17 @@ impl Pallet { // We check that the total amount of the contributions allow to buy the asset // And that the minimum number of investors is ok - if contributions.0 < amount || - contributions_length < - (percent / - Self::u64_to_balance_option(T::MaximumSharePerInvestor::get()).unwrap()) + if contributions.0 < amount + || contributions_length + < (percent + / Self::u64_to_balance_option(T::MaximumSharePerInvestor::get()).unwrap()) { - return result + return result; } // We have at least more than the maximum possible investors - if contributions_length >= - (percent / Self::u64_to_balance_option(T::MinimumSharePerInvestor::get()).unwrap()) + if contributions_length + >= (percent / Self::u64_to_balance_option(T::MinimumSharePerInvestor::get()).unwrap()) { result = Self::get_common_investor_distribution( amount, @@ -335,8 +328,8 @@ impl Pallet { ); } // We have the minimum of investors - else if contributions_length == - (percent / Self::u64_to_balance_option(T::MaximumSharePerInvestor::get()).unwrap()) + else if contributions_length + == (percent / Self::u64_to_balance_option(T::MaximumSharePerInvestor::get()).unwrap()) { result = Self::get_common_investor_distribution( amount, @@ -404,23 +397,23 @@ impl Pallet { } else if item.1 >= actual_percentage { // The current account is given a median share as its maximum available share will // break the distribution rule - item_share = actual_percentage / - Self::u64_to_balance_option(contributions_length - count + 1).unwrap(); + item_share = actual_percentage + / Self::u64_to_balance_option(contributions_length - count + 1).unwrap(); } else { // We calculate what is the share if a median rule is applied on the actual // contribution and the remaining ones - let share_median_diff = (actual_percentage - item.1) / - Self::u64_to_balance_option(contributions_length - count).unwrap(); + let share_median_diff = (actual_percentage - item.1) + / Self::u64_to_balance_option(contributions_length - count).unwrap(); // We check that the distribution between accounts will respect rules if the maximum // available share is given to the current account - if share_median_diff < - Self::u64_to_balance_option(T::MinimumSharePerInvestor::get()).unwrap() + if share_median_diff + < Self::u64_to_balance_option(T::MinimumSharePerInvestor::get()).unwrap() { // The current account is given a median share as its maximum available share // will break the distribution rule - item_share = actual_percentage / - Self::u64_to_balance_option(contributions_length - count + 1).unwrap(); + item_share = actual_percentage + / Self::u64_to_balance_option(contributions_length - count + 1).unwrap(); } else { // The account is given its maximum available share as the remaining // contributions will follow the min-max rule @@ -435,7 +428,7 @@ impl Pallet { count += 1; if actual_percentage == zero_percent { - break + break; } } @@ -457,7 +450,7 @@ impl Pallet { Housing_Fund::BalanceOf, )> = Vec::new(); let contributions = Housing_Fund::Pallet::::get_contributions(); - let mut ordered_accountid_list: Vec> = Vec::new(); + let mut ordered_account_id_list: Vec> = Vec::new(); let mut ordered_contributions: Vec<( Housing_Fund::AccountIdOf, Housing_Fund::Contribution, @@ -466,23 +459,21 @@ impl Pallet { let mut total_share: Housing_Fund::BalanceOf = Self::u64_to_balance_option(0).unwrap(); // the contributions are ordered by block number ascending order - for _i in 0..contributions.len() { + for _ in 0..contributions.len() { let oldest_contribution = Self::get_oldest_contribution( - ordered_accountid_list.clone(), + ordered_account_id_list.clone(), contributions.clone(), ); - ordered_accountid_list.push(oldest_contribution.0.clone()); + ordered_account_id_list.push(oldest_contribution.0.clone()); ordered_contributions.push(oldest_contribution.clone()); } - let contributions_iter = ordered_contributions.iter(); - // Add only contribution matching the minimum share contribution condition - for item in contributions_iter { - let share = Self::get_investor_share(amount, item.1.clone()); - if share.0 > zero_percent { - result.push((item.0.clone(), share.0, share.1)); - total_share += share.1; + for (account_id, contribution) in ordered_contributions.into_iter() { + let (share, value) = Self::get_investor_share(amount, contribution.clone()); + if share > zero_percent { + result.push((account_id, share, value)); + total_share += value; } } @@ -528,16 +519,16 @@ impl Pallet { let mut value: Housing_Fund::BalanceOf = Self::u64_to_balance_option(0).unwrap(); // If the available amount is greater than the maximum amount, then the maximum amount is // returned - if contribution.available_balance >= - Self::get_amount_percentage(amount, T::MaximumSharePerInvestor::get()) + if contribution.available_balance + >= Self::get_amount_percentage(amount, T::MaximumSharePerInvestor::get()) { share = Self::u64_to_balance_option(T::MaximumSharePerInvestor::get()).unwrap(); value = Self::get_amount_percentage(amount, T::MaximumSharePerInvestor::get()); } // If the avalable amount is greater than the minimum but less than the maximum amount then // the share is calculated as a percentage - else if contribution.available_balance >= - Self::get_amount_percentage(amount, T::MinimumSharePerInvestor::get()) + else if contribution.available_balance + >= Self::get_amount_percentage(amount, T::MinimumSharePerInvestor::get()) { share = contribution.available_balance * Self::u64_to_balance_option(100).unwrap() / amount; @@ -551,8 +542,8 @@ impl Pallet { amount: Housing_Fund::BalanceOf, percentage: u64, ) -> Housing_Fund::BalanceOf { - amount * Self::u64_to_balance_option(percentage).unwrap() / - Self::u64_to_balance_option(100).unwrap() + amount * Self::u64_to_balance_option(percentage).unwrap() + / Self::u64_to_balance_option(100).unwrap() } fn convert_balance(amount: Onboarding::BalanceOf) -> Option> { diff --git a/pallets/housing_fund/src/functions.rs b/pallets/housing_fund/src/functions.rs index 129484ac..7d8dc368 100644 --- a/pallets/housing_fund/src/functions.rs +++ b/pallets/housing_fund/src/functions.rs @@ -18,13 +18,12 @@ impl Pallet { pub fn get_contribution_share() -> Vec> { let mut contribution_shares = Vec::>::new(); let amount = FundBalance::::get().total; - let contributions_iter = Contributions::::iter(); let factor = Self::u64_to_balance_option(PERCENT_FACTOR); - for item in contributions_iter { - let share = factor.unwrap() * (item.1.clone().get_total_balance()) / amount; + for (account_id, contribution) in Contributions::::iter() { + let share = factor.unwrap() * (contribution.clone().get_total_balance()) / amount; contribution_shares.push(ContributionShare { - account_id: item.1.account_id.clone(), + account_id, share: Self::balance_to_u32_option(share).unwrap(), }); } @@ -64,22 +63,20 @@ impl Pallet { ); // Checks that each contribution is possible - let contribution_iter = contributions.iter(); - let mut contribution_list = Vec::new(); - for item in contribution_iter { - let entry = Contributions::::get(item.0.clone()); + for (account_id, balance) in contributions.into_iter() { + let entry = Contributions::::get(account_id.clone()); ensure!(entry.is_some(), Error::::NotAContributor); - ensure!(entry.unwrap().can_reserve(item.1), Error::::NotEnoughAvailableBalance); + ensure!(entry.unwrap().can_reserve(balance), Error::::NotEnoughAvailableBalance); - Contributions::::mutate(item.0.clone(), |val| { + Contributions::::mutate(account_id.clone(), |val| { let mut unwrap_val = val.clone().unwrap(); - unwrap_val.reserve_amount(item.1); + unwrap_val.reserve_amount(balance); let contribution = unwrap_val.clone(); *val = Some(contribution); }); - contribution_list.push((item.0.clone(), item.1)); + contribution_list.push((account_id.clone(), balance)); } // The amount is tagged as reserved in the fund for the account_id @@ -117,7 +114,7 @@ impl Pallet { } pub fn get_contributions() -> Vec<(AccountIdOf, Contribution)> { - Contributions::::iter().map(|elt| (elt.0, elt.1)).collect() + Contributions::::iter().map(|(account_id, contribution)| (account_id, contribution)).collect() } /// Cancel a house bidding @@ -133,12 +130,10 @@ impl Pallet { let reservation = reservation_wrap.unwrap(); - let contributions_iter = reservation.contributions.iter(); - - for item in contributions_iter { - Contributions::::mutate(item.0.clone(), |val| { + for (account_id, balance) in reservation.contributions.into_iter() { + Contributions::::mutate(account_id.clone(), |val| { let mut unwrap_val = val.clone().unwrap(); - unwrap_val.unreserve_amount(item.1); + unwrap_val.unreserve_amount(balance); let contribution = unwrap_val.clone(); *val = Some(contribution); }); @@ -211,13 +206,11 @@ impl Pallet { let reservation = reservation_wrap.unwrap(); - let contributions_iter = reservation.contributions.iter(); - // We tag the reserved amount in the contribution as used - for item in contributions_iter { - Contributions::::mutate(item.0.clone(), |val| { + for (account_id, balance) in reservation.clone().contributions.into_iter() { + Contributions::::mutate(account_id.clone(), |val| { let mut unwrap_val = val.clone().unwrap(); - unwrap_val.use_reserved_amount(item.1); + unwrap_val.use_reserved_amount(balance); let contribution = unwrap_val.clone(); *val = Some(contribution); }); diff --git a/pallets/onboarding/src/functions.rs b/pallets/onboarding/src/functions.rs index 21b305d3..bbe88ab6 100644 --- a/pallets/onboarding/src/functions.rs +++ b/pallets/onboarding/src/functions.rs @@ -44,9 +44,9 @@ impl Pallet { pub fn status(collection: NftCollectionOf, item_id: T::NftItemId, status: AssetStatus) { let collection_id: T::NftCollectionId = collection.clone().value().into(); Houses::::mutate(collection_id, item_id, |val| { - let mut v0 = val.clone().unwrap(); - v0.status = status; - *val = Some(v0); + let mut asset = val.clone().unwrap(); + asset.status = status; + *val = Some(asset); }); } @@ -84,8 +84,8 @@ impl Pallet { _infos: Asset, ) -> DispatchResult { let collection_id: T::NftCollectionId = collection.clone().value().into(); - let origin: OriginFor = frame_system::RawOrigin::Root.into(); - let origin2: OriginFor = frame_system::RawOrigin::Signed(buyer.clone()).into(); + let origin_root: OriginFor = frame_system::RawOrigin::Root.into(); + let origin_buyer: OriginFor = frame_system::RawOrigin::Signed(buyer.clone()).into(); //Check that the house item exists and has the correct status ensure!( @@ -117,7 +117,7 @@ impl Pallet { ExistenceRequirement::KeepAlive, )?; let to = T::Lookup::unlookup(buyer.clone()); - Nft::Pallet::::transfer(origin, collection, item_id, to)?; + Nft::Pallet::::transfer(origin_root, collection, item_id, to)?; Self::deposit_event(Event::TokenSold { owner, buyer, @@ -127,7 +127,7 @@ impl Pallet { }); //change status - Self::change_status(origin2, collection, item_id, AssetStatus::PURCHASED).ok(); + Self::change_status(origin_buyer, collection, item_id, AssetStatus::PURCHASED).ok(); Ok(()) } @@ -159,15 +159,20 @@ impl Pallet { T::FeesAccount::get().into_account_truncating() } + pub fn filter_by_status(status: types::AssetStatus) -> Vec<( + ::NftCollectionId, + ::NftItemId, + types::Asset + )> { + Houses::::iter().filter(|(_, _, house)| house.status == status).map(|(collection_id, item_id, house)| (collection_id, item_id, house)).collect() + } + pub fn get_onboarded_houses() -> Vec<( ::NftCollectionId, ::NftItemId, types::Asset, )> { - Houses::::iter() - .filter(|val| val.2.status == types::AssetStatus::ONBOARDED) - .map(|elt| (elt.0, elt.1, elt.2)) - .collect() + Self::filter_by_status(types::AssetStatus::ONBOARDED) } pub fn get_finalised_houses() -> Vec<( @@ -175,9 +180,6 @@ impl Pallet { ::NftItemId, types::Asset, )> { - Houses::::iter() - .filter(|val| val.2.status == types::AssetStatus::FINALISED) - .map(|elt| (elt.0, elt.1, elt.2)) - .collect() + Self::filter_by_status(types::AssetStatus::FINALISED) } }