Skip to content

Commit

Permalink
Fix zero division error in on_resolution (#701)
Browse files Browse the repository at this point in the history
* Fix zero division error in `on_resolution`

* Update zrml/prediction-markets/src/tests.rs

Co-authored-by: Harald Heckmann <mail@haraldheckmann.de>

* Fix typo and future-proof the test

* Update zrml/prediction-markets/src/lib.rs

Co-authored-by: Chralt <chralt98@gmail.com>

* Update zrml/prediction-markets/src/tests.rs

Co-authored-by: Chralt <chralt98@gmail.com>

* fix unused import

Co-authored-by: Harald Heckmann <mail@haraldheckmann.de>
Co-authored-by: Chralt <chralt98@gmail.com>
  • Loading branch information
3 people committed Jul 14, 2022
1 parent 61e1beb commit 87264f8
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
37 changes: 20 additions & 17 deletions zrml/prediction-markets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ mod pallet {
use sp_arithmetic::per_things::Perbill;
use sp_runtime::{
traits::{AccountIdConversion, CheckedDiv, Saturating, Zero},
ArithmeticError, DispatchError, DispatchResult, SaturatedConversion,
DispatchError, DispatchResult, SaturatedConversion,
};
use zeitgeist_primitives::{
constants::{PmPalletId, MILLISECS_PER_BLOCK},
Expand Down Expand Up @@ -1775,22 +1775,25 @@ mod pallet {
}
}

// fold all the imbalances into one and reward the correct reporters.
let reward_per_each = overall_imbalance
.checked_div(&correct_reporters.len().saturated_into())
.ok_or(ArithmeticError::DivisionByZero)?;
for correct_reporter in &correct_reporters {
let reward = overall_imbalance.min(reward_per_each); // *Should* always be equal to `reward_per_each`
overall_imbalance = overall_imbalance.saturating_sub(reward);

if let Err(err) =
T::AssetManager::deposit(Asset::Ztg, correct_reporter, reward)
{
log::warn!(
"[PredictionMarkets] Cannot deposit to the correct reporter. \
error: {:?}",
err
);
// Fold all the imbalances into one and reward the correct reporters. The
// number of correct reporters might be zero if the market defaults to the
// report after abandoned dispute. In that case, the rewards remain slashed.
if let Some(reward_per_each) =
overall_imbalance.checked_div(&correct_reporters.len().saturated_into())
{
for correct_reporter in &correct_reporters {
let reward = overall_imbalance.min(reward_per_each); // *Should* always be equal to `reward_per_each`
overall_imbalance = overall_imbalance.saturating_sub(reward);

if let Err(err) =
T::AssetManager::deposit(Asset::Ztg, correct_reporter, reward)
{
log::warn!(
"[PredictionMarkets] Cannot deposit to the correct reporter. \
error: {:?}",
err
);
}
}
}

Expand Down
54 changes: 54 additions & 0 deletions zrml/prediction-markets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2261,6 +2261,60 @@ fn authorized_correctly_resolves_disputed_market() {
});
}

#[test]
fn on_resolution_defaults_to_oracle_report_in_case_of_unresolved_dispute() {
ExtBuilder::default().build().execute_with(|| {
let end = 1;
assert_ok!(PredictionMarkets::create_market(
Origin::signed(ALICE),
BOB,
MarketPeriod::Block(0..end),
gen_metadata(2),
MarketCreation::Permissionless,
MarketType::Categorical(<Runtime as Config>::MinCategories::get()),
MarketDisputeMechanism::Authorized(FRED),
ScoringRule::CPMM,
));
assert_ok!(PredictionMarkets::buy_complete_set(Origin::signed(CHARLIE), 0, CENT));

run_to_block(end);
assert_ok!(PredictionMarkets::report(
Origin::signed(BOB),
0,
OutcomeReport::Categorical(1)
));
run_to_block(<frame_system::Pallet<Runtime>>::block_number() + 1);
assert_ok!(PredictionMarkets::dispute(
Origin::signed(CHARLIE),
0,
OutcomeReport::Categorical(0)
));
let market = MarketCommons::market(&0).unwrap();
assert_eq!(market.status, MarketStatus::Disputed);

let charlie_reserved = Balances::reserved_balance(&CHARLIE);
assert_eq!(charlie_reserved, DisputeBond::get());

run_to_block(<frame_system::Pallet<Runtime>>::block_number() + DisputePeriod::get());
let market_after = MarketCommons::market(&0).unwrap();
assert_eq!(market_after.status, MarketStatus::Resolved);
let disputes = crate::Disputes::<Runtime>::get(&0);
assert_eq!(disputes.len(), 0);
assert_ok!(PredictionMarkets::redeem_shares(Origin::signed(CHARLIE), 0));

// Make sure rewards are right:
//
// - Bob reported "correctly" and in time, so Alice and Bob don't get slashed
// - Charlie started a dispute which was abandoned, hence he's slashed
let charlie_balance = Balances::free_balance(&CHARLIE);
assert_eq!(charlie_balance, 1_000 * BASE - charlie_reserved);
let alice_balance = Balances::free_balance(&ALICE);
assert_eq!(alice_balance, 1_000 * BASE);
let bob_balance = Balances::free_balance(&BOB);
assert_eq!(bob_balance, 1_000 * BASE);
});
}

#[test]
fn approve_market_correctly_unreserves_advisory_bond() {
ExtBuilder::default().build().execute_with(|| {
Expand Down

0 comments on commit 87264f8

Please sign in to comment.