Skip to content

Commit

Permalink
Implement trusted markets (#1100)
Browse files Browse the repository at this point in the history
* Make `dispute_mechanism` optional

* Allow trusted markets to resolve immediately

* Fix tests

* Implement trusted markets

* Implement migration and fix minor issues

* Update benchmarks

* Fix minor issues

* Fix fuzz tests

* Remove outdated TODO

* Use `on_resolution` instead of `resolve`

* Update migrations

* Update zrml/authorized/src/lib.rs

Co-authored-by: Harald Heckmann <[email protected]>

* Update zrml/simple-disputes/src/lib.rs

Co-authored-by: Harald Heckmann <[email protected]>

---------

Co-authored-by: Harald Heckmann <[email protected]>
  • Loading branch information
maltekliemann and sea212 authored Sep 27, 2023
1 parent 2a7d3d5 commit b86b944
Show file tree
Hide file tree
Showing 23 changed files with 602 additions and 1,303 deletions.
6 changes: 3 additions & 3 deletions primitives/src/market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub struct Market<AI, BA, BN, M, A> {
/// The resolved outcome.
pub resolved_outcome: Option<OutcomeReport>,
/// See [`MarketDisputeMechanism`].
pub dispute_mechanism: MarketDisputeMechanism,
pub dispute_mechanism: Option<MarketDisputeMechanism>,
/// The bonds reserved for this market.
pub bonds: MarketBonds<AI, BA>,
}
Expand Down Expand Up @@ -162,7 +162,7 @@ where
.saturating_add(MarketStatus::max_encoded_len())
.saturating_add(<Option<Report<AI, BN>>>::max_encoded_len())
.saturating_add(<Option<OutcomeReport>>::max_encoded_len())
.saturating_add(<MarketDisputeMechanism>::max_encoded_len())
.saturating_add(<Option<MarketDisputeMechanism>>::max_encoded_len())
.saturating_add(<MarketBonds<AI, BA>>::max_encoded_len())
}
}
Expand Down Expand Up @@ -393,7 +393,7 @@ mod tests {
status: MarketStatus::Active,
report: None,
resolved_outcome: None,
dispute_mechanism: MarketDisputeMechanism::Authorized,
dispute_mechanism: Some(MarketDisputeMechanism::Authorized),
bonds: MarketBonds::default(),
};
assert_eq!(market.matches_outcome_report(&outcome_report), expected);
Expand Down
12 changes: 6 additions & 6 deletions runtime/battery-station/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,16 @@ impl Contains<RuntimeCall> for ContractsCallfilter {
dispute { .. } => true,
// Only allow CPMM markets using Authorized or SimpleDisputes dispute mechanism
create_market {
dispute_mechanism: MarketDisputeMechanism::Authorized,
dispute_mechanism: Some(MarketDisputeMechanism::Authorized),
scoring_rule: ScoringRule::CPMM,
..
} => true,
create_cpmm_market_and_deploy_assets {
dispute_mechanism: MarketDisputeMechanism::Authorized,
dispute_mechanism: Some(MarketDisputeMechanism::Authorized),
..
} => true,
edit_market {
dispute_mechanism: MarketDisputeMechanism::Authorized,
dispute_mechanism: Some(MarketDisputeMechanism::Authorized),
scoring_rule: ScoringRule::CPMM,
..
} => true,
Expand Down Expand Up @@ -180,18 +180,18 @@ impl Contains<RuntimeCall> for IsCallable {
scoring_rule: ScoringRule::RikiddoSigmoidFeeMarketEma, ..
} => false,
create_market {
dispute_mechanism: MarketDisputeMechanism::SimpleDisputes,
dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes),
..
} => false,
edit_market {
scoring_rule: ScoringRule::RikiddoSigmoidFeeMarketEma, ..
} => false,
create_cpmm_market_and_deploy_assets {
dispute_mechanism: MarketDisputeMechanism::SimpleDisputes,
dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes),
..
} => false,
edit_market {
dispute_mechanism: MarketDisputeMechanism::SimpleDisputes,
dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes),
..
} => false,
_ => true,
Expand Down
57 changes: 27 additions & 30 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,35 +45,23 @@ pub mod weights;

