Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ parameter_types! {
pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
pub const MinimumCreditPurchase: Balance = UNITS / 10;
pub RevenueAccumulationAccount: AccountId = BrokerPalletId::get().into_sub_account_truncating(b"burnstash");
pub const MinimumEndPrice: Balance = UNITS;
}

/// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate
Expand Down Expand Up @@ -319,6 +320,6 @@ impl pallet_broker::Config for Runtime {
type AdminOrigin = EnsureRoot<AccountId>;
type SovereignAccountOf = SovereignAccountOf;
type MaxAutoRenewals = ConstU32<100>;
type PriceAdapter = pallet_broker::CenterTargetPrice<Balance>;
type PriceAdapter = pallet_broker::MinimumPrice<Balance, MinimumEndPrice>;
type MinimumCreditPurchase = MinimumCreditPurchase;
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ parameter_types! {
pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
pub const MinimumCreditPurchase: Balance = UNITS / 10;
pub RevenueAccumulationAccount: AccountId = BrokerPalletId::get().into_sub_account_truncating(b"burnstash");
pub const MinimumEndPrice: Balance = UNITS;
}

/// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate
Expand Down Expand Up @@ -332,6 +333,6 @@ impl pallet_broker::Config for Runtime {
type AdminOrigin = EnsureRoot<AccountId>;
type SovereignAccountOf = SovereignAccountOf;
type MaxAutoRenewals = ConstU32<20>;
type PriceAdapter = pallet_broker::CenterTargetPrice<Balance>;
type PriceAdapter = pallet_broker::MinimumPrice<Balance, MinimumEndPrice>;
type MinimumCreditPurchase = MinimumCreditPurchase;
}
24 changes: 24 additions & 0 deletions prdoc/pr_8630.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
title: "Broker: Introduce min price and adjust renewals to lower market"

doc:
- audience: Runtime Dev
description: |-
pallet-broker now provides an additional `AdaptPrice` implementation:
`MinimumPrice`. This price adapter works exactly the same as the
`CenterTargetPrice` adapter, except that it can be configured with a
minimum price. If set, it will never drop the returned `end_price` (nor the
`target_price`) below that minimum.

Apart from having an adapter to ensure a minimum price, the behavior of
renewals was also adjusted: Renewals are now either bumped by renewal bump
or set to the `end_price` of the current sale - whatever number is higher.
This ensures some market coupling of renewal prices, while still
maintaining some predictability.

crates:
- name: pallet-broker
bump: minor
- name: coretime-rococo-runtime
bump: minor
- name: coretime-westend-runtime
bump: minor
68 changes: 67 additions & 1 deletion substrate/frame/broker/src/adapt_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use crate::{CoreIndex, SaleInfoRecord};
use sp_arithmetic::{traits::One, FixedU64};
use sp_core::{Get, RuntimeDebug};
use sp_runtime::{FixedPointNumber, FixedPointOperand, Saturating};

/// Performance of a past sale.
Expand All @@ -43,7 +44,7 @@ pub struct SalePerformance<Balance> {
}

/// Result of `AdaptPrice::adapt_price`.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
pub struct AdaptedPrices<Balance> {
/// New minimum price to use.
pub end_price: Balance,
Expand Down Expand Up @@ -135,8 +136,39 @@ impl<Balance: FixedPointOperand> AdaptPrice<Balance> for CenterTargetPrice<Balan
}
}

/// `AdaptPrice` like `CenterTargetPrice`, but with a minimum price.
///
/// This price adapter behaves exactly like `CenterTargetPrice`, except that it takes a minimum
/// price and makes sure that the returned `end_price` is never lower than that.
///
/// Target price will also get adjusted if necessary (it will never be less than the end_price).
pub struct MinimumPrice<Balance, MinPrice>(core::marker::PhantomData<(Balance, MinPrice)>);

impl<Balance: FixedPointOperand, MinPrice: Get<Balance>> AdaptPrice<Balance>
for MinimumPrice<Balance, MinPrice>
{
fn leadin_factor_at(when: FixedU64) -> FixedU64 {
CenterTargetPrice::<Balance>::leadin_factor_at(when)
}

fn adapt_price(performance: SalePerformance<Balance>) -> AdaptedPrices<Balance> {
let mut proposal = CenterTargetPrice::<Balance>::adapt_price(performance);
let min_price = MinPrice::get();
if proposal.end_price < min_price {
proposal.end_price = min_price;
}
// Fix target price if necessary:
if proposal.target_price < proposal.end_price {
proposal.target_price = proposal.end_price;
}
proposal
}
}

#[cfg(test)]
mod tests {
use sp_core::ConstU64;

use super::*;

#[test]
Expand Down Expand Up @@ -240,4 +272,38 @@ mod tests {
let prices = CenterTargetPrice::adapt_price(performance);
assert_eq!(prices.target_price, 1000);
}

#[test]
fn minimum_price_works() {
let performance = SalePerformance::new(Some(10), 10);
let prices = MinimumPrice::<u64, ConstU64<10>>::adapt_price(performance);
assert_eq!(prices.end_price, 10);
assert_eq!(prices.target_price, 10);
}

#[test]
fn minimum_price_does_not_affect_valid_target_price() {
let performance = SalePerformance::new(Some(12), 10);
let prices = MinimumPrice::<u64, ConstU64<10>>::adapt_price(performance);
assert_eq!(prices.end_price, 10);
assert_eq!(prices.target_price, 12);
}

#[test]
fn no_minimum_price_works_as_center_target_price() {
let performances = [
(Some(100), 10),
(None, 20),
(Some(1000), 10),
(Some(10), 10),
(Some(1), 1),
(Some(0), 10),
];
for (sellout, end) in performances {
let performance = SalePerformance::new(sellout, end);
let prices_minimum = MinimumPrice::<u64, ConstU64<0>>::adapt_price(performance);
let prices = CenterTargetPrice::adapt_price(performance);
assert_eq!(prices, prices_minimum);
}
}
}
Loading
Loading