Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZIP-0 Part II #938

Merged
merged 69 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
8c0f2ed
move disputes to simple-disputes
Chralt98 Jan 9, 2023
bddaa72
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 11, 2023
1977d2a
move more to simple-disputes
Chralt98 Jan 11, 2023
c8699d4
wip
Chralt98 Jan 11, 2023
ae91749
wip
Chralt98 Jan 12, 2023
cd85642
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 13, 2023
228d333
some mock preparation
Chralt98 Jan 13, 2023
1f05799
wip
Chralt98 Jan 13, 2023
0b80b7d
fix tests
Chralt98 Jan 13, 2023
6236d51
taplo fmt
Chralt98 Jan 16, 2023
e4a09a9
update court authorized mdms
Chralt98 Jan 16, 2023
a67c50d
add dispute bond to market storage
Chralt98 Jan 16, 2023
9448ab9
mdm funds flow
Chralt98 Jan 16, 2023
c46621e
fix clippy
Chralt98 Jan 17, 2023
2f12959
fix pm benchmarks
Chralt98 Jan 17, 2023
7430066
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 17, 2023
6f10d96
add migration
Chralt98 Jan 17, 2023
9f002a4
simplify migration
Chralt98 Jan 17, 2023
09730a0
correct migration
Chralt98 Jan 18, 2023
f1347c3
migration fixes and call filter
Chralt98 Jan 18, 2023
b42002c
correct admin_destroy_market benchmark
Chralt98 Jan 18, 2023
80b3fa6
improve simple-disputes mock
Chralt98 Jan 18, 2023
bd7c97d
benchmark reserve_outcome
Chralt98 Jan 19, 2023
61e2e1e
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 19, 2023
355dad6
benchmark reserve_outcome
Chralt98 Jan 19, 2023
4aaea4e
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 20, 2023
af3da23
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 23, 2023
ee2681a
fix weights file
Chralt98 Jan 24, 2023
0ff08c0
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Jan 31, 2023
06314bb
fix after merge
Chralt98 Jan 31, 2023
78f0b03
add migration tests
Chralt98 Jan 31, 2023
84bb021
add migration reserve id test
Chralt98 Jan 31, 2023
e5302da
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Feb 1, 2023
c3c5ca6
apply review suggestions
Chralt98 Mar 2, 2023
5d873d2
rename reserve_outcome to suggest_outcome
Chralt98 Mar 2, 2023
88a43dd
separate resolve_disputed_market into parts
Chralt98 Mar 2, 2023
b8cd91a
edit exchange API documentation
Chralt98 Mar 27, 2023
5d6df79
slash dispute bond
Chralt98 Mar 27, 2023
1fc9b39
Merge branch 'release-dispute-system' into chralt98-dispute-restructu…
Chralt98 Mar 28, 2023
ce13fd2
add empty commit
Chralt98 Mar 28, 2023
7b3ff21
correct admin_destroy_market test
Chralt98 Mar 28, 2023
a052320
remove gd dependency from simple disputes
Chralt98 Mar 28, 2023
c3b61cb
Update zrml/simple-disputes/src/mock.rs
Chralt98 Apr 12, 2023
11960de
Update zrml/simple-disputes/src/mock.rs
Chralt98 Apr 12, 2023
6fc9197
Update zrml/prediction-markets/src/lib.rs
Chralt98 Apr 12, 2023
c638679
add doc string
Chralt98 Apr 12, 2023
553e082
add doc strings
Chralt98 Apr 12, 2023
55fdee0
Reduce settle_bonds LOC
sea212 Apr 3, 2023
0efc405
cargo fmt
Chralt98 Apr 12, 2023
aa09b01
Update zrml/prediction-markets/src/migrations.rs
Chralt98 Apr 12, 2023
2c15b96
Update zrml/prediction-markets/src/migrations.rs
Chralt98 Apr 12, 2023
a71bb5c
apply review suggestion
Chralt98 Apr 12, 2023
afd9d61
add correct mdm benchmarking on_dispute
Chralt98 Apr 17, 2023
af0a25a
use on_dispute_weight inside api
Chralt98 Apr 17, 2023
b88aca4
improve mdm weight technique
Chralt98 Apr 17, 2023
f48a0a3
add mdm weights to on_resolution
Chralt98 Apr 18, 2023
cbe528a
add tests for pm
Chralt98 Apr 18, 2023
3c6c9fe
Merge branch 'main' into chralt98-dispute-restructuring
Chralt98 Apr 18, 2023
7ab62c4
modify migration logs, fix try-runtime
Chralt98 Apr 18, 2023
86bd97e
little benchmark fix
Chralt98 Apr 20, 2023
af60129
Update zrml/authorized/src/benchmarks.rs
Chralt98 Apr 20, 2023
ddf14ff
Update zrml/authorized/src/benchmarks.rs
Chralt98 Apr 20, 2023
8513191
use result with weight struct
Chralt98 Apr 20, 2023
1e0fcbc
improve dispute api weight system
Chralt98 Apr 21, 2023
ae99d7f
Use accurate dispute weight instead of max
sea212 May 3, 2023
1f7f337
Merge branch 'release-dispute-system' into chralt98-dispute-restructu…
Chralt98 May 9, 2023
6025960
fix clippy
Chralt98 May 9, 2023
99836e5
Update zrml/prediction-markets/src/migrations.rs
Chralt98 May 15, 2023
7aae6f1
add copyrights
Chralt98 May 15, 2023
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 6 additions & 73 deletions zrml/prediction-markets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,24 +534,13 @@ mod pallet {
pub fn dispute(
origin: OriginFor<T>,
#[pallet::compact] market_id: MarketIdOf<T>,
outcome: OutcomeReport,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
let disputes = Disputes::<T>::get(market_id);

let curr_block_num = <frame_system::Pallet<T>>::block_number();
let market = <zrml_market_commons::Pallet<T>>::market(&market_id)?;
ensure!(
matches!(market.status, MarketStatus::Reported | MarketStatus::Disputed),
Error::<T>::InvalidMarketStatus
);
let num_disputes: u32 = disputes.len().saturated_into();
Self::validate_dispute(&disputes, &market, num_disputes, &outcome)?;
T::AssetManager::reserve_named(
&Self::reserve_id(),
Asset::Ztg,
&who,
default_dispute_bond::<T>(disputes.len()),
)?;
ensure!(market.status == MarketStatus::Reported, Error::<T>::InvalidMarketStatus);

match market.dispute_mechanism {
MarketDisputeMechanism::Authorized => {
T::Authorized::on_dispute(&disputes, &market_id, &market)?
Expand All @@ -563,12 +552,10 @@ mod pallet {
T::SimpleDisputes::on_dispute(&disputes, &market_id, &market)?
}
}

Self::remove_last_dispute_from_market_ids_per_dispute_block(&disputes, &market_id)?;
Self::set_market_as_disputed(&market, &market_id)?;
let market_dispute = MarketDispute { at: curr_block_num, by: who, outcome };
<Disputes<T>>::try_mutate(market_id, |disputes| {
disputes.try_push(market_dispute.clone()).map_err(|_| <Error<T>>::StorageOverflow)
})?;

// each dispute resets dispute_duration
let dispute_duration_ends_at_block =
curr_block_num.saturating_add(market.deadlines.dispute_duration);
Expand All @@ -579,7 +566,6 @@ mod pallet {
Self::deposit_event(Event::MarketDisputed(
market_id,
MarketStatus::Disputed,
market_dispute,
));
// TODO(#782): add court benchmark
Ok((Some(T::WeightInfo::dispute_authorized(num_disputes, CacheSize::get()))).into())
Expand Down Expand Up @@ -1441,15 +1427,6 @@ mod pallet {
/// The origin that is allowed to destroy markets.
type DestroyOrigin: EnsureOrigin<Self::Origin>;

/// The base amount of currency that must be bonded in order to create a dispute.
#[pallet::constant]
type DisputeBond: Get<BalanceOf<Self>>;

/// The additional amount of currency that must be bonded when creating a subsequent
/// dispute.
#[pallet::constant]
type DisputeFactor: Get<BalanceOf<Self>>;

/// Event
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

Expand Down Expand Up @@ -1692,7 +1669,7 @@ mod pallet {
/// A market has been closed \[market_id\]
MarketClosed(MarketIdOf<T>),
/// A market has been disputed \[market_id, new_market_status, new_outcome\]
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved
MarketDisputed(MarketIdOf<T>, MarketStatus, MarketDispute<T::AccountId, T::BlockNumber>),
MarketDisputed(MarketIdOf<T>, MarketStatus),
/// An advised market has ended before it was approved or rejected. \[market_id\]
MarketExpired(MarketIdOf<T>),
/// A pending market has been rejected as invalid with a reason. \[market_id, reject_reason\]
Expand Down Expand Up @@ -1837,17 +1814,6 @@ mod pallet {
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(PhantomData<T>);

/// For each market, this holds the dispute information for each dispute that's
/// been issued.
#[pallet::storage]
pub type Disputes<T: Config> = StorageMap<
_,
Blake2_128Concat,
MarketIdOf<T>,
BoundedVec<MarketDispute<T::AccountId, T::BlockNumber>, T::MaxDisputes>,
ValueQuery,
>;
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved

#[pallet::storage]
pub type MarketIdsPerOpenBlock<T: Config> = StorageMap<
_,
Expand Down Expand Up @@ -2149,26 +2115,6 @@ mod pallet {
}
}

fn ensure_can_not_dispute_the_same_outcome(
disputes: &[MarketDispute<T::AccountId, T::BlockNumber>],
report: &Report<T::AccountId, T::BlockNumber>,
outcome: &OutcomeReport,
) -> DispatchResult {
if let Some(last_dispute) = disputes.last() {
ensure!(&last_dispute.outcome != outcome, Error::<T>::CannotDisputeSameOutcome);
} else {
ensure!(&report.outcome != outcome, Error::<T>::CannotDisputeSameOutcome);
}

Ok(())
}

#[inline]
fn ensure_disputes_does_not_exceed_max_disputes(num_disputes: u32) -> DispatchResult {
ensure!(num_disputes < T::MaxDisputes::get(), Error::<T>::MaxDisputesReached);
Ok(())
}

fn ensure_market_is_active(market: &MarketOf<T>) -> DispatchResult {
ensure!(market.status == MarketStatus::Active, Error::<T>::MarketIsNotActive);
Ok(())
Expand Down Expand Up @@ -2806,19 +2752,6 @@ mod pallet {
Ok(T::WeightInfo::start_subsidy(total_assets.saturated_into()))
}

fn validate_dispute(
disputes: &[MarketDispute<T::AccountId, T::BlockNumber>],
market: &MarketOf<T>,
num_disputes: u32,
outcome_report: &OutcomeReport,
) -> DispatchResult {
let report = market.report.as_ref().ok_or(Error::<T>::MarketIsNotReported)?;
ensure!(market.matches_outcome_report(outcome_report), Error::<T>::OutcomeMismatch);
Self::ensure_can_not_dispute_the_same_outcome(disputes, report, outcome_report)?;
Self::ensure_disputes_does_not_exceed_max_disputes(num_disputes)?;
Ok(())
}

fn construct_market(
creator: T::AccountId,
creator_fee: u8,
Expand Down
1 change: 1 addition & 0 deletions zrml/simple-disputes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
sp-runtime = { branch = "polkadot-v0.9.26", default-features = false, git = "https://github.com/paritytech/substrate" }
zeitgeist-primitives = { default-features = false, path = "../../primitives" }
zrml-market-commons = { default-features = false, path = "../market-commons" }
orml-traits = { branch = "polkadot-v0.9.26", default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library" }

[dev-dependencies]
pallet-balances = { branch = "polkadot-v0.9.26", git = "https://github.com/paritytech/substrate" }
Expand Down
184 changes: 159 additions & 25 deletions zrml/simple-disputes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,68 +31,195 @@ pub use simple_disputes_pallet_api::SimpleDisputesPalletApi;
mod pallet {
use crate::SimpleDisputesPalletApi;
use core::marker::PhantomData;
use frame_system::pallet_prelude::*;
use frame_support::{
dispatch::DispatchResult,
traits::{Currency, Get, Hooks, IsType},
PalletId,
pallet_prelude::*,
transactional,
};
use sp_runtime::DispatchError;
use zeitgeist_primitives::{
traits::DisputeApi,
types::{Market, MarketDispute, MarketDisputeMechanism, MarketStatus, OutcomeReport},
types::{Report, Asset, Market, MarketDispute, MarketDisputeMechanism, MarketStatus, OutcomeReport},
};
use sp_runtime::traits::Saturating;
use sp_runtime::SaturatedConversion;
use zeitgeist_primitives::traits::ZeitgeistAssetManager;
use zrml_market_commons::MarketCommonsPalletApi;

type BalanceOf<T> =
<CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
pub(crate) type CurrencyOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::Currency;
pub(crate) type MarketIdOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::MarketId;
pub(crate) type MomentOf<T> = <<T as Config>::MarketCommons as MarketCommonsPalletApi>::Moment;
pub(crate) type MarketOf<T> = Market<
<T as frame_system::Config>::AccountId,
BalanceOf<T>,
<T as frame_system::Config>::BlockNumber,
MomentOf<T>,
>;

#[pallet::call]
impl<T: Config> Pallet<T> {}
use orml_traits::currency::NamedMultiReservableCurrency;

#[pallet::config]
pub trait Config: frame_system::Config {
/// Shares of outcome assets and native currency
type AssetManager: ZeitgeistAssetManager<
Self::AccountId,
Balance = <CurrencyOf<Self> as Currency<Self::AccountId>>::Balance,
CurrencyId = Asset<MarketIdOf<Self>>,
ReserveIdentifier = [u8; 8],
>;

/// Event
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

/// The base amount of currency that must be bonded in order to create a dispute.
#[pallet::constant]
type DisputeBond: Get<BalanceOf<Self>>;

/// The additional amount of currency that must be bonded when creating a subsequent
/// dispute.
#[pallet::constant]
type DisputeFactor: Get<BalanceOf<Self>>;

/// The identifier of individual markets.
type MarketCommons: MarketCommonsPalletApi<
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
>;

/// The maximum number of disputes allowed on any single market.
#[pallet::constant]
type MaxDisputes: Get<u32>;

/// The pallet identifier.
#[pallet::constant]
type PalletId: Get<PalletId>;

#[pallet::constant]
type PredictionMarketsPalletId: Get<PalletId>;
}

type BalanceOf<T> =
<CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
pub(crate) type CurrencyOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::Currency;
pub(crate) type MarketIdOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::MarketId;
pub(crate) type MomentOf<T> = <<T as Config>::MarketCommons as MarketCommonsPalletApi>::Moment;
pub(crate) type MarketOf<T> = Market<
<T as frame_system::Config>::AccountId,
BalanceOf<T>,
<T as frame_system::Config>::BlockNumber,
MomentOf<T>,
>;

#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);

/// For each market, this holds the dispute information for each dispute that's
/// been issued.
#[pallet::storage]
pub type Disputes<T: Config> = StorageMap<
_,
Blake2_128Concat,
MarketIdOf<T>,
BoundedVec<MarketDispute<T::AccountId, T::BlockNumber>, T::MaxDisputes>,
ValueQuery,
>;
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T>
where
T: Config, {
OutcomeReserved { market_id: MarketIdOf<T>, dispute: MarketDispute<T::AccountId, T::BlockNumber> },
}

#[pallet::error]
pub enum Error<T> {
/// 1. Any resolution must either have a `Disputed` or `Reported` market status
/// 2. If status is `Disputed`, then at least one dispute must exist
InvalidMarketStatus,
/// On dispute or resolution, someone tried to pass a non-simple-disputes market type
MarketDoesNotHaveSimpleDisputesMechanism,
StorageOverflow,
OutcomeMismatch,
CannotDisputeSameOutcome,
MarketIsNotReported,
sea212 marked this conversation as resolved.
Show resolved Hide resolved
MaxDisputesReached,
}

#[pallet::event]
pub enum Event<T>
where
T: Config, {}

#[pallet::hooks]
impl<T: Config> Hooks<T::BlockNumber> for Pallet<T> {}

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(5000)]
#[transactional]
pub fn reserve_outcome(
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member Author

@Chralt98 Chralt98 Jan 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test this functionality (including API calls)!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maltekliemann I will write tests, when you accept the current logic decisions.

maltekliemann marked this conversation as resolved.
Show resolved Hide resolved
origin: OriginFor<T>,
#[pallet::compact] market_id: MarketIdOf<T>,
outcome: OutcomeReport,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
let market = T::MarketCommons::market(&market_id)?;
ensure!(
market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes,
Error::<T>::MarketDoesNotHaveSimpleDisputesMechanism
);
ensure!(
market.status == MarketStatus::Disputed,
Error::<T>::InvalidMarketStatus
);
ensure!(market.matches_outcome_report(&outcome), Error::<T>::OutcomeMismatch);
let report = market.report.as_ref().ok_or(Error::<T>::MarketIsNotReported)?;

let now = <frame_system::Pallet<T>>::block_number();
let disputes = Disputes::<T>::get(&market_id);
let num_disputes: u32 = disputes.len().saturated_into();

Self::ensure_can_not_dispute_the_same_outcome(&disputes, report, &outcome)?;
Self::ensure_disputes_does_not_exceed_max_disputes(num_disputes)?;

T::AssetManager::reserve_named(
&Self::reserve_id(),
Asset::Ztg,
&who,
default_dispute_bond::<T>(disputes.len()),
)?;

let market_dispute = MarketDispute { at: now, by: who, outcome };
<Disputes<T>>::try_mutate(market_id, |disputes| {
disputes.try_push(market_dispute.clone()).map_err(|_| <Error<T>>::StorageOverflow)
})?;

Self::deposit_event(Event::OutcomeReserved {
market_id,
dispute: market_dispute,
});

Ok((Some(5000)).into())
}
}

impl<T: Config> Pallet<T> {
#[inline]
pub fn reserve_id() -> [u8; 8] {
T::PredictionMarketsPalletId::get().0
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved
}

fn ensure_can_not_dispute_the_same_outcome(
disputes: &[MarketDispute<T::AccountId, T::BlockNumber>],
report: &Report<T::AccountId, T::BlockNumber>,
outcome: &OutcomeReport,
) -> DispatchResult {
if let Some(last_dispute) = disputes.last() {
ensure!(&last_dispute.outcome != outcome, Error::<T>::CannotDisputeSameOutcome);
} else {
ensure!(&report.outcome != outcome, Error::<T>::CannotDisputeSameOutcome);
}

Ok(())
}

#[inline]
fn ensure_disputes_does_not_exceed_max_disputes(num_disputes: u32) -> DispatchResult {
ensure!(num_disputes < T::MaxDisputes::get(), Error::<T>::MaxDisputesReached);
Ok(())
}
sea212 marked this conversation as resolved.
Show resolved Hide resolved
}

impl<T> DisputeApi for Pallet<T>
where
T: Config,
Expand Down Expand Up @@ -137,6 +264,13 @@ mod pallet {

impl<T> SimpleDisputesPalletApi for Pallet<T> where T: Config {}

#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);
// No-one can bound more than BalanceOf<T>, therefore, this functions saturates
pub(crate) fn default_dispute_bond<T>(n: usize) -> BalanceOf<T>
where
T: Config,
{
T::DisputeBond::get().saturating_add(
T::DisputeFactor::get().saturating_mul(n.saturated_into::<u32>().into()),
)
}
}