#[macro_export]
macro_rules! decl_common_types {
{} => {
use sp_runtime::generic;
() => {
use frame_support::traits::{
Currency, Imbalance, NeverEnsureOrigin, OnRuntimeUpgrade, OnUnbalanced,
};
#[cfg(feature = "try-runtime")]
use frame_try_runtime::{UpgradeCheckSelect, TryStateSelect};
use frame_support::traits::{Currency, Imbalance, OnRuntimeUpgrade, OnUnbalanced, NeverEnsureOrigin};
use frame_try_runtime::{TryStateSelect, UpgradeCheckSelect};
use sp_runtime::generic;

pub type Block = generic::Block<Header, UncheckedExtrinsic>;

type Address = sp_runtime::MultiAddress<AccountId, ()>;

#[cfg(feature = "parachain")]
type Migrations = (
orml_asset_registry::Migration<Runtime>,
orml_unknown_tokens::Migration<Runtime>,
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
// IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!!
zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee<Runtime>,
zrml_prediction_markets::migrations::MoveDataToSimpleDisputes<Runtime>,
zrml_global_disputes::migrations::ModifyGlobalDisputesStructures<Runtime>,
);
type Migrations = (zrml_prediction_markets::migrations::MigrateMarkets<Runtime>,);

#[cfg(not(feature = "parachain"))]
type Migrations = (
pallet_grandpa::migrations::CleanupSetIdSessionMap<Runtime>,
// IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!!
zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee<Runtime>,
zrml_prediction_markets::migrations::MoveDataToSimpleDisputes<Runtime>,
zrml_global_disputes::migrations::ModifyGlobalDisputesStructures<Runtime>,
);
type Migrations = (zrml_prediction_markets::migrations::MigrateMarkets<Runtime>,);

pub type Executive = frame_executive::Executive<
Runtime,
Expand All @@ -99,7 +87,8 @@ macro_rules! decl_common_types {
pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
);
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;

// Governance
type AdvisoryCommitteeInstance = pallet_collective::Instance1;
Expand All @@ -111,20 +100,28 @@ macro_rules! decl_common_types {

// Council vote proportions
// At least 50%
type EnsureRootOrHalfCouncil =
EitherOfDiverse<EnsureRoot<AccountId>, EnsureProportionAtLeast<AccountId, CouncilInstance, 1, 2>>;
type EnsureRootOrHalfCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, CouncilInstance, 1, 2>,
>;

// At least 66%
type EnsureRootOrTwoThirdsCouncil =
EitherOfDiverse<EnsureRoot<AccountId>, EnsureProportionAtLeast<AccountId, CouncilInstance, 2, 3>>;
type EnsureRootOrTwoThirdsCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, CouncilInstance, 2, 3>,
>;

// At least 75%
type EnsureRootOrThreeFourthsCouncil =
EitherOfDiverse<EnsureRoot<AccountId>, EnsureProportionAtLeast<AccountId, CouncilInstance, 3, 4>>;
type EnsureRootOrThreeFourthsCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, CouncilInstance, 3, 4>,
>;

// At least 100%
type EnsureRootOrAllCouncil =
EitherOfDiverse<EnsureRoot<AccountId>, EnsureProportionAtLeast<AccountId, CouncilInstance, 1, 1>>;
type EnsureRootOrAllCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureProportionAtLeast<AccountId, CouncilInstance, 1, 1>,
>;

// Technical committee vote proportions
// At least 50%
Expand Down Expand Up @@ -248,7 +245,7 @@ macro_rules! decl_common_types {
}
}
}
}
};
}

