diff --git a/pallets/funding/src/functions/3_auction.rs b/pallets/funding/src/functions/3_auction.rs index 664a2e816..f6209527f 100644 --- a/pallets/funding/src/functions/3_auction.rs +++ b/pallets/funding/src/functions/3_auction.rs @@ -252,8 +252,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/6_settlement.rs b/pallets/funding/src/functions/6_settlement.rs index 0adfecaf1..6435062a7 100644 --- a/pallets/funding/src/functions/6_settlement.rs +++ b/pallets/funding/src/functions/6_settlement.rs @@ -146,13 +146,16 @@ 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 ); // Return either the full amount to refund if bid is rejected/project failed, or a partial amount when the wap > paid price - 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)?; @@ -172,14 +175,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, )?; @@ -197,7 +200,8 @@ impl Pallet { project_id, account: bid.bidder, id: bid.id, - ct_amount: bid.final_ct_amount, + final_ct_amount, + final_ct_price }); Ok(()) @@ -208,18 +212,27 @@ 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 = match bid.status { + BidStatus::Accepted => bid.original_ct_amount, + BidStatus::PartiallyAccepted(amount) => amount, + _ => Zero::zero(), + }; + + 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 mut refund_plmc = bid.plmc_bond.saturating_sub(new_plmc_bond); let mut 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 c5edae12d..d39bb4d85 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,14 @@ 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 = match bid.status { + BidStatus::Accepted => bid.original_ct_amount, + BidStatus::PartiallyAccepted(amount) => amount, + _ => Zero::zero(), + }; + + 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 dd0d90198..d820e7280 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -818,7 +818,12 @@ 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 = match bid.status { + BidStatus::Accepted => bid.original_ct_amount, + BidStatus::PartiallyAccepted(amount) => amount, + BidStatus::Rejected => 0u64.into(), + BidStatus::YetUnknown => {panic!("Bid should have a different status than YetUnknown")} + }; 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 9bf816ca0..a65156e25 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -630,7 +630,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, diff --git a/pallets/funding/src/runtime_api.rs b/pallets/funding/src/runtime_api.rs index b3627a544..49041f1aa 100644 --- a/pallets/funding/src/runtime_api.rs +++ b/pallets/funding/src/runtime_api.rs @@ -70,7 +70,22 @@ 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| { + let a_final_ct_amount = match a.status { + BidStatus::YetUnknown => {panic!("Something on-chain went very wrong")} + BidStatus::Accepted => {a.original_ct_amount} + BidStatus::Rejected => {Zero::zero()} + BidStatus::PartiallyAccepted(amount) => {amount} + } ; + + let b_final_ct_amount = match b.status { + BidStatus::YetUnknown => {panic!("Something on-chain went very wrong")} + BidStatus::Accepted => {b.original_ct_amount} + BidStatus::Rejected => {Zero::zero()} + BidStatus::PartiallyAccepted(amount) => {amount} + } ; + 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..74ad1eee8 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -383,8 +383,6 @@ 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,