From b904835aa9ae17cf7e416593178dc1f01d1fa70b Mon Sep 17 00:00:00 2001 From: Juan Ignacio Rios Date: Tue, 30 Jul 2024 12:58:23 +0200 Subject: [PATCH] Remove unnecessary bid fields --- pallets/funding/src/functions/2_evaluation.rs | 10 -------- pallets/funding/src/functions/3_auction.rs | 2 -- .../funding/src/functions/4_contribution.rs | 12 ++------- pallets/funding/src/functions/6_settlement.rs | 25 +++++++++++++------ pallets/funding/src/functions/misc.rs | 10 +++----- .../src/instantiator/chain_interactions.rs | 3 +-- pallets/funding/src/instantiator/types.rs | 6 ----- pallets/funding/src/lib.rs | 11 +++----- pallets/funding/src/runtime_api.rs | 2 +- pallets/funding/src/types.rs | 25 ++++++++++--------- 10 files changed, 41 insertions(+), 65 deletions(-) diff --git a/pallets/funding/src/functions/2_evaluation.rs b/pallets/funding/src/functions/2_evaluation.rs index 76cad32b8..8c5f10acb 100644 --- a/pallets/funding/src/functions/2_evaluation.rs +++ b/pallets/funding/src/functions/2_evaluation.rs @@ -117,7 +117,6 @@ impl Pallet { project_id: ProjectId, usd_amount: BalanceOf, did: Did, - investor_type: InvestorType, whitelisted_policy: Cid, ) -> DispatchResultWithPostInfo { // * Get variables * @@ -142,15 +141,6 @@ impl Pallet { ensure!(total_evaluations_count < T::MaxEvaluationsPerProject::get(), Error::::TooManyProjectParticipations); ensure!(user_evaluations_count < T::MaxEvaluationsPerUser::get(), Error::::TooManyUserParticipations); - // * Calculate new variables * - if investor_type == InvestorType::Retail { - RetailParticipations::::mutate(&did, |project_participations| { - if project_participations.contains(&project_id).not() { - // We don't care if it fails, since it means the user already has access to the max multiplier - let _ = project_participations.try_push(project_id); - } - }); - } let plmc_bond = plmc_usd_price .reciprocal() .ok_or(Error::::BadMath)? diff --git a/pallets/funding/src/functions/3_auction.rs b/pallets/funding/src/functions/3_auction.rs index 7ad20e26c..5b3ee88d0 100644 --- a/pallets/funding/src/functions/3_auction.rs +++ b/pallets/funding/src/functions/3_auction.rs @@ -251,8 +251,6 @@ impl Pallet { status: BidStatus::YetUnknown, original_ct_amount: ct_amount, original_ct_usd_price: ct_usd_price, - final_ct_amount: ct_amount, - final_ct_usd_price: ct_usd_price, funding_asset, funding_asset_amount_locked, multiplier, diff --git a/pallets/funding/src/functions/4_contribution.rs b/pallets/funding/src/functions/4_contribution.rs index d106353dc..f0e5b0d2b 100644 --- a/pallets/funding/src/functions/4_contribution.rs +++ b/pallets/funding/src/functions/4_contribution.rs @@ -78,19 +78,11 @@ impl Pallet { InvestorType::Retail => project_metadata.contributing_ticket_sizes.retail, }; let max_multiplier = match investor_type { - InvestorType::Retail => { - RetailParticipations::::mutate(&did, |project_participations| { - if project_participations.contains(&project_id).not() { - // We don't care if it fails, since it means the user already has access to the max multiplier - let _ = project_participations.try_push(project_id); - } - retail_max_multiplier_for_participations(project_participations.len() as u8) - }) - }, - + InvestorType::Retail => RETAIL_MAX_MULTIPLIER, InvestorType::Professional => PROFESSIONAL_MAX_MULTIPLIER, InvestorType::Institutional => INSTITUTIONAL_MAX_MULTIPLIER, }; + // * Validity checks * ensure!(project_policy == whitelisted_policy, Error::::PolicyMismatch); ensure!(multiplier.into() <= max_multiplier && multiplier.into() > 0u8, Error::::ForbiddenMultiplier); diff --git a/pallets/funding/src/functions/6_settlement.rs b/pallets/funding/src/functions/6_settlement.rs index 5097f016c..2414c8519 100644 --- a/pallets/funding/src/functions/6_settlement.rs +++ b/pallets/funding/src/functions/6_settlement.rs @@ -146,6 +146,8 @@ impl Pallet { ProjectStatus::SettlementStarted(FundingOutcome::Success) => true, _ => false, }; + let wap = project_details.weighted_average_price.ok_or(Error::::ImpossibleState)?; + ensure!( matches!(project_details.status, ProjectStatus::SettlementStarted(..)) || bid.status == BidStatus::Rejected, Error::::SettlementNotStarted @@ -153,7 +155,8 @@ impl Pallet { // Return either the full amount to refund if bid is rejected/project failed, // or a partial amount when the wap > paid price/bid is partially accepted - let (refunded_plmc, refunded_funding_asset_amount) = Self::calculate_refund(&bid, funding_success)?; + let (final_ct_price, final_ct_amount, refunded_plmc, refunded_funding_asset_amount) = + Self::calculate_refund(&bid, funding_success, wap)?; Self::release_participation_bond(project_id, &bid.bidder, refunded_plmc)?; Self::release_funding_asset(project_id, &bid.bidder, refunded_funding_asset_amount, bid.funding_asset)?; @@ -173,14 +176,14 @@ impl Pallet { HoldReason::Participation(project_id).into(), )?; - Self::mint_contribution_tokens(project_id, &bid.bidder, bid.final_ct_amount)?; + Self::mint_contribution_tokens(project_id, &bid.bidder, final_ct_amount)?; Self::create_migration( project_id, &bid.bidder, bid.id, ParticipationType::Bid, - bid.final_ct_amount, + final_ct_amount, plmc_vesting_info.duration, )?; @@ -198,7 +201,8 @@ impl Pallet { project_id, account: bid.bidder, id: bid.id, - ct_amount: bid.final_ct_amount, + final_ct_amount, + final_ct_price, }); Ok(()) @@ -209,18 +213,23 @@ impl Pallet { fn calculate_refund( bid: &BidInfoOf, funding_success: bool, - ) -> Result<(BalanceOf, BalanceOf), DispatchError> { + wap: PriceOf, + ) -> Result<(PriceOf, BalanceOf, BalanceOf, BalanceOf), DispatchError> { + let final_ct_usd_price = if bid.original_ct_usd_price > wap { wap } else { bid.original_ct_usd_price }; + if bid.status == BidStatus::Rejected || !funding_success { - return Ok((bid.plmc_bond, bid.funding_asset_amount_locked)); + return Ok((final_ct_usd_price, Zero::zero(), bid.plmc_bond, bid.funding_asset_amount_locked)); } - let new_ticket_size = bid.final_ct_usd_price.checked_mul_int(bid.final_ct_amount).ok_or(Error::::BadMath)?; + let final_ct_amount = bid.final_ct_amount(); + + let new_ticket_size = final_ct_usd_price.checked_mul_int(final_ct_amount).ok_or(Error::::BadMath)?; let new_plmc_bond = Self::calculate_plmc_bond(new_ticket_size, bid.multiplier)?; let new_funding_asset_amount = Self::calculate_funding_asset_amount(new_ticket_size, bid.funding_asset)?; let refund_plmc = bid.plmc_bond.saturating_sub(new_plmc_bond); let refund_funding_asset = bid.funding_asset_amount_locked.saturating_sub(new_funding_asset_amount); - Ok((refund_plmc, refund_funding_asset)) + Ok((final_ct_usd_price, final_ct_amount, refund_plmc, refund_funding_asset)) } pub fn do_settle_contribution(contribution: ContributionInfoOf, project_id: ProjectId) -> DispatchResult { diff --git a/pallets/funding/src/functions/misc.rs b/pallets/funding/src/functions/misc.rs index 64ec1a954..0ebe00116 100644 --- a/pallets/funding/src/functions/misc.rs +++ b/pallets/funding/src/functions/misc.rs @@ -90,20 +90,14 @@ impl Pallet { let buyable_amount = auction_allocation_size.saturating_sub(bid_token_amount_sum); if buyable_amount.is_zero() { bid.status = BidStatus::Rejected; - bid.final_ct_amount = Zero::zero(); } else if bid.original_ct_amount <= buyable_amount { - if bid.final_ct_usd_price > wap { - bid.final_ct_usd_price = wap; - } bid_token_amount_sum.saturating_accrue(bid.original_ct_amount); - bid.final_ct_amount = bid.original_ct_amount; bid.status = BidStatus::Accepted; DidWithWinningBids::::mutate(project_id, bid.did.clone(), |flag| { *flag = true; }); } else { bid_token_amount_sum.saturating_accrue(buyable_amount); - bid.final_ct_amount = buyable_amount; bid.status = BidStatus::PartiallyAccepted(buyable_amount); DidWithWinningBids::::mutate(project_id, bid.did.clone(), |flag| { *flag = true; @@ -118,7 +112,9 @@ impl Pallet { let total_auction_allocation_usd: BalanceOf = accepted_bids .into_iter() .try_fold(Zero::zero(), |acc: BalanceOf, bid: BidInfoOf| { - bid.final_ct_usd_price.checked_mul_int(bid.final_ct_amount).and_then(|ticket| acc.checked_add(&ticket)) + let final_ct_usd_price = if bid.original_ct_usd_price > wap { wap } else { bid.original_ct_usd_price }; + let final_ct_amount = bid.final_ct_amount(); + final_ct_usd_price.checked_mul_int(final_ct_amount).and_then(|usd_ticket| acc.checked_add(&usd_ticket)) }) .ok_or(Error::::BadMath)?; diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 7a1274280..f028607ed 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -443,7 +443,6 @@ impl< project_id, usd_amount, generate_did_from_account(account), - InvestorType::Professional, project_policy.clone(), ) })?; @@ -816,7 +815,7 @@ impl< for bid in bids { let account = bid.bidder.clone(); assert_eq!(self.execute(|| { Bids::::iter_prefix_values((&project_id, &account)).count() }), 0); - let amount: BalanceOf = if is_successful { bid.final_ct_amount } else { 0u64.into() }; + let amount: BalanceOf = bid.final_ct_amount(); self.assert_migration(project_id, account, amount, bid.id, ParticipationType::Bid, is_successful); } } diff --git a/pallets/funding/src/instantiator/types.rs b/pallets/funding/src/instantiator/types.rs index 738c8a720..6ffe55041 100644 --- a/pallets/funding/src/instantiator/types.rs +++ b/pallets/funding/src/instantiator/types.rs @@ -399,12 +399,6 @@ impl BidInfoFilter { if self.original_ct_usd_price.is_some() && self.original_ct_usd_price.unwrap() != bid.original_ct_usd_price { return false; } - if self.final_ct_amount.is_some() && self.final_ct_amount.unwrap() != bid.final_ct_amount { - return false; - } - if self.final_ct_usd_price.is_some() && self.final_ct_usd_price.unwrap() != bid.final_ct_usd_price { - return false; - } if self.funding_asset.is_some() && self.funding_asset.unwrap() != bid.funding_asset { return false; } diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index 3d40779dd..dd0a01b98 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -521,10 +521,6 @@ pub mod pallet { BalanceOf, ValueQuery, >; - #[pallet::storage] - // After 25 participations, the retail user has access to the max multiplier of 10x, so no need to keep tracking it - pub type RetailParticipations = - StorageMap<_, Blake2_128Concat, Did, BoundedVec, ValueQuery>; #[pallet::storage] pub type UserMigrations = StorageNMap< @@ -629,7 +625,8 @@ pub mod pallet { project_id: ProjectId, account: AccountIdOf, id: u32, - ct_amount: BalanceOf, + final_ct_amount: BalanceOf, + final_ct_price: PriceOf, }, ContributionSettled { project_id: ProjectId, @@ -869,10 +866,10 @@ pub mod pallet { project_id: ProjectId, #[pallet::compact] usd_amount: BalanceOf, ) -> DispatchResultWithPostInfo { - let (account, did, investor_type, whitelisted_policy) = + let (account, did, _investor_type, whitelisted_policy) = T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?; - Self::do_evaluate(&account, project_id, usd_amount, did, investor_type, whitelisted_policy) + Self::do_evaluate(&account, project_id, usd_amount, did, whitelisted_policy) } #[pallet::call_index(5)] diff --git a/pallets/funding/src/runtime_api.rs b/pallets/funding/src/runtime_api.rs index b3627a544..a729ff1dc 100644 --- a/pallets/funding/src/runtime_api.rs +++ b/pallets/funding/src/runtime_api.rs @@ -70,7 +70,7 @@ impl Pallet { pub fn top_bids(project_id: ProjectId, amount: u32) -> Vec> { Bids::::iter_prefix_values((project_id,)) - .sorted_by(|a, b| b.final_ct_amount.cmp(&a.final_ct_amount)) + .sorted_by(|a, b| b.final_ct_amount().cmp(&a.final_ct_amount())) .take(amount as usize) .collect_vec() } diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index 15aa6f2c2..1b37b1011 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -149,22 +149,14 @@ pub mod config_types { } } - pub type MaxParticipationsForMaxMultiplier = ConstU32<25>; - pub const fn retail_max_multiplier_for_participations(participations: u8) -> u8 { - match participations { - 0..=2 => 1, - 3..=4 => 2, - 5..=9 => 4, - 10..=24 => 7, - 25..=u8::MAX => 10, - } - } + pub const RETAIL_MAX_MULTIPLIER: u8 = 5u8; pub const PROFESSIONAL_MAX_MULTIPLIER: u8 = 10u8; pub const INSTITUTIONAL_MAX_MULTIPLIER: u8 = 25u8; } pub mod storage_types { use super::*; + use sp_runtime::traits::Zero; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Serialize, Deserialize)] pub struct ProjectMetadata { @@ -383,14 +375,23 @@ pub mod storage_types { #[codec(compact)] pub original_ct_amount: Balance, pub original_ct_usd_price: Price, - pub final_ct_amount: Balance, - pub final_ct_usd_price: Price, pub funding_asset: AcceptedFundingAsset, pub funding_asset_amount_locked: Balance, pub multiplier: Multiplier, pub plmc_bond: Balance, pub when: BlockNumber, } + impl + BidInfo + { + pub fn final_ct_amount(&self) -> Balance { + match self.status { + BidStatus::Accepted => self.original_ct_amount, + BidStatus::PartiallyAccepted(amount) => amount, + _ => Zero::zero(), + } + } + } impl< ProjectId: Eq,