diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs
index 4ed5639d6..5ad12e800 100644
--- a/primitives/src/traits.rs
+++ b/primitives/src/traits.rs
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+mod combinatorial_tokens_benchmark_helper;
mod complete_set_operations_api;
mod deploy_pool_api;
mod dispute_api;
@@ -31,6 +32,7 @@ mod payout_api;
mod swaps;
mod zeitgeist_asset;
+pub use combinatorial_tokens_benchmark_helper::*;
pub use complete_set_operations_api::*;
pub use deploy_pool_api::*;
pub use dispute_api::*;
diff --git a/primitives/src/traits/combinatorial_tokens_benchmark_helper.rs b/primitives/src/traits/combinatorial_tokens_benchmark_helper.rs
new file mode 100644
index 000000000..267d20b56
--- /dev/null
+++ b/primitives/src/traits/combinatorial_tokens_benchmark_helper.rs
@@ -0,0 +1,13 @@
+use alloc::vec::Vec;
+use sp_runtime::DispatchResult;
+
+pub trait CombinatorialTokensBenchmarkHelper {
+ type Balance;
+ type MarketId;
+
+ /// Prepares the market with the specified `market_id` to have a particular `payout`.
+ fn setup_payout_vector(
+ market_id: Self::MarketId,
+ payout: Option>,
+ ) -> DispatchResult;
+}
diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs
index 05b85a417..ea6a299c1 100644
--- a/runtime/common/src/lib.rs
+++ b/runtime/common/src/lib.rs
@@ -93,6 +93,9 @@ macro_rules! decl_common_types {
#[cfg(feature = "runtime-benchmarks")]
use zrml_neo_swaps::types::DecisionMarketBenchmarkHelper;
+ #[cfg(feature = "runtime-benchmarks")]
+ use zrml_prediction_markets::types::PredictionMarketsCombinatorialTokensBenchmarkHelper;
+
pub type Block = generic::Block;
type Address = sp_runtime::MultiAddress;
@@ -1154,12 +1157,15 @@ macro_rules! impl_config_traits {
}
impl zrml_combinatorial_tokens::Config for Runtime {
+ #[cfg(feature = "runtime-benchmarks")]
+ type BenchmarkHelper = PredictionMarketsCombinatorialTokensBenchmarkHelper;
type CombinatorialIdManager = CryptographicIdManager;
type MarketCommons = MarketCommons;
type MultiCurrency = AssetManager;
type Payout = PredictionMarkets;
type RuntimeEvent = RuntimeEvent;
type PalletId = CombinatorialTokensPalletId;
+ type WeightInfo = zrml_combinatorial_tokens::weights::WeightInfo;
}
impl zrml_court::Config for Runtime {
@@ -1453,6 +1459,7 @@ macro_rules! create_runtime_api {
list_benchmark!(list, extra, pallet_vesting, Vesting);
list_benchmark!(list, extra, zrml_swaps, Swaps);
list_benchmark!(list, extra, zrml_authorized, Authorized);
+ list_benchmark!(list, extra, zrml_combinatorial_tokens, CombinatorialTokens);
list_benchmark!(list, extra, zrml_court, Court);
list_benchmark!(list, extra, zrml_futarchy, Futarchy);
list_benchmark!(list, extra, zrml_global_disputes, GlobalDisputes);
@@ -1543,6 +1550,7 @@ macro_rules! create_runtime_api {
add_benchmark!(params, batches, pallet_vesting, Vesting);
add_benchmark!(params, batches, zrml_swaps, Swaps);
add_benchmark!(params, batches, zrml_authorized, Authorized);
+ add_benchmark!(params, batches, zrml_combinatorial_tokens, CombinatorialTokens);
add_benchmark!(params, batches, zrml_court, Court);
add_benchmark!(params, batches, zrml_futarchy, Futarchy);
add_benchmark!(params, batches, zrml_global_disputes, GlobalDisputes);
diff --git a/scripts/benchmarks/configuration.sh b/scripts/benchmarks/configuration.sh
index 41ec1f9f9..41409c06a 100644
--- a/scripts/benchmarks/configuration.sh
+++ b/scripts/benchmarks/configuration.sh
@@ -26,8 +26,9 @@ export ORML_PALLETS_STEPS="${ORML_PALLETS_STEPS:-50}"
export ORML_WEIGHT_TEMPLATE="./misc/orml_weight_template.hbs"
export ZEITGEIST_PALLETS=(
- zrml_authorized zrml_court zrml_futarchy zrml_global_disputes zrml_hybrid_router \
- zrml_neo_swaps zrml_orderbook zrml_parimutuel zrml_prediction_markets zrml_swaps zrml_styx \
+ zrml_authorized zrml_combinatorial_tokens zrml_court zrml_futarchy zrml_global_disputes \
+ zrml_hybrid_router zrml_neo_swaps zrml_orderbook zrml_parimutuel zrml_prediction_markets \
+ zrml_swaps zrml_styx \
)
export ZEITGEIST_PALLETS_RUNS="${ZEITGEIST_PALLETS_RUNS:-20}"
export ZEITGEIST_PALLETS_STEPS="${ZEITGEIST_PALLETS_STEPS:-50}"
diff --git a/zrml/combinatorial-tokens/src/benchmarking.rs b/zrml/combinatorial-tokens/src/benchmarking.rs
new file mode 100644
index 000000000..901821fb1
--- /dev/null
+++ b/zrml/combinatorial-tokens/src/benchmarking.rs
@@ -0,0 +1,594 @@
+// Copyright 2024 Forecasting Technologies LTD.
+//
+// This file is part of Zeitgeist.
+//
+// Zeitgeist 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.
+//
+// Zeitgeist 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 Zeitgeist. If not, see .
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use crate::{BalanceOf, Call, Config, Event, MarketIdOf, Pallet};
+use alloc::{vec, vec::Vec};
+use frame_benchmarking::v2::*;
+use frame_support::dispatch::RawOrigin;
+use frame_system::Pallet as System;
+use orml_traits::MultiCurrency;
+use sp_runtime::{traits::Zero, Perbill};
+use zeitgeist_primitives::{
+ math::fixed::{BaseProvider, ZeitgeistBase},
+ traits::{CombinatorialTokensBenchmarkHelper, MarketCommonsPalletApi},
+ types::{Asset, Market, MarketCreation, MarketPeriod, MarketStatus, MarketType, ScoringRule},
+};
+
+fn create_market(caller: T::AccountId, asset_count: u16) -> MarketIdOf {
+ let market = Market {
+ market_id: Default::default(),
+ base_asset: Asset::Ztg,
+ creation: MarketCreation::Permissionless,
+ creator_fee: Perbill::zero(),
+ creator: caller.clone(),
+ oracle: caller,
+ metadata: Default::default(),
+ market_type: MarketType::Categorical(asset_count),
+ period: MarketPeriod::Block(0u32.into()..1u32.into()),
+ deadlines: Default::default(),
+ scoring_rule: ScoringRule::AmmCdaHybrid,
+ status: MarketStatus::Active,
+ report: None,
+ resolved_outcome: None,
+ dispute_mechanism: None,
+ bonds: Default::default(),
+ early_close: None,
+ };
+ T::MarketCommons::push_market(market).unwrap()
+}
+
+fn create_payout_vector(asset_count: u16) -> Vec> {
+ let mut result = vec![Zero::zero(); asset_count as usize];
+ result[0] = ZeitgeistBase::get().unwrap();
+
+ result
+}
+
+#[benchmarks]
+mod benchmarks {
+ use super::*;
+
+ #[benchmark]
+ fn split_position_vertical_sans_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+
+ let parent_collection_id = None;
+ let market_id = create_market::(alice.clone(), position_count.try_into().unwrap());
+ // Partition is 10...0, 010...0, ..., 0...01.
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; position_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ T::MultiCurrency::deposit(Asset::Ztg, &alice, amount).unwrap();
+
+ #[extrinsic_call]
+ split_position(
+ RawOrigin::Signed(alice.clone()),
+ parent_collection_id,
+ market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let collection_ids: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::collection_id_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+ let assets_out: Vec<_> = collection_ids
+ .iter()
+ .cloned()
+ .map(|collection_id| {
+ Pallet::::position_from_collection_id(market_id, collection_id).unwrap()
+ })
+ .collect();
+ let expected_event = ::RuntimeEvent::from(Event::::TokenSplit {
+ who: alice,
+ parent_collection_id,
+ market_id,
+ partition,
+ asset_in: Asset::Ztg,
+ assets_out,
+ collection_ids,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn split_position_vertical_with_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+
+ let parent_collection_id = None;
+ let parent_market_id = create_market::(alice.clone(), 2);
+
+ // The collection/position that we're merging into.
+ let cid_01 = Pallet::::collection_id_from_parent_collection(
+ parent_collection_id,
+ parent_market_id,
+ vec![false, true],
+ false,
+ )
+ .unwrap();
+ let pos_01 = Pallet::::position_from_collection_id(parent_market_id, cid_01).unwrap();
+
+ let child_market_id = create_market::(alice.clone(), position_count.try_into().unwrap());
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; position_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ T::MultiCurrency::deposit(pos_01, &alice, amount).unwrap();
+
+ #[extrinsic_call]
+ split_position(
+ RawOrigin::Signed(alice.clone()),
+ Some(cid_01),
+ child_market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let collection_ids: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::collection_id_from_parent_collection(
+ Some(cid_01),
+ child_market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+ let assets_out: Vec<_> = collection_ids
+ .iter()
+ .cloned()
+ .map(|collection_id| {
+ Pallet::::position_from_collection_id(child_market_id, collection_id).unwrap()
+ })
+ .collect();
+ let expected_event = ::RuntimeEvent::from(Event::::TokenSplit {
+ who: alice,
+ parent_collection_id: Some(cid_01),
+ market_id: child_market_id,
+ partition,
+ asset_in: pos_01,
+ assets_out,
+ collection_ids,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn split_position_horizontal(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+ let asset_count = position_count + 1;
+
+ let parent_collection_id = None;
+ let market_id = create_market::(alice.clone(), asset_count.try_into().unwrap());
+ // Partition is 10...0, 010...0, ..., 0...010. Doesn't contain 0...01.
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; asset_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ // Add 1...10 to Alice's account.
+ let mut asset_in_index_set = vec![true; asset_count];
+ *asset_in_index_set.last_mut().unwrap() = false;
+ let asset_in = Pallet::::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ asset_in_index_set,
+ false,
+ )
+ .unwrap();
+ T::MultiCurrency::deposit(asset_in, &alice, amount).unwrap();
+
+ #[extrinsic_call]
+ split_position(
+ RawOrigin::Signed(alice.clone()),
+ parent_collection_id,
+ market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let collection_ids: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::collection_id_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+ let assets_out: Vec<_> = collection_ids
+ .iter()
+ .cloned()
+ .map(|collection_id| {
+ Pallet::::position_from_collection_id(market_id, collection_id).unwrap()
+ })
+ .collect();
+ let expected_event = ::RuntimeEvent::from(Event::::TokenSplit {
+ who: alice,
+ parent_collection_id,
+ market_id,
+ partition,
+ asset_in,
+ assets_out,
+ collection_ids,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn merge_position_vertical_sans_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+
+ let parent_collection_id = None;
+ let market_id = create_market::(alice.clone(), position_count.try_into().unwrap());
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; position_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ let assets_in: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+
+ for &asset in assets_in.iter() {
+ T::MultiCurrency::deposit(asset, &alice, amount).unwrap();
+ }
+ T::MultiCurrency::deposit(Asset::Ztg, &Pallet::::account_id(), amount).unwrap();
+
+ #[extrinsic_call]
+ merge_position(
+ RawOrigin::Signed(alice.clone()),
+ parent_collection_id,
+ market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let expected_event = ::RuntimeEvent::from(Event::::TokenMerged {
+ who: alice,
+ parent_collection_id,
+ market_id,
+ partition,
+ asset_out: Asset::Ztg,
+ assets_in,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn merge_position_vertical_with_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+
+ let parent_collection_id = None;
+ let parent_market_id = create_market::(alice.clone(), 2);
+
+ // The collection/position that we're merging into.
+ let cid_01 = Pallet::::collection_id_from_parent_collection(
+ parent_collection_id,
+ parent_market_id,
+ vec![false, true],
+ false,
+ )
+ .unwrap();
+ let pos_01 = Pallet::::position_from_collection_id(parent_market_id, cid_01).unwrap();
+
+ let child_market_id = create_market::(alice.clone(), position_count.try_into().unwrap());
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; position_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ let assets_in: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::position_from_parent_collection(
+ Some(cid_01),
+ child_market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+
+ for &asset in assets_in.iter() {
+ T::MultiCurrency::deposit(asset, &alice, amount).unwrap();
+ }
+
+ #[extrinsic_call]
+ merge_position(
+ RawOrigin::Signed(alice.clone()),
+ Some(cid_01),
+ child_market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let expected_event = ::RuntimeEvent::from(Event::::TokenMerged {
+ who: alice,
+ parent_collection_id: Some(cid_01),
+ market_id: child_market_id,
+ partition,
+ asset_out: pos_01,
+ assets_in,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn merge_position_horizontal(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let position_count: usize = n.try_into().unwrap();
+ let asset_count = position_count + 1;
+
+ let parent_collection_id = None;
+ let market_id = create_market::(alice.clone(), asset_count.try_into().unwrap());
+ // Partition is 10...0, 010...0, ..., 0...010. Doesn't contain 0...01.
+ let partition: Vec<_> = (0..position_count)
+ .map(|index| {
+ let mut index_set = vec![false; asset_count];
+ index_set[index] = true;
+
+ index_set
+ })
+ .collect();
+ let amount = ZeitgeistBase::get().unwrap();
+
+ let assets_in: Vec<_> = partition
+ .iter()
+ .cloned()
+ .map(|index_set| {
+ Pallet::::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set,
+ false,
+ )
+ .unwrap()
+ })
+ .collect();
+
+ for &asset in assets_in.iter() {
+ T::MultiCurrency::deposit(asset, &alice, amount).unwrap();
+ }
+
+ #[extrinsic_call]
+ merge_position(
+ RawOrigin::Signed(alice.clone()),
+ parent_collection_id,
+ market_id,
+ partition.clone(),
+ amount,
+ true,
+ );
+
+ let mut asset_out_index_set = vec![true; asset_count];
+ *asset_out_index_set.last_mut().unwrap() = false;
+ let asset_out = Pallet::::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ asset_out_index_set,
+ false,
+ )
+ .unwrap();
+ let expected_event = ::RuntimeEvent::from(Event::::TokenMerged {
+ who: alice,
+ parent_collection_id,
+ market_id,
+ partition,
+ asset_out,
+ assets_in,
+ amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn redeem_position_sans_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let n_u16: u16 = n.try_into().unwrap();
+ let asset_count = n_u16 + 1;
+
+ // `index_set` has `n` entries that are `true`, which results in `n` iterations in the `for`
+ // loop in `redeem_position`.
+ let mut index_set = vec![true; asset_count as usize];
+ *index_set.last_mut().unwrap() = false;
+
+ let parent_collection_id = None;
+ let market_id = create_market::(alice.clone(), asset_count);
+
+ let payout_vector = create_payout_vector::(asset_count);
+ T::BenchmarkHelper::setup_payout_vector(market_id, Some(payout_vector)).unwrap();
+
+ // Deposit tokens for Alice and the pallet account.
+ let position = Pallet::::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set.clone(),
+ false,
+ )
+ .unwrap();
+ let amount = ZeitgeistBase::get().unwrap();
+ T::MultiCurrency::deposit(position, &alice, amount).unwrap();
+ T::MultiCurrency::deposit(Asset::Ztg, &Pallet::::account_id(), amount).unwrap();
+
+ #[extrinsic_call]
+ redeem_position(
+ RawOrigin::Signed(alice.clone()),
+ parent_collection_id,
+ market_id,
+ index_set.clone(),
+ true,
+ );
+
+ let expected_event = ::RuntimeEvent::from(Event::::TokenRedeemed {
+ who: alice,
+ parent_collection_id,
+ market_id,
+ index_set,
+ asset_in: position,
+ amount_in: amount,
+ asset_out: Asset::Ztg,
+ amount_out: amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ #[benchmark]
+ fn redeem_position_with_parent(n: Linear<2, 32>) {
+ let alice: T::AccountId = whitelisted_caller();
+
+ let n_u16: u16 = n.try_into().unwrap();
+ let asset_count = n_u16 + 1;
+
+ // `index_set` has `n` entries that are `true`, which results in `n` iterations in the `for`
+ // loop in `redeem_position`.
+ let mut index_set = vec![true; asset_count as usize];
+ *index_set.last_mut().unwrap() = false;
+
+ let parent_market_id = create_market::(alice.clone(), 2);
+ let cid_01 = Pallet::::collection_id_from_parent_collection(
+ None,
+ parent_market_id,
+ vec![false, true],
+ false,
+ )
+ .unwrap();
+ let pos_01 = Pallet::::position_from_collection_id(parent_market_id, cid_01).unwrap();
+
+ let child_market_id = create_market::(alice.clone(), asset_count);
+ let pos_01_10 = Pallet::::position_from_parent_collection(
+ Some(cid_01),
+ child_market_id,
+ index_set.clone(),
+ false,
+ )
+ .unwrap();
+ let amount = ZeitgeistBase::get().unwrap();
+ T::MultiCurrency::deposit(pos_01_10, &alice, amount).unwrap();
+
+ let payout_vector = create_payout_vector::(asset_count);
+ T::BenchmarkHelper::setup_payout_vector(child_market_id, Some(payout_vector)).unwrap();
+
+ #[extrinsic_call]
+ redeem_position(
+ RawOrigin::Signed(alice.clone()),
+ Some(cid_01),
+ child_market_id,
+ index_set.clone(),
+ true,
+ );
+
+ let expected_event = ::RuntimeEvent::from(Event::::TokenRedeemed {
+ who: alice,
+ parent_collection_id: Some(cid_01),
+ market_id: child_market_id,
+ index_set,
+ asset_in: pos_01_10,
+ amount_in: amount,
+ asset_out: pos_01,
+ amount_out: amount,
+ });
+ System::::assert_last_event(expected_event.into());
+ }
+
+ impl_benchmark_test_suite!(
+ Pallet,
+ crate::mock::ext_builder::ExtBuilder::build(),
+ crate::mock::runtime::Runtime
+ );
+}
diff --git a/zrml/combinatorial-tokens/src/lib.rs b/zrml/combinatorial-tokens/src/lib.rs
index 6f4a34c9c..0706ca56a 100644
--- a/zrml/combinatorial-tokens/src/lib.rs
+++ b/zrml/combinatorial-tokens/src/lib.rs
@@ -27,21 +27,23 @@
extern crate alloc;
+mod benchmarking;
pub mod mock;
mod tests;
mod traits;
pub mod types;
+pub mod weights;
pub use pallet::*;
#[frame_support::pallet]
mod pallet {
- use crate::traits::CombinatorialIdManager;
+ use crate::{traits::CombinatorialIdManager, weights::WeightInfoZeitgeist};
use alloc::{vec, vec::Vec};
use core::marker::PhantomData;
use frame_support::{
ensure,
- pallet_prelude::{IsType, StorageVersion},
+ pallet_prelude::{DispatchResultWithPostInfo, IsType, StorageVersion},
require_transactional, transactional, PalletId,
};
use frame_system::{
@@ -51,7 +53,7 @@ mod pallet {
use orml_traits::MultiCurrency;
use sp_runtime::{
traits::{AccountIdConversion, Get, Zero},
- DispatchError, DispatchResult,
+ DispatchError, SaturatedConversion,
};
use zeitgeist_primitives::{
math::{checked_ops_res::CheckedAddRes, fixed::FixedMul},
@@ -59,8 +61,17 @@ mod pallet {
types::{Asset, CombinatorialId},
};
+ #[cfg(feature = "runtime-benchmarks")]
+ use zeitgeist_primitives::traits::CombinatorialTokensBenchmarkHelper;
+
#[pallet::config]
pub trait Config: frame_system::Config {
+ #[cfg(feature = "runtime-benchmarks")]
+ type BenchmarkHelper: CombinatorialTokensBenchmarkHelper<
+ Balance = BalanceOf,
+ MarketId = MarketIdOf,
+ >;
+
type CombinatorialIdManager: CombinatorialIdManager<
Asset = AssetOf,
MarketId = MarketIdOf,
@@ -77,6 +88,8 @@ mod pallet {
#[pallet::constant]
type PalletId: Get;
+
+ type WeightInfo: WeightInfoZeitgeist;
}
#[pallet::pallet]
@@ -103,8 +116,9 @@ mod pallet {
/// User `who` has split `amount` units of token `asset_in` into the same amount of each
/// token in `assets_out` using `partition`. The ith element of `partition` matches the ith
/// element of `assets_out`, so `assets_out[i]` is the outcome represented by the specified
- /// `parent_collection_id` together with `partition` in `market_id`.
- /// TODO The second sentence is confusing.
+ /// `parent_collection_id` when split using `partition[i]` in `market_id`. The same goes for
+ /// the `collection_ids` vector, the ith element of which specifies the collection ID of
+ /// `assets_out[i]`.
TokenSplit {
who: AccountIdOf,
parent_collection_id: Option,
@@ -117,13 +131,35 @@ mod pallet {
},
/// User `who` has merged `amount` units of each of the tokens in `assets_in` into the same
- /// amount of `asset_out`.
+ /// amount of `asset_out`. The ith element of the `partition` matches the ith element of
+ /// `assets_in`, so `assets_in[i]` is the outcome represented by the specified
+ /// `parent_collection_id` when split using `partition[i]` in `market_id`. Note that the
+ /// `parent_collection_id` is equal to the collection ID of the position `asset_out`; if
+ /// `asset_out` is the collateral token, then `parent_collection_id` is `None`.
TokenMerged {
who: AccountIdOf,
+ parent_collection_id: Option,
+ market_id: MarketIdOf,
+ partition: Vec>,
asset_out: AssetOf,
assets_in: Vec>,
amount: BalanceOf,
},
+
+ /// User `who` has redeemed `amount_in` units of `asset_in` for `amount_out` units of
+ /// `asset_out` using the report for the market specified by `market_id`. The
+ /// `parent_collection_id` specifies the collection ID of the `asset_out`; it is `None` if
+ /// the `asset_out` is the collateral token.
+ TokenRedeemed {
+ who: AccountIdOf,
+ parent_collection_id: Option,
+ market_id: MarketIdOf,
+ index_set: Vec,
+ asset_in: AssetOf,
+ amount_in: BalanceOf,
+ asset_out: AssetOf,
+ amount_out: BalanceOf,
+ },
}
#[pallet::error]
@@ -154,7 +190,13 @@ mod pallet {
#[pallet::call]
impl Pallet {
#[pallet::call_index(0)]
- #[pallet::weight({0})] // TODO
+ #[pallet::weight(
+ T::WeightInfo::split_position_vertical_sans_parent(partition.len().saturated_into())
+ .max(T::WeightInfo::split_position_vertical_with_parent(
+ partition.len().saturated_into(),
+ ))
+ .max(T::WeightInfo::split_position_horizontal(partition.len().saturated_into()))
+ )]
#[transactional]
pub fn split_position(
origin: OriginFor,
@@ -163,13 +205,27 @@ mod pallet {
market_id: MarketIdOf,
partition: Vec>,
amount: BalanceOf,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
- Self::do_split_position(who, parent_collection_id, market_id, partition, amount)
+ Self::do_split_position(
+ who,
+ parent_collection_id,
+ market_id,
+ partition,
+ amount,
+ force_max_work,
+ )
}
#[pallet::call_index(1)]
- #[pallet::weight({0})] // TODO
+ #[pallet::weight(
+ T::WeightInfo::merge_position_vertical_sans_parent(partition.len().saturated_into())
+ .max(T::WeightInfo::merge_position_vertical_with_parent(
+ partition.len().saturated_into(),
+ ))
+ .max(T::WeightInfo::merge_position_horizontal(partition.len().saturated_into()))
+ )]
#[transactional]
pub fn merge_position(
origin: OriginFor,
@@ -177,22 +233,40 @@ mod pallet {
market_id: MarketIdOf,
partition: Vec>,
amount: BalanceOf,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
- Self::do_merge_position(who, parent_collection_id, market_id, partition, amount)
+ Self::do_merge_position(
+ who,
+ parent_collection_id,
+ market_id,
+ partition,
+ amount,
+ force_max_work,
+ )
}
#[pallet::call_index(2)]
- #[pallet::weight({0})] // TODO
+ #[pallet::weight(
+ T::WeightInfo::redeem_position_with_parent(index_set.len().saturated_into())
+ .max(T::WeightInfo::redeem_position_sans_parent(index_set.len().saturated_into()))
+ )]
#[transactional]
pub fn redeem_position(
origin: OriginFor,
parent_collection_id: Option>,
market_id: MarketIdOf,
index_set: Vec,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
- Self::do_redeem_position(who, parent_collection_id, market_id, index_set)
+ Self::do_redeem_position(
+ who,
+ parent_collection_id,
+ market_id,
+ index_set,
+ force_max_work,
+ )
}
}
@@ -204,14 +278,15 @@ mod pallet {
market_id: MarketIdOf,
partition: Vec>,
amount: BalanceOf,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let market = T::MarketCommons::market(&market_id)?;
let collateral_token = market.base_asset;
let free_index_set = Self::free_index_set(market_id, &partition)?;
// Destroy/store the tokens to be split.
- let split_asset = if !free_index_set.iter().any(|&i| i) {
+ let (weight, split_asset) = if !free_index_set.iter().any(|&i| i) {
// Vertical split.
if let Some(pci) = parent_collection_id {
// Split combinatorial token into higher level position. Destroy the tokens.
@@ -224,7 +299,11 @@ mod pallet {
T::MultiCurrency::ensure_can_withdraw(position, &who, amount)?;
T::MultiCurrency::withdraw(position, &who, amount)?;
- position
+ let weight = T::WeightInfo::split_position_vertical_with_parent(
+ partition.len().saturated_into(),
+ );
+
+ (weight, position)
} else {
// Split collateral into first level position. Store the collateral in the
// pallet account. This is the legacy `buy_complete_set`.
@@ -236,7 +315,11 @@ mod pallet {
amount,
)?;
- collateral_token
+ let weight = T::WeightInfo::split_position_vertical_sans_parent(
+ partition.len().saturated_into(),
+ );
+
+ (weight, collateral_token)
}
} else {
// Horizontal split.
@@ -245,11 +328,15 @@ mod pallet {
parent_collection_id,
market_id,
remaining_index_set,
+ force_max_work,
)?;
T::MultiCurrency::ensure_can_withdraw(position, &who, amount)?;
T::MultiCurrency::withdraw(position, &who, amount)?;
- position
+ let weight =
+ T::WeightInfo::split_position_horizontal(partition.len().saturated_into());
+
+ (weight, position)
};
// Deposit the new tokens.
@@ -261,6 +348,7 @@ mod pallet {
parent_collection_id,
market_id,
index_set,
+ force_max_work,
)
})
.collect::, _>>()?;
@@ -269,6 +357,8 @@ mod pallet {
.cloned()
.map(|collection_id| Self::position_from_collection_id(market_id, collection_id))
.collect::, _>>()?;
+ // Security note: Safe as iterations are limited to the number of assets in the market
+ // thanks to the `ensure!` invocations in `Self::free_index_set`.
for &position in positions.iter() {
T::MultiCurrency::deposit(position, &who, amount)?;
}
@@ -284,7 +374,7 @@ mod pallet {
amount,
});
- Ok(())
+ Ok(Some(weight).into())
}
#[require_transactional]
@@ -294,13 +384,14 @@ mod pallet {
market_id: MarketIdOf,
partition: Vec>,
amount: BalanceOf,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let market = T::MarketCommons::market(&market_id)?;
let collateral_token = market.base_asset;
let free_index_set = Self::free_index_set(market_id, &partition)?;
- // Destory the old tokens.
+ // Destroy the old tokens.
let positions = partition
.iter()
.cloned()
@@ -309,15 +400,18 @@ mod pallet {
parent_collection_id,
market_id,
index_set,
+ force_max_work,
)
})
.collect::, _>>()?;
+ // Security note: Safe as iterations are limited to the number of assets in the market
+ // thanks to the `ensure!` invocations in `Self::free_index_set`.
for &position in positions.iter() {
T::MultiCurrency::withdraw(position, &who, amount)?;
}
// Destroy/store the tokens to be split.
- let merged_token = if !free_index_set.iter().any(|&i| i) {
+ let (weight, merged_token) = if !free_index_set.iter().any(|&i| i) {
// Vertical merge.
if let Some(pci) = parent_collection_id {
// Merge combinatorial token into higher level position. Destroy the tokens.
@@ -326,7 +420,11 @@ mod pallet {
let position = Asset::CombinatorialToken(position_id);
T::MultiCurrency::deposit(position, &who, amount)?;
- position
+ let weight = T::WeightInfo::merge_position_vertical_with_parent(
+ partition.len().saturated_into(),
+ );
+
+ (weight, position)
} else {
// Merge first-level tokens into collateral. Move collateral from the pallet
// account to the user's wallet. This is the legacy `sell_complete_set`.
@@ -337,7 +435,11 @@ mod pallet {
amount,
)?;
- collateral_token
+ let weight = T::WeightInfo::merge_position_vertical_sans_parent(
+ partition.len().saturated_into(),
+ );
+
+ (weight, collateral_token)
}
} else {
// Horizontal merge.
@@ -346,20 +448,27 @@ mod pallet {
parent_collection_id,
market_id,
remaining_index_set,
+ force_max_work,
)?;
T::MultiCurrency::deposit(position, &who, amount)?;
- position
+ let weight =
+ T::WeightInfo::merge_position_horizontal(partition.len().saturated_into());
+
+ (weight, position)
};
Self::deposit_event(Event::::TokenMerged {
who,
+ parent_collection_id,
+ market_id,
+ partition,
asset_out: merged_token,
assets_in: positions,
amount,
});
- Ok(())
+ Ok(Some(weight).into())
}
fn do_redeem_position(
@@ -367,7 +476,8 @@ mod pallet {
parent_collection_id: Option>,
market_id: MarketIdOf,
index_set: Vec,
- ) -> DispatchResult {
+ force_max_work: bool,
+ ) -> DispatchResultWithPostInfo {
let payout_vector =
T::Payout::payout_vector(market_id).ok_or(Error::::PayoutVectorNotFound)?;
@@ -381,6 +491,8 @@ mod pallet {
// Add up values of each outcome.
let mut total_stake: BalanceOf = Zero::zero();
+ // Security note: Safe because `zip` will limit this loop to `payout_vector.len()`
+ // iterations.
for (&index, value) in index_set.iter().zip(payout_vector.iter()) {
if index {
total_stake = total_stake.checked_add_res(value)?;
@@ -389,19 +501,28 @@ mod pallet {
ensure!(!total_stake.is_zero(), Error::::TokenHasNoValue);
- let position =
- Self::position_from_parent_collection(parent_collection_id, market_id, index_set)?;
+ let position = Self::position_from_parent_collection(
+ parent_collection_id,
+ market_id,
+ index_set.clone(),
+ force_max_work,
+ )?;
let amount = T::MultiCurrency::free_balance(position, &who);
ensure!(!amount.is_zero(), Error::::NoTokensFound);
T::MultiCurrency::withdraw(position, &who, amount)?;
let total_payout = total_stake.bmul(amount)?;
- if let Some(pci) = parent_collection_id {
+ let (weight, asset_out) = if let Some(pci) = parent_collection_id {
// Merge combinatorial token into higher level position. Destroy the tokens.
let position_id = T::CombinatorialIdManager::get_position_id(collateral_token, pci);
let position = Asset::CombinatorialToken(position_id);
T::MultiCurrency::deposit(position, &who, total_payout)?;
+
+ let weight =
+ T::WeightInfo::redeem_position_with_parent(index_set.len().saturated_into());
+
+ (weight, position)
} else {
T::MultiCurrency::transfer(
collateral_token,
@@ -409,16 +530,32 @@ mod pallet {
&who,
total_payout,
)?;
- }
- Ok(())
+ let weight =
+ T::WeightInfo::redeem_position_sans_parent(index_set.len().saturated_into());
+
+ (weight, collateral_token)
+ };
+
+ Self::deposit_event(Event::::TokenRedeemed {
+ who,
+ parent_collection_id,
+ market_id,
+ index_set,
+ asset_in: position,
+ amount_in: amount,
+ asset_out,
+ amount_out: total_payout,
+ });
+
+ Ok(Some(weight).into())
}
pub(crate) fn account_id() -> T::AccountId {
T::PalletId::get().into_account_truncating()
}
- fn free_index_set(
+ pub(crate) fn free_index_set(
market_id: MarketIdOf,
partition: &[Vec],
) -> Result, DispatchError> {
@@ -447,21 +584,22 @@ mod pallet {
Ok(free_index_set)
}
- fn collection_id_from_parent_collection(
+ pub(crate) fn collection_id_from_parent_collection(
parent_collection_id: Option>,
market_id: MarketIdOf,
index_set: Vec,
+ force_max_work: bool,
) -> Result, DispatchError> {
T::CombinatorialIdManager::get_collection_id(
parent_collection_id,
market_id,
index_set,
- false, // TODO Expose this parameter!
+ force_max_work,
)
.ok_or(Error::::InvalidCollectionId.into())
}
- fn position_from_collection_id(
+ pub(crate) fn position_from_collection_id(
market_id: MarketIdOf,
collection_id: CombinatorialIdOf,
) -> Result, DispatchError> {
@@ -475,15 +613,17 @@ mod pallet {
Ok(asset)
}
- fn position_from_parent_collection(
+ pub(crate) fn position_from_parent_collection(
parent_collection_id: Option>,
market_id: MarketIdOf,
index_set: Vec,
+ force_max_work: bool,
) -> Result, DispatchError> {
let collection_id = Self::collection_id_from_parent_collection(
parent_collection_id,
market_id,
index_set,
+ force_max_work,
)?;
Self::position_from_collection_id(market_id, collection_id)
diff --git a/zrml/combinatorial-tokens/src/mock/runtime.rs b/zrml/combinatorial-tokens/src/mock/runtime.rs
index 157841ca7..ede07e829 100644
--- a/zrml/combinatorial-tokens/src/mock/runtime.rs
+++ b/zrml/combinatorial-tokens/src/mock/runtime.rs
@@ -16,7 +16,7 @@
// along with Zeitgeist. If not, see .
use crate as zrml_combinatorial_tokens;
-use crate::{mock::types::MockPayout, types::CryptographicIdManager};
+use crate::{mock::types::MockPayout, types::CryptographicIdManager, weights::WeightInfo};
use frame_support::{construct_runtime, traits::Everything, Blake2_256};
use frame_system::mocking::MockBlock;
use sp_runtime::traits::{BlakeTwo256, ConstU32, IdentityLookup};
@@ -30,6 +30,9 @@ use zeitgeist_primitives::{
},
};
+#[cfg(feature = "runtime-benchmarks")]
+use crate::mock::types::BenchmarkHelper;
+
construct_runtime! {
pub enum Runtime {
CombinatorialTokens: zrml_combinatorial_tokens,
@@ -43,12 +46,15 @@ construct_runtime! {
}
impl zrml_combinatorial_tokens::Config for Runtime {
+ #[cfg(feature = "runtime-benchmarks")]
+ type BenchmarkHelper = BenchmarkHelper;
type CombinatorialIdManager = CryptographicIdManager;
type MarketCommons = MarketCommons;
type MultiCurrency = Currencies;
type Payout = MockPayout;
type RuntimeEvent = RuntimeEvent;
type PalletId = CombinatorialTokensPalletId;
+ type WeightInfo = WeightInfo;
}
impl orml_currencies::Config for Runtime {
diff --git a/zrml/combinatorial-tokens/src/mock/types/benchmark_helper.rs b/zrml/combinatorial-tokens/src/mock/types/benchmark_helper.rs
new file mode 100644
index 000000000..36d1438fa
--- /dev/null
+++ b/zrml/combinatorial-tokens/src/mock/types/benchmark_helper.rs
@@ -0,0 +1,25 @@
+use crate::{
+ mock::{runtime::Runtime, types::MockPayout},
+ BalanceOf, MarketIdOf,
+};
+use alloc::vec::Vec;
+use sp_runtime::DispatchResult;
+use zeitgeist_primitives::traits::CombinatorialTokensBenchmarkHelper;
+
+pub struct BenchmarkHelper;
+
+impl CombinatorialTokensBenchmarkHelper for BenchmarkHelper {
+ type Balance = BalanceOf;
+ type MarketId = MarketIdOf;
+
+ /// A bit of a messy implementation as this sets the return value of the next `payout_vector`
+ /// call, regardless of what `_market_id` is.
+ fn setup_payout_vector(
+ _market_id: Self::MarketId,
+ payout: Option>,
+ ) -> DispatchResult {
+ MockPayout::set_return_value(payout);
+
+ Ok(())
+ }
+}
diff --git a/zrml/combinatorial-tokens/src/mock/types/mod.rs b/zrml/combinatorial-tokens/src/mock/types/mod.rs
index 03136bcda..6f3afbeaf 100644
--- a/zrml/combinatorial-tokens/src/mock/types/mod.rs
+++ b/zrml/combinatorial-tokens/src/mock/types/mod.rs
@@ -15,6 +15,10 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmark_helper;
mod payout;
-pub use payout::MockPayout;
+#[cfg(feature = "runtime-benchmarks")]
+pub(crate) use benchmark_helper::BenchmarkHelper;
+pub(crate) use payout::MockPayout;
diff --git a/zrml/combinatorial-tokens/src/tests/integration.rs b/zrml/combinatorial-tokens/src/tests/integration.rs
index ced2f9ae1..83a5162bd 100644
--- a/zrml/combinatorial-tokens/src/tests/integration.rs
+++ b/zrml/combinatorial-tokens/src/tests/integration.rs
@@ -42,6 +42,7 @@ fn split_followed_by_merge_vertical_no_parent() {
market_id,
partition.clone(),
amount,
+ false,
));
assert_eq!(alice.free_balance(Asset::Ztg), _99);
assert_eq!(alice.free_balance(ct_001), _1);
@@ -54,6 +55,7 @@ fn split_followed_by_merge_vertical_no_parent() {
market_id,
partition,
amount,
+ false,
));
assert_eq!(alice.free_balance(Asset::Ztg), _100);
assert_eq!(alice.free_balance(ct_001), 0);
@@ -94,6 +96,7 @@ fn split_followed_by_merge_vertical_with_parent() {
parent_market_id,
parent_partition.clone(),
parent_amount,
+ false,
));
let child_market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
@@ -110,6 +113,7 @@ fn split_followed_by_merge_vertical_with_parent() {
child_market_id,
child_partition.clone(),
child_amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), parent_amount - child_amount);
assert_eq!(alice.free_balance(ct_110), parent_amount);
@@ -124,6 +128,7 @@ fn split_followed_by_merge_vertical_with_parent() {
child_market_id,
child_partition,
child_amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), parent_amount);
assert_eq!(alice.free_balance(ct_110), parent_amount);
@@ -138,6 +143,7 @@ fn split_followed_by_merge_vertical_with_parent() {
parent_market_id,
parent_partition,
parent_amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
assert_eq!(alice.free_balance(ct_110), 0);
@@ -219,6 +225,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_0,
partition_0.clone(),
amount,
+ false,
));
// Split C into C&(U|V) and C&(W|X).
@@ -228,6 +235,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_1,
partition_1.clone(),
amount,
+ false,
));
// Split A|B into into (A|B)&(U|V) and (A|B)&(W|X).
@@ -237,6 +245,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_1,
partition_1.clone(),
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
@@ -256,6 +265,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_0,
partition_0.clone(),
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
@@ -275,6 +285,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_0,
partition_0,
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
@@ -294,6 +305,7 @@ fn split_followed_by_merge_vertical_with_parent_in_opposite_order() {
market_1,
partition_1,
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
@@ -325,6 +337,7 @@ fn split_vertical_followed_by_horizontal_split_no_parent() {
market_id,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
amount,
+ false,
));
assert_ok!(CombinatorialTokens::split_position(
alice.signed(),
@@ -332,6 +345,7 @@ fn split_vertical_followed_by_horizontal_split_no_parent() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0]],
amount,
+ false,
));
let ct_001 = CombinatorialToken([
@@ -358,6 +372,7 @@ fn split_vertical_followed_by_horizontal_split_no_parent() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0], vec![B0, B0, B1]],
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 2 * amount);
@@ -383,6 +398,7 @@ fn split_vertical_followed_by_horizontal_split_with_parent() {
parent_market_id,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
parent_amount,
+ false,
));
let child_market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
@@ -425,6 +441,7 @@ fn split_vertical_followed_by_horizontal_split_with_parent() {
child_market_id,
vec![vec![B0, B0, B1, B1], vec![B1, B1, B0, B0]],
child_amount_first_pass,
+ false,
));
assert_ok!(CombinatorialTokens::split_position(
alice.signed(),
@@ -432,6 +449,7 @@ fn split_vertical_followed_by_horizontal_split_with_parent() {
child_market_id,
vec![vec![B1, B0, B0, B0], vec![B0, B1, B0, B0]],
child_amount_first_pass,
+ false,
));
assert_eq!(alice.free_balance(ct_001), parent_amount - child_amount_first_pass);
@@ -451,6 +469,7 @@ fn split_vertical_followed_by_horizontal_split_with_parent() {
child_market_id,
vec![vec![B1, B0, B0, B0], vec![B0, B1, B0, B0], vec![B0, B0, B1, B1]],
child_amount_second_pass,
+ false,
));
let total_child_amount = child_amount_first_pass + child_amount_second_pass;
@@ -488,6 +507,7 @@ fn split_horizontal_followed_by_merge_horizontal() {
market_id,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
amount,
+ false,
));
assert_ok!(CombinatorialTokens::split_position(
@@ -496,6 +516,7 @@ fn split_horizontal_followed_by_merge_horizontal() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0]],
amount,
+ false,
));
assert_ok!(CombinatorialTokens::merge_position(
@@ -504,6 +525,7 @@ fn split_horizontal_followed_by_merge_horizontal() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0]],
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), _1);
diff --git a/zrml/combinatorial-tokens/src/tests/merge_position.rs b/zrml/combinatorial-tokens/src/tests/merge_position.rs
index b724e57c9..077685f29 100644
--- a/zrml/combinatorial-tokens/src/tests/merge_position.rs
+++ b/zrml/combinatorial-tokens/src/tests/merge_position.rs
@@ -41,20 +41,35 @@ fn merge_position_works_no_parent(
let pallet =
Account::new(Pallet::::account_id()).deposit(collateral, amount).unwrap();
+ let parent_collection_id = None;
let market_id = create_market(collateral, MarketType::Categorical(3));
-
+ let partition = vec![vec![B0, B0, B1], vec![B1, B1, B0]];
assert_ok!(CombinatorialTokens::merge_position(
alice.signed(),
- None,
+ parent_collection_id,
market_id,
- vec![vec![B0, B0, B1], vec![B1, B1, B0]],
+ partition.clone(),
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), 0);
assert_eq!(alice.free_balance(ct_110), 0);
assert_eq!(alice.free_balance(collateral), _100);
assert_eq!(pallet.free_balance(collateral), 0);
+
+ System::assert_last_event(
+ Event::::TokenMerged {
+ who: alice.id,
+ parent_collection_id,
+ market_id,
+ partition,
+ assets_in: vec![ct_001, ct_110],
+ asset_out: collateral,
+ amount,
+ }
+ .into(),
+ );
});
}
@@ -82,25 +97,39 @@ fn merge_position_works_parent() {
.unwrap();
let _ = create_market(Asset::Ztg, MarketType::Categorical(3));
- let market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
// Collection ID of [0, 0, 1].
- let parent_collection_id = [
+ let parent_collection_id = Some([
6, 44, 173, 50, 122, 106, 144, 185, 253, 19, 252, 218, 215, 241, 218, 37, 196, 112, 45,
133, 165, 48, 231, 189, 87, 123, 131, 18, 190, 5, 110, 93,
- ];
-
+ ]);
+ let market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
+ let partition = vec![vec![B0, B1, B0, B1], vec![B1, B0, B1, B0]];
assert_ok!(CombinatorialTokens::merge_position(
alice.signed(),
- Some(parent_collection_id),
+ parent_collection_id,
market_id,
- vec![vec![B0, B1, B0, B1], vec![B1, B0, B1, B0]],
+ partition.clone(),
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_001), amount);
assert_eq!(alice.free_balance(ct_001_0101), 0);
assert_eq!(alice.free_balance(ct_001_1010), 0);
+
+ System::assert_last_event(
+ Event::::TokenMerged {
+ who: alice.id,
+ parent_collection_id,
+ market_id,
+ partition,
+ assets_in: vec![ct_001_0101, ct_001_1010],
+ asset_out: ct_001,
+ amount,
+ }
+ .into(),
+ );
});
}
@@ -131,6 +160,7 @@ fn merge_position_horizontal_works() {
market_id,
vec![vec![B0, B1, B0], vec![B1, B0, B0]],
amount,
+ false,
));
assert_eq!(alice.free_balance(ct_110), amount);
@@ -151,6 +181,7 @@ fn merge_position_fails_if_market_not_found() {
0,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
1,
+ false,
),
zrml_market_commons::Error::::MarketDoesNotExist,
);
@@ -167,7 +198,14 @@ fn merge_position_fails_on_invalid_partition_length() {
let partition = vec![vec![B1, B0, B1], vec![B0, B1]];
assert_noop!(
- CombinatorialTokens::merge_position(alice.signed(), None, market_id, partition, _1,),
+ CombinatorialTokens::merge_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false
+ ),
Error::::InvalidPartition
);
});
@@ -183,7 +221,14 @@ fn merge_position_fails_on_trivial_partition_member() {
let partition = vec![vec![B1, B0, B1], vec![B0, B0, B0]];
assert_noop!(
- CombinatorialTokens::merge_position(alice.signed(), None, market_id, partition, _1,),
+ CombinatorialTokens::merge_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false
+ ),
Error::::InvalidPartition
);
});
@@ -199,7 +244,14 @@ fn merge_position_fails_on_overlapping_partition_members() {
let partition = vec![vec![B1, B0, B1], vec![B0, B0, B1]];
assert_noop!(
- CombinatorialTokens::merge_position(alice.signed(), None, market_id, partition, _1,),
+ CombinatorialTokens::merge_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false
+ ),
Error::::InvalidPartition
);
});
@@ -220,6 +272,7 @@ fn merge_position_fails_on_insufficient_funds() {
market_id,
vec![vec![B1, B0, B1], vec![B0, B1, B0]],
_100,
+ false,
),
orml_tokens::Error::::BalanceTooLow
);
@@ -241,6 +294,7 @@ fn merge_position_fails_on_insufficient_funds_foreign_token() {
market_id,
vec![vec![B1, B0, B1], vec![B0, B1, B0]],
_100,
+ false,
),
orml_tokens::Error::::BalanceTooLow
);
diff --git a/zrml/combinatorial-tokens/src/tests/redeem_position.rs b/zrml/combinatorial-tokens/src/tests/redeem_position.rs
index a58381206..64a0d9944 100644
--- a/zrml/combinatorial-tokens/src/tests/redeem_position.rs
+++ b/zrml/combinatorial-tokens/src/tests/redeem_position.rs
@@ -22,11 +22,13 @@ use test_case::test_case;
fn redeem_position_fails_on_no_payout_vector() {
ExtBuilder::build().execute_with(|| {
let alice = Account::new(0).deposit(Asset::Ztg, _100).unwrap();
+ let market_id = 0;
MockPayout::set_return_value(None);
assert_noop!(
- CombinatorialTokens::redeem_position(alice.signed(), None, 0, vec![]),
+ CombinatorialTokens::redeem_position(alice.signed(), None, market_id, vec![], false),
Error::::PayoutVectorNotFound
);
+ assert!(MockPayout::called_once_with(market_id));
});
}
@@ -36,7 +38,7 @@ fn redeem_position_fails_on_market_not_found() {
let alice = Account::new(0).deposit(Asset::Ztg, _100).unwrap();
MockPayout::set_return_value(Some(vec![_1_2, _1_2]));
assert_noop!(
- CombinatorialTokens::redeem_position(alice.signed(), None, 0, vec![]),
+ CombinatorialTokens::redeem_position(alice.signed(), None, 0, vec![], false),
zrml_market_commons::Error::::MarketDoesNotExist
);
});
@@ -51,7 +53,7 @@ fn redeem_position_fails_on_incorrect_index_set(index_set: Vec) {
MockPayout::set_return_value(Some(vec![_1_3, _1_3, _1_3]));
let market_id = create_market(Asset::Ztg, MarketType::Categorical(3));
assert_noop!(
- CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set),
+ CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set, false),
Error::::InvalidIndexSet
);
});
@@ -65,7 +67,7 @@ fn redeem_position_fails_if_tokens_have_to_value() {
let market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
let index_set = vec![B1, B0, B0, B1];
assert_noop!(
- CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set),
+ CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set, false),
Error::::TokenHasNoValue
);
});
@@ -79,7 +81,7 @@ fn redeem_position_fails_if_user_holds_no_winning_tokens() {
let market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
let index_set = vec![B0, B1, B0, B1];
assert_noop!(
- CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set),
+ CombinatorialTokens::redeem_position(alice.signed(), None, market_id, index_set, false),
Error::::NoTokensFound,
);
});
@@ -93,22 +95,43 @@ fn redeem_position_works_sans_parent() {
225, 102, 57, 241, 199, 18, 226, 137, 68, 3, 219, 131,
]);
let alice = Account::new(0).deposit(ct_110, _3).unwrap();
- let pallet = Account::new(Pallet::::account_id()).deposit(Asset::Ztg, _3).unwrap();
+ let amount_in = _3;
+ let pallet =
+ Account::new(Pallet::::account_id()).deposit(Asset::Ztg, amount_in).unwrap();
MockPayout::set_return_value(Some(vec![_1_4, _1_2, _1_4]));
+ let parent_collection_id = None;
let market_id = create_market(Asset::Ztg, MarketType::Categorical(3));
let index_set = vec![B1, B1, B0];
assert_ok!(CombinatorialTokens::redeem_position(
alice.signed(),
- None,
+ parent_collection_id,
market_id,
- index_set
+ index_set.clone(),
+ false,
));
assert_eq!(alice.free_balance(ct_110), 0);
- assert_eq!(alice.free_balance(Asset::Ztg), _2 + _1_4);
+ let amount_out = _2 + _1_4;
+ assert_eq!(alice.free_balance(Asset::Ztg), amount_out);
assert_eq!(pallet.free_balance(Asset::Ztg), _3_4);
+
+ System::assert_last_event(
+ Event::::TokenRedeemed {
+ who: alice.id,
+ parent_collection_id,
+ market_id,
+ index_set,
+ asset_in: ct_110,
+ amount_in,
+ asset_out: Asset::Ztg,
+ amount_out,
+ }
+ .into(),
+ );
+
+ assert!(MockPayout::called_once_with(market_id));
});
}
@@ -124,27 +147,46 @@ fn redeem_position_works_with_parent() {
225, 211, 72, 142, 210, 98, 202, 168, 193, 245, 217, 239, 28,
]);
- let alice = Account::new(0).deposit(ct_001_0101, _7).unwrap();
+ let amount_in = _7;
+ let alice = Account::new(0).deposit(ct_001_0101, amount_in).unwrap();
MockPayout::set_return_value(Some(vec![_1_4, 0, _1_2, _1_4]));
let _ = create_market(Asset::Ztg, MarketType::Categorical(3));
- let child_market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
+ let market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
// Collection ID of [0, 0, 1].
- let parent_collection_id = [
+ let parent_collection_id = Some([
6, 44, 173, 50, 122, 106, 144, 185, 253, 19, 252, 218, 215, 241, 218, 37, 196, 112, 45,
133, 165, 48, 231, 189, 87, 123, 131, 18, 190, 5, 110, 93,
- ];
+ ]);
let index_set = vec![B0, B1, B0, B1];
assert_ok!(CombinatorialTokens::redeem_position(
alice.signed(),
- Some(parent_collection_id),
- child_market_id,
- index_set
+ parent_collection_id,
+ market_id,
+ index_set.clone(),
+ false,
));
assert_eq!(alice.free_balance(ct_001_0101), 0);
- assert_eq!(alice.free_balance(ct_001), _1 + _3_4);
+ let amount_out = _1 + _3_4;
+ assert_eq!(alice.free_balance(ct_001), amount_out);
+
+ System::assert_last_event(
+ Event::::TokenRedeemed {
+ who: alice.id,
+ parent_collection_id,
+ market_id,
+ index_set,
+ asset_in: ct_001_0101,
+ amount_in,
+ asset_out: ct_001,
+ amount_out,
+ }
+ .into(),
+ );
+
+ assert!(MockPayout::called_once_with(market_id));
});
}
diff --git a/zrml/combinatorial-tokens/src/tests/split_position.rs b/zrml/combinatorial-tokens/src/tests/split_position.rs
index 4a1460931..88873e02b 100644
--- a/zrml/combinatorial-tokens/src/tests/split_position.rs
+++ b/zrml/combinatorial-tokens/src/tests/split_position.rs
@@ -34,6 +34,7 @@ fn split_position_works_vertical_no_parent() {
market_id,
partition.clone(),
amount,
+ false,
));
let ct_001 = CombinatorialToken([
@@ -89,6 +90,7 @@ fn split_position_works_vertical_with_parent() {
parent_market_id,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
parent_amount,
+ false,
));
let child_market_id = create_market(Asset::Ztg, MarketType::Categorical(4));
@@ -105,6 +107,7 @@ fn split_position_works_vertical_with_parent() {
child_market_id,
partition.clone(),
child_amount,
+ false,
));
// Alice is left with 1 unit of [0, 0, 1], 2 units of [1, 1, 0] and one unit of each of the
@@ -180,6 +183,7 @@ fn split_position_fails_if_market_not_found() {
0,
vec![vec![B0, B0, B1], vec![B1, B1, B0]],
1,
+ false,
),
zrml_market_commons::Error::::MarketDoesNotExist,
);
@@ -196,7 +200,14 @@ fn split_position_fails_on_invalid_partition_length() {
let partition = vec![vec![B1, B0, B1], vec![B0, B1]];
assert_noop!(
- CombinatorialTokens::split_position(alice.signed(), None, market_id, partition, _1),
+ CombinatorialTokens::split_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false,
+ ),
Error::::InvalidPartition
);
});
@@ -212,7 +223,14 @@ fn split_position_fails_on_empty_partition_member() {
let partition = vec![vec![B1, B0, B1], vec![B0, B0, B0]];
assert_noop!(
- CombinatorialTokens::split_position(alice.signed(), None, market_id, partition, _1,),
+ CombinatorialTokens::split_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false
+ ),
Error::::InvalidPartition
);
});
@@ -228,7 +246,14 @@ fn split_position_fails_on_overlapping_partition_members() {
let partition = vec![vec![B1, B0, B1], vec![B0, B0, B1]];
assert_noop!(
- CombinatorialTokens::split_position(alice.signed(), None, market_id, partition, _1),
+ CombinatorialTokens::split_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false,
+ ),
Error::::InvalidPartition
);
});
@@ -243,7 +268,14 @@ fn split_position_fails_on_trivial_partition() {
let partition = vec![vec![B1, B1, B1]];
assert_noop!(
- CombinatorialTokens::split_position(alice.signed(), None, market_id, partition, _1),
+ CombinatorialTokens::split_position(
+ alice.signed(),
+ None,
+ market_id,
+ partition,
+ _1,
+ false
+ ),
Error::::InvalidPartition
);
});
@@ -264,6 +296,7 @@ fn split_position_fails_on_insufficient_funds_native_token_no_parent() {
market_id,
vec![vec![B1, B0, B1], vec![B0, B1, B0]],
_100,
+ false,
),
orml_currencies::Error::::BalanceTooLow
);
@@ -285,6 +318,7 @@ fn split_position_fails_on_insufficient_funds_foreign_token_no_parent() {
market_id,
vec![vec![B1, B0, B1], vec![B0, B1, B0]],
_100,
+ false,
),
orml_currencies::Error::::BalanceTooLow
);
@@ -317,6 +351,7 @@ fn split_position_vertical_fails_on_insufficient_funds_combinatorial_token() {
market_id,
vec![vec![B1, B0, B1, B0], vec![B0, B1, B0, B1]],
_100,
+ false,
),
orml_tokens::Error::::BalanceTooLow
);
@@ -328,6 +363,7 @@ fn split_position_vertical_fails_on_insufficient_funds_combinatorial_token() {
market_id,
vec![vec![B1, B0, B1, B0], vec![B0, B1, B0, B1]],
_99,
+ false,
));
});
}
@@ -352,6 +388,7 @@ fn split_position_horizontal_fails_on_insufficient_funds_combinatorial_token() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0]],
_100,
+ false,
),
orml_tokens::Error::::BalanceTooLow
);
@@ -363,6 +400,7 @@ fn split_position_horizontal_fails_on_insufficient_funds_combinatorial_token() {
market_id,
vec![vec![B1, B0, B0], vec![B0, B1, B0]],
_99,
+ false,
));
});
}
diff --git a/zrml/combinatorial-tokens/src/types/cryptographic_id_manager/decompressor/mod.rs b/zrml/combinatorial-tokens/src/types/cryptographic_id_manager/decompressor/mod.rs
index 4a437d956..f5f5d0a6f 100644
--- a/zrml/combinatorial-tokens/src/types/cryptographic_id_manager/decompressor/mod.rs
+++ b/zrml/combinatorial-tokens/src/types/cryptographic_id_manager/decompressor/mod.rs
@@ -57,15 +57,14 @@ pub(crate) fn get_collection_id(
Some(bytes)
}
-const DECOMPRESS_HASH_MAX_ITERS: usize = 1_000;
+const DECOMPRESS_HASH_MAX_ITERS: usize = 32;
/// Decompresses a collection ID `hash` to a point of `alt_bn128`. The amount of work done can be
/// forced to be independent of the input by setting the `force_max_work` flag.
///
/// We don't have mathematical proof that the points of `alt_bn128` are distributed so that the
/// required number of iterations is below the specified limit of iterations, but there's good
-/// evidence that input hash requires more than `log_2(P) = 507.19338271000436` iterations. We
-/// will use `1_000` iterations as maximum for now.
+/// evidence that input hash requires more than `log_2(P) = 507.19338271000436` iterations.
///
/// Provided the assumption above is correct, this function cannot return `None`.
fn decompress_hash(hash: CombinatorialId, force_max_work: bool) -> Option {
@@ -107,7 +106,7 @@ fn decompress_hash(hash: CombinatorialId, force_max_work: bool) -> Option.
+
+//! Autogenerated weights for zrml_combinatorial_tokens
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: `2024-10-24`, STEPS: `2`, REPEAT: `0`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `blackbird`, CPU: ``
+//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
+
+// Executed Command:
+// ./target/release/zeitgeist
+// benchmark
+// pallet
+// --chain=dev
+// --steps=2
+// --repeat=0
+// --pallet=zrml_combinatorial_tokens
+// --extrinsic=*
+// --execution=native
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --template=./misc/weight_template.hbs
+// --header=./HEADER_GPL3
+// --output=./zrml/combinatorial-tokens/src/weights.rs
+
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use core::marker::PhantomData;
+use frame_support::{traits::Get, weights::Weight};
+
+/// Trait containing the required functions for weight retrival within
+/// zrml_combinatorial_tokens (automatically generated)
+pub trait WeightInfoZeitgeist {
+ fn split_position_vertical_sans_parent(n: u32, ) -> Weight;
+ fn split_position_vertical_with_parent(n: u32, ) -> Weight;
+ fn split_position_horizontal(n: u32, ) -> Weight;
+ fn merge_position_vertical_sans_parent(n: u32, ) -> Weight;
+ fn merge_position_vertical_with_parent(n: u32, ) -> Weight;
+ fn merge_position_horizontal(n: u32, ) -> Weight;
+ fn redeem_position_sans_parent(n: u32, ) -> Weight;
+ fn redeem_position_with_parent(n: u32, ) -> Weight;
+}
+
+/// Weight functions for zrml_combinatorial_tokens (automatically generated)
+pub struct WeightInfo(PhantomData);
+impl WeightInfoZeitgeist for WeightInfo {
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `System::Account` (r:1 w:1)
+ /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(132), added: 2607, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:32 w:32)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:32 w:32)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn split_position_vertical_sans_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `441`
+ // Estimated: `84574`
+ // Minimum execution time: 1_923_000 nanoseconds.
+ Weight::from_parts(29_365_000_000, 84574)
+ .saturating_add(T::DbWeight::get().reads(66))
+ .saturating_add(T::DbWeight::get().writes(65))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:33 w:33)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:33 w:33)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn split_position_vertical_with_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `671`
+ // Estimated: `87186`
+ // Minimum execution time: 2_353_000 nanoseconds.
+ Weight::from_parts(37_193_000_000, 87186)
+ .saturating_add(T::DbWeight::get().reads(67))
+ .saturating_add(T::DbWeight::get().writes(66))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:33 w:33)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:33 w:33)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn split_position_horizontal(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `633`
+ // Estimated: `87186`
+ // Minimum execution time: 2_773_000 nanoseconds.
+ Weight::from_parts(30_303_000_000, 87186)
+ .saturating_add(T::DbWeight::get().reads(67))
+ .saturating_add(T::DbWeight::get().writes(66))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:32 w:32)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:32 w:32)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// Storage: `System::Account` (r:1 w:1)
+ /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(132), added: 2607, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn merge_position_vertical_sans_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `624 + n * (160 ±0)`
+ // Estimated: `84574`
+ // Minimum execution time: 1_889_000 nanoseconds.
+ Weight::from_parts(29_394_000_000, 84574)
+ .saturating_add(T::DbWeight::get().reads(66))
+ .saturating_add(T::DbWeight::get().writes(65))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:33 w:33)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:33 w:33)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn merge_position_vertical_with_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `518 + n * (160 ±0)`
+ // Estimated: `87186`
+ // Minimum execution time: 2_376_000 nanoseconds.
+ Weight::from_parts(37_564_000_000, 87186)
+ .saturating_add(T::DbWeight::get().reads(67))
+ .saturating_add(T::DbWeight::get().writes(66))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:33 w:33)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:33 w:33)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn merge_position_horizontal(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `480 + n * (160 ±0)`
+ // Estimated: `87186`
+ // Minimum execution time: 2_760_000 nanoseconds.
+ Weight::from_parts(30_589_000_000, 87186)
+ .saturating_add(T::DbWeight::get().reads(67))
+ .saturating_add(T::DbWeight::get().writes(66))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:1 w:1)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:1 w:1)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// Storage: `System::Account` (r:1 w:1)
+ /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(132), added: 2607, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn redeem_position_sans_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `780`
+ // Estimated: `4173`
+ // Minimum execution time: 979_000 nanoseconds.
+ Weight::from_parts(986_000_000, 4173)
+ .saturating_add(T::DbWeight::get().reads(4))
+ .saturating_add(T::DbWeight::get().writes(3))
+ }
+ /// Storage: `MarketCommons::Markets` (r:1 w:0)
+ /// Proof: `MarketCommons::Markets` (`max_values`: None, `max_size`: Some(708), added: 3183, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::Accounts` (r:2 w:2)
+ /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`)
+ /// Storage: `Tokens::TotalIssuance` (r:2 w:2)
+ /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`)
+ /// The range of component `n` is `[2, 32]`.
+ fn redeem_position_with_parent(_n: u32, ) -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `674`
+ // Estimated: `6214`
+ // Minimum execution time: 1_193_000 nanoseconds.
+ Weight::from_parts(1_215_000_000, 6214)
+ .saturating_add(T::DbWeight::get().reads(5))
+ .saturating_add(T::DbWeight::get().writes(4))
+ }
+}
diff --git a/zrml/prediction-markets/src/lib.rs b/zrml/prediction-markets/src/lib.rs
index abaf617df..8d924151e 100644
--- a/zrml/prediction-markets/src/lib.rs
+++ b/zrml/prediction-markets/src/lib.rs
@@ -27,6 +27,7 @@ mod benchmarks;
pub mod migrations;
pub mod mock;
mod tests;
+pub mod types;
pub mod weights;
pub use pallet::*;
diff --git a/zrml/prediction-markets/src/types/combinatorial_tokens_benchmark_helper.rs b/zrml/prediction-markets/src/types/combinatorial_tokens_benchmark_helper.rs
new file mode 100644
index 000000000..1a8019122
--- /dev/null
+++ b/zrml/prediction-markets/src/types/combinatorial_tokens_benchmark_helper.rs
@@ -0,0 +1,40 @@
+use crate::{BalanceOf, Config, MarketIdOf};
+use alloc::vec::Vec;
+use core::marker::PhantomData;
+use sp_runtime::{traits::Zero, DispatchResult};
+use zeitgeist_primitives::{
+ traits::{CombinatorialTokensBenchmarkHelper, MarketCommonsPalletApi},
+ types::{MarketStatus, OutcomeReport},
+};
+
+pub struct PredictionMarketsCombinatorialTokensBenchmarkHelper(PhantomData);
+
+impl CombinatorialTokensBenchmarkHelper
+ for PredictionMarketsCombinatorialTokensBenchmarkHelper
+where
+ T: Config,
+{
+ type Balance = BalanceOf;
+ type MarketId = MarketIdOf;
+
+ /// Aggressively modifies the market specified by `market_id` to be resolved. The payout vector
+ /// must contain exactly one non-zero entry. Does absolutely no error management.
+ fn setup_payout_vector(
+ market_id: Self::MarketId,
+ payout_vector: Option>,
+ ) -> DispatchResult {
+ let payout_vector = payout_vector.unwrap();
+ let index = payout_vector.iter().position(|&value| !value.is_zero()).unwrap();
+
+ as MarketCommonsPalletApi>::mutate_market(
+ &market_id,
+ |market| {
+ market.resolved_outcome =
+ Some(OutcomeReport::Categorical(index.try_into().unwrap()));
+ market.status = MarketStatus::Resolved;
+
+ Ok(())
+ },
+ )
+ }
+}
diff --git a/zrml/prediction-markets/src/types/mod.rs b/zrml/prediction-markets/src/types/mod.rs
new file mode 100644
index 000000000..04d4ef801
--- /dev/null
+++ b/zrml/prediction-markets/src/types/mod.rs
@@ -0,0 +1,3 @@
+mod combinatorial_tokens_benchmark_helper;
+
+pub use combinatorial_tokens_benchmark_helper::PredictionMarketsCombinatorialTokensBenchmarkHelper;