// Construct runtime
Expand Down
6 changes: 3 additions & 3 deletions runtime/zeitgeist/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ impl Contains<RuntimeCall> for IsCallable {
create_market { scoring_rule: RikiddoSigmoidFeeMarketEma, .. } => false,
edit_market { scoring_rule: RikiddoSigmoidFeeMarketEma, .. } => false,
// Disable Court & SimpleDisputes dispute resolution mechanism
create_market { dispute_mechanism: Court | SimpleDisputes, .. } => false,
edit_market { dispute_mechanism: Court | SimpleDisputes, .. } => false,
create_market { dispute_mechanism: Some(Court | SimpleDisputes), .. } => false,
edit_market { dispute_mechanism: Some(Court | SimpleDisputes), .. } => false,
create_cpmm_market_and_deploy_assets {
dispute_mechanism: Court | SimpleDisputes,
dispute_mechanism: Some(Court | SimpleDisputes),
..
} => false,
_ => true,
Expand Down
50 changes: 19 additions & 31 deletions zrml/authorized/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ mod pallet {
PalletId, Twox64Concat,
};
use frame_system::pallet_prelude::OriginFor;
use sp_runtime::{traits::Saturating, DispatchError};
use sp_runtime::{traits::Saturating, DispatchError, DispatchResult};
use zeitgeist_primitives::{
traits::{DisputeApi, DisputeMaxWeightApi, DisputeResolutionApi},
types::{
Expand Down Expand Up @@ -95,10 +95,7 @@ mod pallet {
let market = T::MarketCommons::market(&market_id)?;
ensure!(market.status == MarketStatus::Disputed, Error::<T>::MarketIsNotDisputed);
ensure!(market.matches_outcome_report(&outcome), Error::<T>::OutcomeMismatch);
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(&market)?;

let now = frame_system::Pallet::<T>::block_number();

Expand Down Expand Up @@ -192,6 +189,15 @@ mod pallet {
fn get_auto_resolve(market_id: &MarketIdOf<T>) -> Option<T::BlockNumber> {
AuthorizedOutcomeReports::<T>::get(market_id).map(|report| report.resolve_at)
}

#[inline]
fn ensure_dispute_mechanism(market: &MarketOf<T>) -> DispatchResult {
ensure!(
market.dispute_mechanism == Some(MarketDisputeMechanism::Authorized),
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Ok(())
}
}

impl<T> DisputeMaxWeightApi for Pallet<T>
Expand Down Expand Up @@ -243,10 +249,7 @@ mod pallet {
_: &Self::MarketId,
market: &MarketOf<T>,
) -> Result<ResultWithWeightInfo<()>, DispatchError> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;

let res =
ResultWithWeightInfo { result: (), weight: T::WeightInfo::on_dispute_weight() };
Expand All @@ -258,10 +261,7 @@ mod pallet {
market_id: &Self::MarketId,
market: &MarketOf<T>,
) -> Result<ResultWithWeightInfo<Option<OutcomeReport>>, DispatchError> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;
let report = AuthorizedOutcomeReports::<T>::take(market_id);

let res = ResultWithWeightInfo {
Expand All @@ -278,10 +278,7 @@ mod pallet {
_: &OutcomeReport,
overall_imbalance: NegativeImbalanceOf<T>,
) -> Result<ResultWithWeightInfo<NegativeImbalanceOf<T>>, DispatchError> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;
// all funds to treasury
let res = ResultWithWeightInfo {
result: overall_imbalance,
Expand All @@ -300,7 +297,7 @@ mod pallet {
weight: T::WeightInfo::get_auto_resolve_weight(),
};

if market.dispute_mechanism != MarketDisputeMechanism::Authorized {
if market.dispute_mechanism != Some(MarketDisputeMechanism::Authorized) {
return res;
}

Expand All @@ -313,10 +310,7 @@ mod pallet {
_: &Self::MarketId,
market: &MarketOf<T>,
) -> Result<ResultWithWeightInfo<bool>, DispatchError> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;

let res =
ResultWithWeightInfo { result: false, weight: T::WeightInfo::has_failed_weight() };
Expand All @@ -331,10 +325,7 @@ mod pallet {
ResultWithWeightInfo<Vec<GlobalDisputeItem<Self::AccountId, Self::Balance>>>,
DispatchError,
> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;

let res = ResultWithWeightInfo {
result: Vec::new(),
Expand All @@ -348,10 +339,7 @@ mod pallet {
market_id: &Self::MarketId,
market: &MarketOf<T>,
) -> Result<ResultWithWeightInfo<()>, DispatchError> {
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::Authorized,
Error::<T>::MarketDoesNotHaveDisputeMechanismAuthorized
);
Self::ensure_dispute_mechanism(market)?;

AuthorizedOutcomeReports::<T>::remove(market_id);

Expand Down Expand Up @@ -385,7 +373,7 @@ where
creator_fee: sp_runtime::Perbill::zero(),
creator: T::PalletId::get().into_account_truncating(),
market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=100),
dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::Authorized,
dispute_mechanism: Some(MarketDisputeMechanism::Authorized),
metadata: Default::default(),
oracle: T::PalletId::get().into_account_truncating(),
period: zeitgeist_primitives::types::MarketPeriod::Block(Default::default()),
Expand Down
2 changes: 1 addition & 1 deletion zrml/authorized/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn authorize_market_outcome_fails_if_market_does_not_exist() {
fn authorize_market_outcome_fails_on_non_authorized_market() {
ExtBuilder::default().build().execute_with(|| {
let mut market = market_mock::<Runtime>();
market.dispute_mechanism = MarketDisputeMechanism::Court;
market.dispute_mechanism = Some(MarketDisputeMechanism::Court);
Markets::<Runtime>::insert(0, market);
assert_noop!(
Authorized::authorize_market_outcome(
Expand Down
2 changes: 1 addition & 1 deletion zrml/court/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ where
creator_fee: sp_runtime::Perbill::zero(),
creator: account("creator", 0, 0),
market_type: MarketType::Scalar(0..=100),
dispute_mechanism: MarketDisputeMechanism::Court,
dispute_mechanism: Some(MarketDisputeMechanism::Court),
metadata: vec![],
oracle: account("oracle", 0, 0),
period: MarketPeriod::Block(
Expand Down
Loading

0 comments on commit b86b944

Please sign in to comment.