diff --git a/benchmarked-extrinsics.rs b/benchmarked-extrinsics.rs
new file mode 100644
index 000000000..7a50290bf
--- /dev/null
+++ b/benchmarked-extrinsics.rs
@@ -0,0 +1,155 @@
+// Polimec Blockchain – https://www.polimec.org/
+// Copyright (C) Polimec 2022. All rights reserved.
+
+// The Polimec Blockchain is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// The Polimec Blockchain is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// If you feel like getting in touch with us, you can do so at info@polimec.org
+
+
+//! Autogenerated weights for `pallet_funding`
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 39.0.0
+//! DATE: 2025-02-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `Mac.home`, CPU: ``
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("polimec-paseo-local")`, DB CACHE: `1024`
+
+// Executed Command:
+// target/production/polimec-node
+// benchmark
+// pallet
+// --chain=polimec-paseo-local
+// --steps=50
+// --repeat=20
+// --pallet=pallet-funding
+// --no-storage-info
+// --no-median-slopes
+// --no-min-squares
+// --extrinsic=bid
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=benchmarked-extrinsics.rs
+// --template=./.maintain/frame-weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use core::marker::PhantomData;
+
+/// Weight functions needed for `pallet_funding`.
+pub trait WeightInfo {
+ fn bid(x: u32, ) -> Weight;
+}
+
+/// Weights for `pallet_funding` using the Substrate node and recommended hardware.
+pub struct SubstrateWeight(PhantomData);
+impl WeightInfo for SubstrateWeight {
+ /// Storage: `Timestamp::Now` (r:1 w:0)
+ /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::ProjectsMetadata` (r:1 w:0)
+ /// Proof: `Funding::ProjectsMetadata` (`max_values`: None, `max_size`: Some(437), added: 2912, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::ProjectsDetails` (r:1 w:0)
+ /// Proof: `Funding::ProjectsDetails` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Buckets` (r:1 w:1)
+ /// Proof: `Funding::Buckets` (`max_values`: None, `max_size`: Some(100), added: 2575, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::NextBidId` (r:1 w:1)
+ /// Proof: `Funding::NextBidId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::BidBucketBounds` (r:10 w:10)
+ /// Proof: `Funding::BidBucketBounds` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::AuctionBoughtUSD` (r:1 w:1)
+ /// Proof: `Funding::AuctionBoughtUSD` (`max_values`: None, `max_size`: Some(118), added: 2593, mode: `MaxEncodedLen`)
+ /// Storage: `Oracle::Values` (r:2 w:0)
+ /// Proof: `Oracle::Values` (`max_values`: None, `max_size`: Some(634), added: 3109, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Metadata` (r:1 w:0)
+ /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Evaluations` (r:1 w:0)
+ /// Proof: `Funding::Evaluations` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`)
+ /// Storage: `Balances::Holds` (r:1 w:1)
+ /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Asset` (r:1 w:1)
+ /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Account` (r:2 w:2)
+ /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::CTAmountOversubscribed` (r:1 w:1)
+ /// Proof: `Funding::CTAmountOversubscribed` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Bids` (r:0 w:10)
+ /// Proof: `Funding::Bids` (`max_values`: None, `max_size`: Some(309), added: 2784, mode: `MaxEncodedLen`)
+ /// The range of component `x` is `[1, 10]`.
+ fn bid(x: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `2890`
+ // Estimated: `7404 + x * (2535 ±0)`
+ // Minimum execution time: 184_000_000 picoseconds.
+ Weight::from_parts(139_444_380, 7404)
+ // Standard Error: 76_200
+ .saturating_add(Weight::from_parts(59_216_258, 0).saturating_mul(x.into()))
+ .saturating_add(T::DbWeight::get().reads(15_u64))
+ .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into())))
+ .saturating_add(T::DbWeight::get().writes(8_u64))
+ .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(x.into())))
+ .saturating_add(Weight::from_parts(0, 2535).saturating_mul(x.into()))
+ }
+}
+
+// For backwards compatibility and tests.
+impl WeightInfo for () {
+ /// Storage: `Timestamp::Now` (r:1 w:0)
+ /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::ProjectsMetadata` (r:1 w:0)
+ /// Proof: `Funding::ProjectsMetadata` (`max_values`: None, `max_size`: Some(437), added: 2912, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::ProjectsDetails` (r:1 w:0)
+ /// Proof: `Funding::ProjectsDetails` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Buckets` (r:1 w:1)
+ /// Proof: `Funding::Buckets` (`max_values`: None, `max_size`: Some(100), added: 2575, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::NextBidId` (r:1 w:1)
+ /// Proof: `Funding::NextBidId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::BidBucketBounds` (r:10 w:10)
+ /// Proof: `Funding::BidBucketBounds` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::AuctionBoughtUSD` (r:1 w:1)
+ /// Proof: `Funding::AuctionBoughtUSD` (`max_values`: None, `max_size`: Some(118), added: 2593, mode: `MaxEncodedLen`)
+ /// Storage: `Oracle::Values` (r:2 w:0)
+ /// Proof: `Oracle::Values` (`max_values`: None, `max_size`: Some(634), added: 3109, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Metadata` (r:1 w:0)
+ /// Proof: `ForeignAssets::Metadata` (`max_values`: None, `max_size`: Some(738), added: 3213, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Evaluations` (r:1 w:0)
+ /// Proof: `Funding::Evaluations` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`)
+ /// Storage: `Balances::Holds` (r:1 w:1)
+ /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Asset` (r:1 w:1)
+ /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
+ /// Storage: `ForeignAssets::Account` (r:2 w:2)
+ /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::CTAmountOversubscribed` (r:1 w:1)
+ /// Proof: `Funding::CTAmountOversubscribed` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`)
+ /// Storage: `Funding::Bids` (r:0 w:10)
+ /// Proof: `Funding::Bids` (`max_values`: None, `max_size`: Some(309), added: 2784, mode: `MaxEncodedLen`)
+ /// The range of component `x` is `[1, 10]`.
+ fn bid(x: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `2890`
+ // Estimated: `7404 + x * (2535 ±0)`
+ // Minimum execution time: 184_000_000 picoseconds.
+ Weight::from_parts(139_444_380, 7404)
+ // Standard Error: 76_200
+ .saturating_add(Weight::from_parts(59_216_258, 0).saturating_mul(x.into()))
+ .saturating_add(RocksDbWeight::get().reads(15_u64))
+ .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into())))
+ .saturating_add(RocksDbWeight::get().writes(8_u64))
+ .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(x.into())))
+ .saturating_add(Weight::from_parts(0, 2535).saturating_mul(x.into()))
+ }
+}
\ No newline at end of file
diff --git a/integration-tests/src/tests/ct_migration.rs b/integration-tests/src/tests/ct_migration.rs
index b5fac0c73..7ffea6b54 100644
--- a/integration-tests/src/tests/ct_migration.rs
+++ b/integration-tests/src/tests/ct_migration.rs
@@ -70,7 +70,7 @@ fn get_migrations_for_participants(
for participant in participants {
let (status, migrations) =
pallet_funding::UserMigrations::::get((project_id, participant.clone())).unwrap();
- user_migrations.insert(participant, (status, Migrations::from(migrations.into())));
+ user_migrations.insert(participant, (status, Migrations::from(migrations.to_vec())));
}
});
user_migrations
@@ -159,8 +159,8 @@ fn create_settled_project() -> (ProjectId, Vec) {
let mut inst = IntegrationInstantiator::new(None);
let project_metadata = default_project_metadata(ISSUER.into());
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 5);
- let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 8);
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 30);
PolimecNet::execute_with(|| {
let project_id = inst.create_finished_project(project_metadata, ISSUER.into(), None, evaluations, bids);
assert_eq!(
@@ -171,10 +171,6 @@ fn create_settled_project() -> (ProjectId, Vec) {
pallet_funding::Evaluations::::iter_prefix_values((project_id,))
.map(|eval| eval.evaluator)
.chain(pallet_funding::Bids::::iter_prefix_values((project_id,)).map(|bid| bid.bidder))
- .chain(
- pallet_funding::Contributions::::iter_prefix_values((project_id,))
- .map(|contribution| contribution.contributor),
- )
.collect();
participants.sort();
participants.dedup();
@@ -211,8 +207,8 @@ fn create_project_with_unsettled_participation(participation_type: Participation
let mut inst = IntegrationInstantiator::new(None);
PolimecNet::execute_with(|| {
let project_metadata = default_project_metadata(ISSUER.into());
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 5);
- let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 8);
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 30);
let project_id = inst.create_finished_project(project_metadata, ISSUER.into(), None, evaluations, bids);
assert_eq!(
@@ -221,12 +217,12 @@ fn create_project_with_unsettled_participation(participation_type: Participation
);
let evaluations_to_settle =
pallet_funding::Evaluations::::iter_prefix_values((project_id,)).collect_vec();
- let bids_to_settle = pallet_funding::Bids::::iter_prefix_values((project_id,)).collect_vec();
+ let bids_to_settle = inst.get_bids(project_id);
let mut participants: Vec = evaluations_to_settle
.iter()
.map(|eval| eval.evaluator.clone())
- .chain(bids_to_settle.iter().map(|bid| bid.bidder.clone()))
+ .chain(bids_to_settle.iter().map(|x| x.bidder.clone()))
.collect();
participants.sort();
participants.dedup();
@@ -242,9 +238,10 @@ fn create_project_with_unsettled_participation(participation_type: Participation
.unwrap()
}
- let start = if participation_type == ParticipationType::Bid { 1 } else { 0 };
- for bid in bids_to_settle[start..].iter() {
- PolimecFunding::settle_bid(RuntimeOrigin::signed(alice()), project_id, bid.bidder.clone(), bid.id).unwrap()
+ let proposed_start = if participation_type == ParticipationType::Bid { 1 } else { 0 };
+ let end = if proposed_start == 1 { bids_to_settle.len() - 1 } else { bids_to_settle.len() };
+ for bid in bids_to_settle[..end].iter() {
+ PolimecFunding::settle_bid(RuntimeOrigin::signed(alice()), project_id, bid.id).unwrap()
}
let evaluations =
diff --git a/integration-tests/src/tests/e2e.rs b/integration-tests/src/tests/e2e.rs
index b330b6193..43617bd8b 100644
--- a/integration-tests/src/tests/e2e.rs
+++ b/integration-tests/src/tests/e2e.rs
@@ -266,7 +266,6 @@ fn participate_with_checks(
mut inst: IntegrationInstantiator,
project_id: ProjectId,
participation_type: ParticipationType,
- participation_id: u32,
user: [u8; 32],
mode: ParticipationMode,
investor_type: InvestorType,
@@ -311,9 +310,6 @@ fn participate_with_checks(
if participation_type == ParticipationType::Bid {
PolimecFunding::bid(PolimecOrigin::signed(user.clone()), user_jwt, project_id, ct_amount, mode, funding_asset)
.unwrap();
- let stored_bid = Bids::::get((project_id, user.clone(), participation_id));
- // dbg!(&stored_bid);
- assert!(stored_bid.is_some());
}
let post_participation_free_plmc = PolimecBalances::free_balance(user.clone());
@@ -399,7 +395,6 @@ fn e2e_test() {
inst,
project_id,
ParticipationType::Bid,
- bid_id,
user,
mode,
investor_type,
@@ -425,13 +420,8 @@ fn e2e_test() {
let prev_treasury_usdt_balance = PolimecForeignAssets::balance(USDT.id(), otm_project_sub_account.clone());
let prev_escrow_usdt_balance = PolimecForeignAssets::balance(USDT.id(), funding_escrow_account.clone());
- PolimecFunding::settle_bid(
- PolimecOrigin::signed(rejected_bidder.clone()),
- project_id,
- rejected_bidder.clone(),
- rejected_bid_id,
- )
- .unwrap();
+ PolimecFunding::settle_bid(PolimecOrigin::signed(rejected_bidder.clone()), project_id, rejected_bid_id)
+ .unwrap();
let post_bid_free_plmc = PolimecBalances::free_balance(rejected_bidder.clone());
let post_bid_reserved_plmc = PolimecBalances::reserved_balance(rejected_bidder.clone());
@@ -663,3 +653,12 @@ fn e2e_test() {
}
});
}
+
+#[test]
+fn sandbox() {
+ let bid_weight = ::WeightInfo::bid(1);
+ let process_weight = ::WeightInfo::process_next_oversubscribed_bid();
+
+ dbg!(bid_weight);
+ dbg!(process_weight);
+}
diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs
index 728ce9d0d..58a475432 100644
--- a/pallets/funding/src/benchmarking.rs
+++ b/pallets/funding/src/benchmarking.rs
@@ -21,7 +21,6 @@
use super::*;
use crate::{instantiator::*, traits::SetPrices};
use polimec_common::assets::AcceptedFundingAsset;
-use ParticipationMode::{Classic, OTM};
use frame_benchmarking::v2::*;
use frame_support::{
@@ -72,9 +71,9 @@ where
.unwrap(),
bidding_ticket_sizes: BiddingTicketSizes {
- professional: TicketSize::new(10u128 * USD_UNIT, None),
- institutional: TicketSize::new(10u128 * USD_UNIT, None),
- retail: TicketSize::new(10u128 * USD_UNIT, None),
+ professional: TicketSize::new(100u128 * USD_UNIT, None),
+ institutional: TicketSize::new(100u128 * USD_UNIT, None),
+ retail: TicketSize::new(100u128 * USD_UNIT, None),
phantom: Default::default(),
},
participation_currencies: vec![USDT, USDC, DOT, WETH].try_into().unwrap(),
@@ -84,90 +83,6 @@ where
}
}
-pub fn default_evaluations() -> Vec>
-where
- ::Price: From,
- T::Hash: From,
-{
- let threshold = ::EvaluationSuccessThreshold::get();
- let default_project_metadata: ProjectMetadataOf =
- default_project_metadata::(account::>("issuer", 0, 0));
- let funding_target =
- default_project_metadata.minimum_price.saturating_mul_int(default_project_metadata.total_allocation_size);
- let evaluation_target = threshold * funding_target;
-
- vec![
- EvaluationParams::from((
- account::>("evaluator_1", 0, 0),
- Percent::from_percent(35) * evaluation_target,
- )),
- EvaluationParams::from((
- account::>("evaluator_2", 0, 0),
- Percent::from_percent(35) * evaluation_target,
- )),
- EvaluationParams::from((
- account::>("evaluator_3", 0, 0),
- Percent::from_percent(35) * evaluation_target,
- )),
- ]
-}
-
-pub fn default_bids() -> Vec>
-where
- ::Price: From,
- T::Hash: From,
-{
- let default_project_metadata = default_project_metadata::(account::>("issuer", 0, 0));
- let auction_funding_target =
- default_project_metadata.minimum_price.saturating_mul_int(default_project_metadata.total_allocation_size);
- let inst = BenchInstantiator::::new(None);
-
- inst.generate_bids_from_total_usd(
- default_project_metadata.clone(),
- Percent::from_percent(95) * auction_funding_target,
- 5,
- )
-}
-
-pub fn full_bids() -> Vec>
-where
- T: Config,
- ::Price: From,
- T::Hash: From,
-{
- let inst = BenchInstantiator::::new(None);
- let default_project = default_project_metadata::(account::>("issuer", 0, 0));
- let total_ct_for_bids = default_project.total_allocation_size;
- let total_usd_for_bids = default_project.minimum_price.checked_mul_int(total_ct_for_bids).unwrap();
- inst.generate_bids_from_total_usd(default_project.clone(), total_usd_for_bids, 5)
-}
-
-pub fn default_weights() -> Vec {
- vec![20u8, 15u8, 10u8, 25u8, 30u8]
-}
-
-pub fn default_evaluators() -> Vec> {
- vec![
- account::>("evaluator_1", 0, 0),
- account::>("evaluator_2", 0, 0),
- account::>("evaluator_3", 0, 0),
- account::>("evaluator_4", 0, 0),
- account::>("evaluator_5", 0, 0),
- ]
-}
-pub fn default_bidders() -> Vec> {
- vec![
- account::>("bidder_1", 0, 0),
- account::>("bidder_2", 0, 0),
- account::>("bidder_3", 0, 0),
- account::>("bidder_4", 0, 0),
- account::>("bidder_5", 0, 0),
- ]
-}
-
-pub fn default_bidder_modes() -> Vec {
- vec![Classic(10u8), Classic(3u8), OTM, OTM, Classic(4u8)]
-}
/// Grab an account, seeded by a name and index.
pub fn string_account(
name: scale_info::prelude::string::String,
@@ -314,7 +229,7 @@ mod benchmarks {
bidding_ticket_sizes: BiddingTicketSizes {
professional: TicketSize::new(5000 * USD_UNIT, Some(10_000 * USD_UNIT)),
institutional: TicketSize::new(5000 * USD_UNIT, Some(10_000 * USD_UNIT)),
- retail: TicketSize::new(10 * USD_UNIT, Some(10_000 * USD_UNIT)),
+ retail: TicketSize::new(100 * USD_UNIT, Some(10_000 * USD_UNIT)),
phantom: Default::default(),
},
participation_currencies: vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::USDC].try_into().unwrap(),
@@ -393,15 +308,13 @@ mod benchmarks {
}
#[benchmark]
- fn evaluate(
- // How many other evaluations the user did for that same project
- x: Linear<0, { T::MaxEvaluationsPerUser::get() - 1 }>,
- ) {
+ fn evaluate() {
// setup
let mut inst = BenchInstantiator::::new(None);
::SetPrices::set_prices();
- // We can't see events at block 0 inst.advance_time(1u32.into());
+ // We can't see events at block 0
+ inst.advance_time(1u32.into());
let issuer = account::>("issuer", 0, 0);
let test_evaluator = account::>("evaluator", 0, 0);
@@ -410,25 +323,16 @@ mod benchmarks {
let project_metadata = default_project_metadata::(issuer.clone());
let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None);
- let existing_evaluation = EvaluationParams::from((test_evaluator.clone(), (200 * USD_UNIT).into()));
let extrinsic_evaluation = EvaluationParams::from((test_evaluator.clone(), (1_000 * USD_UNIT).into()));
- let existing_evaluations = vec![existing_evaluation; x as usize];
- let plmc_for_existing_evaluations = inst.calculate_evaluation_plmc_spent(existing_evaluations.clone());
let plmc_for_extrinsic_evaluation = inst.calculate_evaluation_plmc_spent(vec![extrinsic_evaluation.clone()]);
let existential_plmc: Vec> =
plmc_for_extrinsic_evaluation.accounts().existential_deposits();
inst.mint_plmc_to(existential_plmc);
- inst.mint_plmc_to(plmc_for_existing_evaluations.clone());
inst.mint_plmc_to(plmc_for_extrinsic_evaluation.clone());
- // do "x" evaluations for this user
- inst.evaluate_for_users(project_id, existing_evaluations).expect("All evaluations are accepted");
-
let extrinsic_plmc_bonded = plmc_for_extrinsic_evaluation[0].plmc_amount;
- let total_expected_plmc_bonded = inst
- .sum_balance_mappings(vec![plmc_for_existing_evaluations.clone(), plmc_for_extrinsic_evaluation.clone()]);
let jwt = get_mock_jwt_with_cid(
extrinsic_evaluation.account.clone(),
@@ -468,7 +372,7 @@ mod benchmarks {
let bonded_plmc = inst
.get_reserved_plmc_balances_for(vec![extrinsic_evaluation.account.clone()], HoldReason::Evaluation.into())[0]
.plmc_amount;
- assert_eq!(bonded_plmc, total_expected_plmc_bonded);
+ assert_eq!(bonded_plmc, extrinsic_plmc_bonded);
// Events
frame_system::Pallet::::assert_last_event(
@@ -544,10 +448,8 @@ mod benchmarks {
#[benchmark]
fn bid(
- // amount of already made bids by the same user. Leave 10 bids available to make the extrinsic pass in case y = max (10)
- x: Linear<0, { T::MaxBidsPerUser::get() - 10 }>,
- // amount of times when `perform_bid` is called (i.e. into how many buckets the bid is spread)
- y: Linear<0, 10>,
+ // Amount of bids that are outbid by this one.
+ x: Linear<1, 1000>,
) {
// * setup *
let mut inst = BenchInstantiator::::new(None);
@@ -561,10 +463,10 @@ mod benchmarks {
whitelist_account!(bidder);
let mut project_metadata = default_project_metadata::(issuer.clone());
- project_metadata.mainnet_token_max_supply = 100_000 * CT_UNIT;
- project_metadata.total_allocation_size = 100_000 * CT_UNIT;
+ project_metadata.mainnet_token_max_supply = 40_000 * CT_UNIT;
+ project_metadata.total_allocation_size = 40_000 * CT_UNIT;
project_metadata.minimum_price = PriceProviderOf::::calculate_decimals_aware_price(
- PriceOf::::checked_from_rational(100, 1).unwrap(),
+ PriceOf::::checked_from_rational(10, 1).unwrap(),
USD_DECIMALS,
CT_DECIMALS,
)
@@ -574,145 +476,75 @@ mod benchmarks {
let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations);
- let existing_bid = BidParams::from((
- bidder.clone(),
- Institutional,
- (50 * CT_UNIT).into(),
- ParticipationMode::Classic(5u8),
- AcceptedFundingAsset::USDT,
- ));
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 100, x);
+ let total_ct_bid = project_metadata.total_allocation_size;
- let existing_bids = vec![existing_bid; x as usize];
- let existing_bids_post_bucketing =
- inst.get_actual_price_charged_for_bucketed_bids(&existing_bids, project_metadata.clone(), None);
- let plmc_for_existing_bids = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(
- &existing_bids,
+ let bids_plmc = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(
+ &bids,
+ project_metadata.clone(),
+ None,
+ );
+ let bids_funding_assets = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket(
+ &bids,
project_metadata.clone(),
None,
);
- let usdt_for_existing_bids: Vec> = inst
- .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket(
- &existing_bids,
- project_metadata.clone(),
- None,
- );
- let escrow_account = Pallet::::fund_account_id(project_id);
- let prev_total_escrow_usdt_locked =
- inst.get_free_funding_asset_balances_for(vec![(escrow_account.clone(), usdt_id())]);
-
- inst.mint_plmc_ed_if_required(plmc_for_existing_bids.accounts());
- inst.mint_plmc_to(plmc_for_existing_bids.clone());
- inst.mint_funding_asset_ed_if_required(usdt_for_existing_bids.to_account_asset_map());
- inst.mint_funding_asset_to(usdt_for_existing_bids.clone());
-
- // do "x" contributions for this user
- inst.bid_for_users(project_id, existing_bids.clone()).unwrap();
-
- // to call do_perform_bid several times, we need the bucket to reach its limit. You can only bid over 10 buckets
- // in a single bid, since the increase delta is 10% of the total allocation, and you cannot bid more than the allocation.
- let mut ct_amount = (50 * CT_UNIT).into();
- let mut maybe_filler_bid = None;
- let new_bidder = account::>("new_bidder", 0, 0);
-
- let mut usdt_for_filler_bidder =
- vec![UserToFundingAsset::::new(new_bidder.clone(), Zero::zero(), AcceptedFundingAsset::USDT.id())];
- if y > 0 {
- let current_bucket = Buckets::::get(project_id).unwrap();
- // first lets bring the bucket to almost its limit with another bidder:
- assert!(new_bidder.clone() != bidder.clone());
- let bid_params = BidParams::from((
- new_bidder.clone(),
- Institutional,
- current_bucket.amount_left,
- ParticipationMode::Classic(1u8),
- AcceptedFundingAsset::USDT,
- ));
- maybe_filler_bid = Some(bid_params.clone());
- let plmc_for_new_bidder = inst.calculate_auction_plmc_charged_with_given_price(
- &vec![bid_params.clone()],
- current_bucket.current_price,
- );
- let usdt_for_new_bidder = inst.calculate_auction_funding_asset_charged_with_given_price(
- &vec![bid_params.clone()],
- current_bucket.current_price,
- );
-
- inst.mint_plmc_ed_if_required(vec![(new_bidder.clone())]);
- inst.mint_plmc_to(plmc_for_new_bidder);
-
- inst.mint_funding_asset_ed_if_required(vec![(new_bidder, AcceptedFundingAsset::USDT.id())]);
- inst.mint_funding_asset_to(usdt_for_new_bidder.clone());
-
- inst.bid_for_users(project_id, vec![bid_params]).unwrap();
-
- let auction_allocation = project_metadata.total_allocation_size;
- let bucket_size = Percent::from_percent(10) * auction_allocation;
- ct_amount = bucket_size * (y as u128);
- usdt_for_filler_bidder = usdt_for_new_bidder;
- }
+ inst.mint_plmc_ed_if_required(bids.accounts());
+ inst.mint_plmc_to(bids_plmc);
+
+ inst.mint_funding_asset_ed_if_required(bids.to_account_asset_map());
+ inst.mint_funding_asset_to(bids_funding_assets);
+
+ inst.bid_for_users(project_id, bids).unwrap();
+
+ let current_bucket = Buckets::::get(project_id).unwrap();
let extrinsic_bid = BidParams::from((
bidder.clone(),
Institutional,
- ct_amount,
+ total_ct_bid,
ParticipationMode::Classic(1u8),
AcceptedFundingAsset::USDT,
));
- let original_extrinsic_bid = extrinsic_bid.clone();
- let current_bucket = Buckets::::get(project_id).unwrap();
- // we need to call this after bidding `x` amount of times, to get the latest bucket from storage
- let extrinsic_bids_post_bucketing = inst.get_actual_price_charged_for_bucketed_bids(
+
+ let extrinsic_bid_plmc = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(
+ &vec![extrinsic_bid.clone()],
+ project_metadata.clone(),
+ Some(current_bucket),
+ );
+ let extrinsic_bid_funding_asset = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket(
&vec![extrinsic_bid.clone()],
project_metadata.clone(),
Some(current_bucket),
);
- assert_eq!(extrinsic_bids_post_bucketing.len(), (y as usize).max(1usize));
-
- let plmc_for_extrinsic_bids: Vec> = inst
- .calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(
- &vec![extrinsic_bid.clone()],
- project_metadata.clone(),
- Some(current_bucket),
- );
- let usdt_for_extrinsic_bids: Vec> = inst
- .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket(
- &vec![extrinsic_bid],
- project_metadata.clone(),
- Some(current_bucket),
- );
- inst.mint_plmc_ed_if_required(plmc_for_extrinsic_bids.accounts());
- inst.mint_plmc_to(plmc_for_extrinsic_bids.clone());
- inst.mint_funding_asset_ed_if_required(usdt_for_extrinsic_bids.to_account_asset_map());
- inst.mint_funding_asset_to(usdt_for_extrinsic_bids.clone());
-
- let total_free_plmc = inst.get_ed();
- let total_plmc_participation_bonded =
- inst.sum_balance_mappings(vec![plmc_for_extrinsic_bids.clone(), plmc_for_existing_bids.clone()]);
- let total_free_usdt = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id());
- let total_escrow_usdt_locked = inst.sum_funding_asset_mappings(vec![
- prev_total_escrow_usdt_locked.clone(),
- usdt_for_extrinsic_bids.clone(),
- usdt_for_existing_bids.clone(),
- usdt_for_filler_bidder.clone(),
- ])[0]
- .1;
+ inst.mint_plmc_ed_if_required(extrinsic_bid_plmc.accounts());
+ inst.mint_plmc_to(extrinsic_bid_plmc.clone());
+ inst.mint_funding_asset_ed_if_required(extrinsic_bid_funding_asset.to_account_asset_map());
+ inst.mint_funding_asset_to(extrinsic_bid_funding_asset.clone());
+
+ let extrinsic_bids_post_bucketing = inst.get_actual_price_charged_for_bucketed_bids(
+ &vec![extrinsic_bid.clone()],
+ project_metadata.clone(),
+ Some(current_bucket),
+ );
+ dbg!(extrinsic_bids_post_bucketing.len());
let jwt = get_mock_jwt_with_cid(
- original_extrinsic_bid.bidder.clone(),
+ bidder.clone(),
InvestorType::Institutional,
- generate_did_from_account(original_extrinsic_bid.bidder.clone()),
+ generate_did_from_account(bidder.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);
#[extrinsic_call]
bid(
- RawOrigin::Signed(original_extrinsic_bid.bidder.clone()),
+ RawOrigin::Signed(bidder.clone()),
jwt,
project_id,
- original_extrinsic_bid.amount,
- original_extrinsic_bid.mode,
- original_extrinsic_bid.asset,
+ extrinsic_bid.amount,
+ extrinsic_bid.mode,
+ extrinsic_bid.asset,
);
// * validity checks *
@@ -732,66 +564,72 @@ mod benchmarks {
plmc_bond: None,
when: None,
};
- Bids::::iter_prefix_values((project_id, bidder.clone()))
+ Bids::::iter_prefix_values((project_id,))
.find(|stored_bid| bid_filter.matches_bid(stored_bid))
.expect("bid not found");
}
- // Bucket Storage Check
- let bucket_delta_amount = Percent::from_percent(10) * project_metadata.total_allocation_size;
- let ten_percent_in_price: ::Price =
- PriceOf::::checked_from_rational(1, 10).unwrap() * project_metadata.minimum_price;
+ let cutoff = OutbidBidsCutoff::::get(project_id).unwrap();
- let mut expected_bucket = Bucket::new(
- project_metadata.total_allocation_size,
- project_metadata.minimum_price,
- ten_percent_in_price,
- bucket_delta_amount,
- );
+ // First bucket with whole allocation should be outbid.
+ assert_eq!(cutoff, (project_metadata.minimum_price, 0));
+ }
- for (bid_params, _price_) in existing_bids_post_bucketing.clone() {
- expected_bucket.update(bid_params.amount);
- }
- if let Some(bid_params) = maybe_filler_bid {
- expected_bucket.update(bid_params.amount);
- }
- for (bid_params, _price_) in extrinsic_bids_post_bucketing.clone() {
- expected_bucket.update(bid_params.amount);
- }
+ // We benchmark the worst case, which is a new cutoff being calculated.
+ // This doesn't happen when the first bid we read is partially accepted instead of rejected.
+ #[benchmark]
+ fn process_next_oversubscribed_bid() {
+ // * setup *
+ let mut inst = BenchInstantiator::::new(None);
+ ::SetPrices::set_prices();
- let current_bucket = Buckets::::get(project_id).unwrap();
- assert_eq!(current_bucket, expected_bucket);
+ // We can't see events at block 0
+ inst.advance_time(1u32.into());
- // Balances
- let bonded_plmc =
- inst.get_reserved_plmc_balances_for(vec![bidder.clone()], HoldReason::Participation.into())[0].plmc_amount;
- assert_eq!(bonded_plmc, total_plmc_participation_bonded);
+ let issuer = account::>("issuer", 0, 0);
+ let bidder = account::>("bidder", 0, 0);
+ whitelist_account!(bidder);
+
+ let project_metadata = default_project_metadata::(issuer.clone());
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 5);
+ let first_bucket_bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 100, 10);
+ let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations);
- let free_plmc = inst.get_free_plmc_balances_for(vec![bidder.clone()])[0].plmc_amount;
- assert_eq!(free_plmc, total_free_plmc);
+ inst.mint_necessary_tokens_for_bids(project_id, first_bucket_bids.clone());
+ inst.bid_for_users(project_id, first_bucket_bids.clone()).unwrap();
- let escrow_account = Pallet::::fund_account_id(project_id);
- let locked_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), escrow_account.clone());
- assert_eq!(locked_usdt, total_escrow_usdt_locked);
+ let oversubscribing_bid_amount = first_bucket_bids[9].amount;
+ let oversubscribing_bid = BidParams::from((
+ bidder.clone(),
+ Institutional,
+ oversubscribing_bid_amount,
+ ParticipationMode::Classic(1u8),
+ AcceptedFundingAsset::USDT,
+ ));
+ inst.mint_necessary_tokens_for_bids(project_id, vec![oversubscribing_bid.clone()]);
+ inst.bid_for_users(project_id, vec![oversubscribing_bid.clone()]).unwrap();
- let free_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), bidder);
- assert_eq!(free_usdt, total_free_usdt);
+ Pallet::::do_process_next_oversubscribed_bid(project_id).unwrap();
+ let pre_cutoff = OutbidBidsCutoff::::get(project_id).unwrap();
- // Events
- for (bid_params, _price_) in extrinsic_bids_post_bucketing {
- let maybe_event = find_event! {
- T,
- Event::::Bid {
- project_id,
- ct_amount,
- mode, ..
- },
- project_id == project_id,
- ct_amount == bid_params.amount,
- mode == bid_params.mode
- };
- assert!(maybe_event.is_some(), "Event not found");
- }
+ inst.mint_necessary_tokens_for_bids(project_id, vec![oversubscribing_bid.clone()]);
+ inst.bid_for_users(project_id, vec![oversubscribing_bid.clone()]).unwrap();
+
+ #[extrinsic_call]
+ process_next_oversubscribed_bid(RawOrigin::Signed(bidder), project_id);
+
+ // * validity checks *
+ let oversubscribed_amount = CTAmountOversubscribed::::get(project_id);
+ assert!(oversubscribed_amount.is_zero());
+
+ let rejected_bid = Bids::::get((project_id, 9)).unwrap();
+ assert_eq!(rejected_bid.status, BidStatus::Rejected);
+
+ let rejected_bid = Bids::::get((project_id, 8)).unwrap();
+ assert_eq!(rejected_bid.status, BidStatus::Rejected);
+
+ let post_cutoff = OutbidBidsCutoff::::get(project_id).unwrap();
+ assert_ne!(pre_cutoff, post_cutoff);
}
// end_funding has 2 logic paths:
@@ -868,13 +706,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
whitelist_account!(anyone);
- let project_id = inst.create_finished_project(
- default_project_metadata::(issuer.clone()),
- issuer,
- None,
- default_evaluations::(),
- default_bids::(),
- );
+ let project_metadata = default_project_metadata::(issuer.clone());
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 30);
+ let project_id = inst.create_finished_project(project_metadata, issuer, None, evaluations, bids);
#[extrinsic_call]
start_settlement(RawOrigin::Signed(anyone), project_id);
@@ -900,16 +735,19 @@ mod benchmarks {
inst.advance_time(1u32.into());
let issuer = account::>("issuer", 0, 0);
- let evaluations: Vec> = default_evaluations::();
+ let project_metadata = default_project_metadata::(issuer.clone());
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
let evaluator: AccountIdOf = evaluations[0].account.clone();
whitelist_account!(evaluator);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 30);
+
let project_id = inst.create_finished_project(
default_project_metadata::(issuer.clone()),
issuer,
None,
evaluations,
- default_bids::(),
+ bids,
);
let evaluation_to_settle =
@@ -961,53 +799,41 @@ mod benchmarks {
inst.advance_time(1u32.into());
let issuer = account::>("issuer", 0, 0);
- let mut bidder_accounts = default_bidders::().into_iter();
let project_metadata = default_project_metadata::(issuer.clone());
- // let target_wap = project_metadata.minimum_price + project_metadata.minimum_price * >::saturating_from_rational(1, 10);
- let mut target_bucket = >::create_bucket_from_metadata(&project_metadata.clone()).unwrap();
- target_bucket.update(target_bucket.amount_left);
- target_bucket.update(target_bucket.amount_left);
-
- let bids = inst.generate_bids_from_bucket(
- project_metadata.clone(),
- target_bucket,
- bidder_accounts.next().unwrap(),
- |_| bidder_accounts.next().unwrap(),
- AcceptedFundingAsset::USDT,
- );
-
- let project_id = inst.create_finished_project(
- project_metadata.clone(),
- issuer,
- None,
- default_evaluations::(),
- bids.clone(),
- );
+ let increase = project_metadata.minimum_price * PriceOf::::saturating_from_rational(5, 10);
+ let target_wap = project_metadata.minimum_price + increase;
- let wap = inst.get_project_details(project_id).weighted_average_price.unwrap();
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_that_take_price_to(project_metadata.clone(), target_wap);
- let bidder = bids.last().unwrap().bidder.clone();
- whitelist_account!(bidder);
+ let project_id =
+ inst.create_finished_project(project_metadata.clone(), issuer, None, evaluations, bids.clone());
assert_ok!(>::do_start_settlement(project_id));
- let bid_to_settle =
- inst.execute(|| Bids::::iter_prefix_values((project_id, bidder.clone())).next().unwrap());
+ let bid_to_settle = inst.execute(|| {
+ let mut bids_iter = Bids::::iter_prefix_values((project_id,));
+ bids_iter.find(|b| matches!(b.status, BidStatus::PartiallyAccepted(_))).unwrap()
+ });
- // Make sure a refund has to happen
- assert!(bid_to_settle.original_ct_usd_price > wap);
+ let bidder = bid_to_settle.bidder.clone();
+ whitelist_account!(bidder);
+
+ let BidStatus::PartiallyAccepted(expected_ct_amount) = bid_to_settle.status else {
+ unreachable!();
+ };
#[extrinsic_call]
- settle_bid(RawOrigin::Signed(bidder.clone()), project_id, bidder.clone(), bid_to_settle.id);
+ settle_bid(RawOrigin::Signed(bidder.clone()), project_id, bid_to_settle.id);
// * validity checks *
// Storage
- assert!(Bids::::get((project_id, bidder.clone(), bid_to_settle.id)).is_none());
+ assert!(Bids::::get((project_id, bid_to_settle.id)).is_none());
// Balances
let ct_amount = inst.get_ct_asset_balances_for(project_id, vec![bidder.clone()])[0];
- assert_eq!(bid_to_settle.original_ct_amount, ct_amount);
+ assert_eq!(expected_ct_amount, ct_amount);
// Events
frame_system::Pallet::::assert_last_event(
@@ -1015,8 +841,9 @@ mod benchmarks {
project_id,
account: bidder.clone(),
id: bid_to_settle.id,
- final_ct_amount: bid_to_settle.original_ct_amount,
- final_ct_usd_price: wap,
+ status: bid_to_settle.status,
+ final_ct_amount: expected_ct_amount,
+ final_ct_usd_price: bid_to_settle.original_ct_usd_price,
}
.into(),
);
@@ -1033,14 +860,11 @@ mod benchmarks {
whitelist_account!(anyone);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- false,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 95, 30);
+
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, false);
#[extrinsic_call]
mark_project_as_settled(RawOrigin::Signed(anyone), project_id);
@@ -1059,8 +883,8 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 1);
- let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 1);
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
let project_id =
inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
@@ -1077,13 +901,13 @@ mod benchmarks {
// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted);
- assert_eq!(UnmigratedCounter::::get(project_id), 2);
+ assert_eq!(UnmigratedCounter::::get(project_id), 40);
}
#[benchmark]
fn confirm_offchain_migration(
// Amount of migrations to confirm for a single user
- x: Linear<1, { <::MaxBidsPerUser>::get() }>,
+ x: Linear<1, 100>,
) {
// setup
let mut inst = BenchInstantiator::::new(None);
@@ -1092,6 +916,11 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let participant = account::>("test_participant", 0, 0);
+ let project_metadata = default_project_metadata::(issuer.clone());
+
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+
+ let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 50);
let max_bids = x;
let participant_bids = (0..max_bids)
.map(|_| {
@@ -1104,12 +933,6 @@ mod benchmarks {
))
})
.collect_vec();
-
- let project_metadata = default_project_metadata::(issuer.clone());
-
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 1);
-
- let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 1);
bids.extend(participant_bids);
let project_id =
@@ -1140,8 +963,8 @@ mod benchmarks {
// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted);
- // Evaluations and Bids had 1 each where it was a different account that the one we just confirmed.
- assert_eq!(UnmigratedCounter::::get(project_id), 2);
+
+ assert_eq!(UnmigratedCounter::::get(project_id), 10 + 50);
}
#[benchmark]
@@ -1153,14 +976,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1197,14 +1016,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1254,14 +1069,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1328,14 +1139,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1408,7 +1215,7 @@ mod benchmarks {
#[benchmark]
fn send_pallet_migration_for(
// Amount of migrations to confirm for a single user
- x: Linear<1, { ::MaxBidsPerUser::get() }>,
+ x: Linear<1, 100>,
) {
// setup
let mut inst = BenchInstantiator::::new(None);
@@ -1424,7 +1231,7 @@ mod benchmarks {
BidParams::from((
participant.clone(),
Institutional,
- (500 * CT_UNIT).into(),
+ (50 * CT_UNIT).into(),
ParticipationMode::Classic(1u8),
AcceptedFundingAsset::USDT,
))
@@ -1432,8 +1239,8 @@ mod benchmarks {
.collect_vec();
let project_metadata = default_project_metadata::(issuer.clone());
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 5);
- let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 1);
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 40);
bids.extend(participant_bids);
let project_id =
@@ -1480,9 +1287,9 @@ mod benchmarks {
}
#[benchmark]
- fn confirm_pallet_migrations(
+ fn confirm_pallet_migration(
// Amount of migrations to confirm for a single user
- x: Linear<1, { ::MaxBidsPerUser::get() }>,
+ x: Linear<1, 100>,
) {
// setup
let mut inst = BenchInstantiator::::new(None);
@@ -1498,7 +1305,7 @@ mod benchmarks {
BidParams::from((
participant.clone(),
Institutional,
- (500 * CT_UNIT).into(),
+ (50 * CT_UNIT).into(),
ParticipationMode::Classic(1u8),
AcceptedFundingAsset::USDT,
))
@@ -1506,9 +1313,10 @@ mod benchmarks {
.collect_vec();
let project_metadata = default_project_metadata::(issuer.clone());
- let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 1);
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+
+ let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 50);
- let mut bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 1);
bids.extend(participant_bids);
let project_id =
@@ -1571,14 +1379,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1610,14 +1414,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
@@ -1651,14 +1451,10 @@ mod benchmarks {
let issuer = account::>("issuer", 0, 0);
let project_metadata = default_project_metadata::(issuer.clone());
- let project_id = inst.create_settled_project(
- project_metadata.clone(),
- issuer.clone(),
- None,
- default_evaluations::(),
- default_bids::(),
- true,
- );
+ let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), 10);
+ let bids = inst.generate_bids_from_total_ct_percent(project_metadata.clone(), 34, 30);
+ let project_id =
+ inst.create_settled_project(project_metadata.clone(), issuer.clone(), None, evaluations, bids, true);
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
diff --git a/pallets/funding/src/functions/2_evaluation.rs b/pallets/funding/src/functions/2_evaluation.rs
index a859dc519..8a6713b0e 100644
--- a/pallets/funding/src/functions/2_evaluation.rs
+++ b/pallets/funding/src/functions/2_evaluation.rs
@@ -45,6 +45,10 @@ impl Pallet {
// * Branch in possible project paths *
// Successful path
return if is_funded {
+ let mut project_ids = ProjectsInAuctionRound::::get().to_vec();
+ project_ids.push(project_id);
+ let project_ids = WeakBoundedVec::force_from(project_ids, None);
+ ProjectsInAuctionRound::::put(project_ids);
Self::transition_project(
project_id,
project_details,
diff --git a/pallets/funding/src/functions/3_auction.rs b/pallets/funding/src/functions/3_auction.rs
index 67894453c..4039d9d0e 100644
--- a/pallets/funding/src/functions/3_auction.rs
+++ b/pallets/funding/src/functions/3_auction.rs
@@ -3,7 +3,7 @@ use super::*;
impl Pallet {
#[transactional]
- pub fn do_bid(params: DoBidParams) -> DispatchResultWithPostInfo {
+ pub fn do_bid(params: DoBidParams) -> DispatchResult {
// * Get variables *
let DoBidParams {
bidder,
@@ -23,7 +23,6 @@ impl Pallet {
let mut current_bucket = Buckets::::get(project_id).ok_or(Error::::BucketNotFound)?;
let now = >::block_number();
let mut amount_to_bid = ct_amount;
- let total_bids_for_project = BidCounts::::get(project_id);
let project_policy = project_metadata.policy_ipfs_cid.ok_or(Error::::ImpossibleState)?;
// User will spend at least this amount of USD for his bid(s). More if the bid gets split into different buckets
@@ -32,9 +31,6 @@ impl Pallet {
// weight return variables
let mut perform_bid_calls = 0;
- let existing_bids = Bids::::iter_prefix_values((project_id, bidder.clone())).collect::>();
- let existing_bids_amount = existing_bids.len() as u32;
-
let metadata_ticket_size_bounds = match investor_type {
InvestorType::Institutional => project_metadata.bidding_ticket_sizes.institutional,
InvestorType::Professional => project_metadata.bidding_ticket_sizes.professional,
@@ -68,7 +64,6 @@ impl Pallet {
// Note: We limit the CT Amount to the auction allocation size, to avoid long-running loops.
ensure!(ct_amount <= project_metadata.total_allocation_size, Error::::TooHigh);
- ensure!(existing_bids.len() < T::MaxBidsPerUser::get() as usize, Error::::TooManyUserParticipations);
ensure!(
project_metadata.participants_account_type.junction_is_supported(&receiving_account),
Error::::UnsupportedReceiverAccountJunction
@@ -84,6 +79,7 @@ impl Pallet {
current_bucket.amount_left
};
let bid_id = NextBidId::::get();
+ let auction_oversubscribed = current_bucket.current_price > current_bucket.initial_price;
let perform_params = DoPerformBidParams {
bidder: bidder.clone(),
@@ -96,10 +92,20 @@ impl Pallet {
now,
did: did.clone(),
metadata_ticket_size_bounds,
- total_bids_by_bidder: existing_bids_amount.saturating_add(perform_bid_calls),
- total_bids_for_project: total_bids_for_project.saturating_add(perform_bid_calls),
receiving_account,
+ auction_oversubscribed,
};
+
+ BidBucketBounds::::mutate(project_id, current_bucket.current_price, |maybe_indexes| {
+ if let Some((i, j)) = maybe_indexes {
+ // TODO: remove the debug_assert before the PR is merged.
+ debug_assert!(bid_id == *j + 1);
+ *maybe_indexes = Some((*i, bid_id));
+ } else {
+ *maybe_indexes = Some((bid_id, bid_id));
+ }
+ });
+
Self::do_perform_bid(perform_params)?;
perform_bid_calls = perform_bid_calls.saturating_add(1);
@@ -112,10 +118,7 @@ impl Pallet {
// Note: If the bucket has been exhausted, the 'update' function has already made the 'current_bucket' point to the next one.
Buckets::::insert(project_id, current_bucket);
- Ok(PostDispatchInfo {
- actual_weight: Some(WeightInfoOf::::bid(existing_bids_amount, perform_bid_calls)),
- pays_fee: Pays::No,
- })
+ Ok(())
}
#[transactional]
@@ -131,26 +134,23 @@ impl Pallet {
now,
did,
metadata_ticket_size_bounds,
- total_bids_by_bidder,
- total_bids_for_project,
receiving_account,
+ auction_oversubscribed,
} = do_perform_bid_params;
- let ticket_size = ct_usd_price.checked_mul_int(ct_amount).ok_or(Error::::BadMath)?;
+ let usd_ticket_size = ct_usd_price.checked_mul_int(ct_amount).ok_or(Error::::BadMath)?;
let total_usd_bid_by_did = AuctionBoughtUSD::::get((project_id, did.clone()));
let multiplier: MultiplierOf = mode.multiplier().try_into().map_err(|_| Error::::BadMath)?;
ensure!(
metadata_ticket_size_bounds
- .usd_ticket_below_maximum_per_did(total_usd_bid_by_did.saturating_add(ticket_size)),
+ .usd_ticket_below_maximum_per_did(total_usd_bid_by_did.saturating_add(usd_ticket_size)),
Error::::TooHigh
);
- ensure!(total_bids_by_bidder < T::MaxBidsPerUser::get(), Error::::TooManyUserParticipations);
- ensure!(total_bids_for_project < T::MaxBidsPerProject::get(), Error::::TooManyProjectParticipations);
// * Calculate new variables *
- let plmc_bond = Self::calculate_plmc_bond(ticket_size, multiplier).map_err(|_| Error::::BadMath)?;
- let funding_asset_amount_locked = Self::calculate_funding_asset_amount(ticket_size, funding_asset)?;
+ let plmc_bond = Self::calculate_plmc_bond(usd_ticket_size, multiplier).map_err(|_| Error::::BadMath)?;
+ let funding_asset_amount_locked = Self::calculate_funding_asset_amount(usd_ticket_size, funding_asset)?;
let new_bid = BidInfoOf:: {
id: bid_id,
@@ -171,10 +171,13 @@ impl Pallet {
Self::bond_plmc_with_mode(&bidder, project_id, plmc_bond, mode, funding_asset)?;
Self::try_funding_asset_hold(&bidder, project_id, funding_asset_amount_locked, funding_asset.id())?;
- Bids::::insert((project_id, bidder.clone(), bid_id), &new_bid);
+ Bids::::insert((project_id, bid_id), &new_bid);
NextBidId::::set(bid_id.saturating_add(One::one()));
- BidCounts::::mutate(project_id, |c| *c = c.saturating_add(1));
- AuctionBoughtUSD::::mutate((project_id, did), |amount| *amount = amount.saturating_add(ticket_size));
+ AuctionBoughtUSD::::mutate((project_id, did), |amount| *amount = amount.saturating_add(usd_ticket_size));
+
+ if auction_oversubscribed {
+ CTAmountOversubscribed::::mutate(project_id, |amount| *amount = amount.saturating_add(ct_amount));
+ }
Self::deposit_event(Event::Bid {
project_id,
@@ -190,4 +193,73 @@ impl Pallet {
Ok(new_bid)
}
+
+ /// Go over one oversubscribed bid and update the cutoff.
+ pub fn do_process_next_oversubscribed_bid(project_id: ProjectId) -> DispatchResult {
+ let project_metadata = ProjectsMetadata::::get(project_id).ok_or(Error::::ProjectMetadataNotFound)?;
+ let bucket = Buckets::::get(project_id).ok_or(Error::::BucketNotFound)?;
+ let maybe_current_cutoff = OutbidBidsCutoff::::get(project_id);
+ let mut ct_amount_oversubscribed = CTAmountOversubscribed::::get(project_id);
+
+ ensure!(ct_amount_oversubscribed > Zero::zero(), Error::::NoBidsOversubscribed);
+
+ let current_cutoff: (PriceOf, u32);
+
+ // Adjust initial cutoff if necessary
+ if let Some((price, index)) = maybe_current_cutoff {
+ let bid = Bids::::get((project_id, index)).ok_or(Error::::ImpossibleState)?;
+ if matches!(bid.status, BidStatus::PartiallyAccepted(_)) {
+ current_cutoff = (price, index);
+ } else {
+ let (new_price, new_index) = Self::get_next_cutoff(project_id, bucket.delta_price, price, index)?;
+ current_cutoff = (new_price, new_index);
+ }
+ } else {
+ // Initialize to the first bucket
+ let first_price = project_metadata.minimum_price;
+ let first_bucket_bounds =
+ BidBucketBounds::::get(project_id, first_price).ok_or(Error::::ImpossibleState)?;
+ current_cutoff = (first_price, first_bucket_bounds.1);
+ }
+
+ let (_price, index) = current_cutoff;
+
+ let mut bid = Bids::::get((project_id, index)).ok_or(Error::::ImpossibleState)?;
+
+ let bid_amount = match bid.status {
+ BidStatus::PartiallyAccepted(ct_amount_accepted) => ct_amount_accepted,
+ _ => bid.original_ct_amount,
+ };
+
+ if bid_amount > ct_amount_oversubscribed {
+ bid.status = BidStatus::PartiallyAccepted(bid_amount.saturating_sub(ct_amount_oversubscribed));
+ Bids::::insert((project_id, bid.id), bid);
+ ct_amount_oversubscribed = Zero::zero();
+ } else {
+ bid.status = BidStatus::Rejected;
+ Bids::::insert((project_id, bid.id), bid);
+ ct_amount_oversubscribed = ct_amount_oversubscribed.saturating_sub(bid_amount);
+ }
+
+ OutbidBidsCutoff::::set(project_id, Some(current_cutoff));
+ CTAmountOversubscribed::::insert(project_id, ct_amount_oversubscribed);
+
+ Ok(())
+ }
+
+ pub fn get_next_cutoff(
+ project_id: ProjectId,
+ delta_price: PriceOf,
+ current_price: PriceOf,
+ current_index: u32,
+ ) -> Result<(PriceOf