Merge branch 'betting-merge' of https://bitbucket.org/peerplaysblockchain/peerplays-graphene into betting-merge
This commit is contained in:
commit
2c8b9ce17a
15 changed files with 511 additions and 243 deletions
|
|
@ -236,6 +236,10 @@ struct get_impacted_account_visitor
|
|||
{
|
||||
_impacted.insert( op.bettor_id );
|
||||
}
|
||||
void operator()( const bet_adjusted_operation& op )
|
||||
{
|
||||
_impacted.insert( op.bettor_id );
|
||||
}
|
||||
void operator()( const bet_matched_operation& op )
|
||||
{
|
||||
_impacted.insert( op.bettor_id );
|
||||
|
|
|
|||
|
|
@ -291,26 +291,14 @@ void_result bet_place_evaluator::do_evaluate(const bet_place_operation& op)
|
|||
simulated_bet.betting_market_id = op.betting_market_id;
|
||||
simulated_bet.amount_to_bet = op.amount_to_bet;
|
||||
simulated_bet.backer_multiplier = op.backer_multiplier;
|
||||
simulated_bet.amount_reserved_for_fees = op.amount_reserved_for_fees;
|
||||
simulated_bet.back_or_lay = op.back_or_lay;
|
||||
|
||||
share_type required_deposit = get_required_deposit_for_bet(simulated_bet);
|
||||
#endif
|
||||
|
||||
// verify they reserved enough to cover the percentage fee
|
||||
uint16_t percentage_fee = current_params.current_fees->get<bet_place_operation>().percentage_fee;
|
||||
fc::uint128_t minimum_percentage_fee_calculation = op.amount_to_bet.amount.value;
|
||||
minimum_percentage_fee_calculation *= percentage_fee;
|
||||
minimum_percentage_fee_calculation += GRAPHENE_100_PERCENT - 1; // round up
|
||||
minimum_percentage_fee_calculation /= GRAPHENE_100_PERCENT;
|
||||
share_type minimum_percentage_fee = minimum_percentage_fee_calculation.to_uint64();
|
||||
FC_ASSERT(op.amount_reserved_for_fees >= minimum_percentage_fee, "insufficient fees",
|
||||
("fee_provided", op.amount_reserved_for_fees)("fee_required", minimum_percentage_fee));
|
||||
|
||||
// do they have enough in their account to place the bet
|
||||
_stake_plus_fees = op.amount_to_bet.amount + op.amount_reserved_for_fees;
|
||||
FC_ASSERT( d.get_balance( *fee_paying_account, *_asset ).amount >= _stake_plus_fees, "insufficient balance",
|
||||
("balance", d.get_balance(*fee_paying_account, *_asset))("stake_plus_fees", _stake_plus_fees) );
|
||||
FC_ASSERT( d.get_balance( *fee_paying_account, *_asset ).amount >= op.amount_to_bet.amount, "insufficient balance",
|
||||
("balance", d.get_balance(*fee_paying_account, *_asset))("amount_to_bet", op.amount_to_bet.amount) );
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
|
@ -324,15 +312,16 @@ object_id_type bet_place_evaluator::do_apply(const bet_place_operation& op)
|
|||
bet_obj.betting_market_id = op.betting_market_id;
|
||||
bet_obj.amount_to_bet = op.amount_to_bet;
|
||||
bet_obj.backer_multiplier = op.backer_multiplier;
|
||||
bet_obj.amount_reserved_for_fees = op.amount_reserved_for_fees;
|
||||
bet_obj.back_or_lay = op.back_or_lay;
|
||||
});
|
||||
|
||||
d.adjust_balance(fee_paying_account->id, asset(-_stake_plus_fees, _betting_market_group->asset_id));
|
||||
bet_id_type new_bet_id = new_bet.id; // save the bet id here, new_bet may be deleted during place_bet()
|
||||
|
||||
d.adjust_balance(fee_paying_account->id, -op.amount_to_bet);
|
||||
|
||||
bool bet_matched = d.place_bet(new_bet);
|
||||
|
||||
return new_bet.id;
|
||||
return new_bet_id;
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
void_result bet_cancel_evaluator::do_evaluate(const bet_cancel_operation& op)
|
||||
|
|
|
|||
|
|
@ -11,15 +11,12 @@ namespace graphene { namespace chain {
|
|||
void database::cancel_bet( const bet_object& bet, bool create_virtual_op )
|
||||
{
|
||||
asset amount_to_refund = bet.amount_to_bet;
|
||||
amount_to_refund += bet.amount_reserved_for_fees;
|
||||
//TODO: update global statistics
|
||||
adjust_balance(bet.bettor_id, amount_to_refund); //return unmatched stake + fees
|
||||
//TODO: do special fee accounting as required
|
||||
adjust_balance(bet.bettor_id, amount_to_refund);
|
||||
if (create_virtual_op)
|
||||
{
|
||||
bet_canceled_operation bet_canceled_virtual_op(bet.bettor_id, bet.id,
|
||||
bet.amount_to_bet,
|
||||
bet.amount_reserved_for_fees);
|
||||
bet.amount_to_bet);
|
||||
//idump((bet_canceled_virtual_op));
|
||||
push_applied_operation(std::move(bet_canceled_virtual_op));
|
||||
}
|
||||
|
|
@ -127,7 +124,6 @@ void database::resolve_betting_market_group(const betting_market_group_object& b
|
|||
uint16_t rake_fee_percentage = get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
share_type net_profits;
|
||||
share_type payout_amounts;
|
||||
share_type fees_collected;
|
||||
account_id_type bettor_id = bettor_positions_pair.first;
|
||||
const std::vector<const betting_market_position_object*>& bettor_positions = bettor_positions_pair.second;
|
||||
|
||||
|
|
@ -149,7 +145,6 @@ void database::resolve_betting_market_group(const betting_market_group_object& b
|
|||
{
|
||||
share_type total_payout = position->pay_if_payout_condition + position->pay_if_not_canceled;
|
||||
payout_amounts += total_payout;
|
||||
fees_collected += position->fees_collected;
|
||||
net_profits += total_payout - position->pay_if_canceled;
|
||||
break;
|
||||
}
|
||||
|
|
@ -157,12 +152,11 @@ void database::resolve_betting_market_group(const betting_market_group_object& b
|
|||
{
|
||||
share_type total_payout = position->pay_if_not_payout_condition + position->pay_if_not_canceled;
|
||||
payout_amounts += total_payout;
|
||||
fees_collected += position->fees_collected;
|
||||
net_profits += total_payout - position->pay_if_canceled;
|
||||
break;
|
||||
}
|
||||
case betting_market_resolution_type::cancel:
|
||||
payout_amounts += position->pay_if_canceled + position->fees_collected;
|
||||
payout_amounts += position->pay_if_canceled;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
|
|
@ -179,9 +173,6 @@ void database::resolve_betting_market_group(const betting_market_group_object& b
|
|||
adjust_balance(*rake_account_id, asset(rake_amount, betting_market_group.asset_id));
|
||||
}
|
||||
|
||||
if (fees_collected.value)
|
||||
adjust_balance(*rake_account_id, asset(fees_collected, betting_market_group.asset_id));
|
||||
|
||||
// pay winning - rake
|
||||
adjust_balance(bettor_id, asset(payout_amounts - rake_amount, betting_market_group.asset_id));
|
||||
// [ROL]
|
||||
|
|
@ -191,7 +182,7 @@ void database::resolve_betting_market_group(const betting_market_group_object& b
|
|||
betting_market_group.id,
|
||||
resolutions,
|
||||
payout_amounts,
|
||||
fees_collected));
|
||||
rake_amount));
|
||||
}
|
||||
|
||||
betting_market_itr = betting_market_index.lower_bound(betting_market_group.id);
|
||||
|
|
@ -213,27 +204,7 @@ void database::get_required_deposit_for_bet(const betting_market_object& betting
|
|||
}
|
||||
#endif
|
||||
|
||||
bool maybe_cull_small_bet( database& db, const bet_object& bet_object_to_cull )
|
||||
{
|
||||
/**
|
||||
* There are times when this bet can't be even partially matched at its stated odds
|
||||
* For example, say it's a back bet for 20 satoshis at 1.92 odds (which comes out to 25:23
|
||||
* odds). It's not possible for it to match at exact odds since it's < 25
|
||||
*
|
||||
* Remove these bets from the books to reduce clutter.
|
||||
*/
|
||||
share_type minimum_matchable_amount = bet_object_to_cull.get_minimum_matchable_amount();
|
||||
if (bet_object_to_cull.amount_to_bet.amount < minimum_matchable_amount)
|
||||
{
|
||||
dlog("culling small bet of ${amount}, smaller than the minimum ${minimum_matchable_amount} at odds ${odds}",
|
||||
("amount", bet_object_to_cull.amount_to_bet.amount)("minimum_matchable_amount", minimum_matchable_amount)("odds", bet_object_to_cull.backer_multiplier));
|
||||
db.cancel_bet(bet_object_to_cull);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
share_type adjust_betting_position(database& db, account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, share_type bet_amount, share_type matched_amount, share_type fees_collected)
|
||||
share_type adjust_betting_position(database& db, account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, share_type bet_amount, share_type matched_amount)
|
||||
{ try {
|
||||
assert(bet_amount >= 0);
|
||||
|
||||
|
|
@ -253,7 +224,6 @@ share_type adjust_betting_position(database& db, account_id_type bettor_id, bett
|
|||
position.pay_if_not_payout_condition = back_or_lay == bet_type::lay ? bet_amount + matched_amount : 0;
|
||||
position.pay_if_canceled = bet_amount;
|
||||
position.pay_if_not_canceled = 0;
|
||||
position.fees_collected = fees_collected;
|
||||
// this should not be reducible
|
||||
});
|
||||
} else {
|
||||
|
|
@ -263,7 +233,6 @@ share_type adjust_betting_position(database& db, account_id_type bettor_id, bett
|
|||
position.pay_if_payout_condition += back_or_lay == bet_type::back ? bet_amount + matched_amount : 0;
|
||||
position.pay_if_not_payout_condition += back_or_lay == bet_type::lay ? bet_amount + matched_amount : 0;
|
||||
position.pay_if_canceled += bet_amount;
|
||||
position.fees_collected += fees_collected;
|
||||
|
||||
guaranteed_winnings_returned = position.reduce();
|
||||
});
|
||||
|
|
@ -275,29 +244,21 @@ share_type adjust_betting_position(database& db, account_id_type bettor_id, bett
|
|||
// called twice when a bet is matched, once for the taker, once for the maker
|
||||
bool bet_was_matched(database& db, const bet_object& bet,
|
||||
share_type amount_bet, share_type amount_matched,
|
||||
bet_multiplier_type actual_multiplier, bool cull_if_small)
|
||||
bet_multiplier_type actual_multiplier)
|
||||
{
|
||||
// calculate the percentage fee paid
|
||||
fc::uint128_t percentage_fee_128 = bet.amount_reserved_for_fees.value;
|
||||
percentage_fee_128 *= amount_bet.value;
|
||||
percentage_fee_128 += bet.amount_to_bet.amount.value - 1;
|
||||
percentage_fee_128 /= bet.amount_to_bet.amount.value;
|
||||
share_type fee_paid = percentage_fee_128.to_uint64();
|
||||
|
||||
// record their bet, modifying their position, and return any winnings
|
||||
share_type guaranteed_winnings_returned = adjust_betting_position(db, bet.bettor_id, bet.betting_market_id,
|
||||
bet.back_or_lay, amount_bet, amount_matched, fee_paid);
|
||||
bet.back_or_lay, amount_bet, amount_matched);
|
||||
db.adjust_balance(bet.bettor_id, asset(guaranteed_winnings_returned, bet.amount_to_bet.asset_id));
|
||||
|
||||
// generate a virtual "match" op
|
||||
asset asset_amount_bet(amount_bet, bet.amount_to_bet.asset_id);
|
||||
|
||||
bet_matched_operation bet_matched_virtual_op(bet.bettor_id, bet.id, bet.betting_market_id,
|
||||
bet_matched_operation bet_matched_virtual_op(bet.bettor_id, bet.id,
|
||||
asset_amount_bet,
|
||||
fee_paid,
|
||||
actual_multiplier,
|
||||
guaranteed_winnings_returned);
|
||||
//idump((bet_matched_virtual_op));
|
||||
//edump((bet_matched_virtual_op));
|
||||
db.push_applied_operation(std::move(bet_matched_virtual_op));
|
||||
|
||||
// update the bet on the books
|
||||
|
|
@ -310,12 +271,7 @@ bool bet_was_matched(database& db, const bet_object& bet,
|
|||
{
|
||||
db.modify(bet, [&](bet_object& bet_obj) {
|
||||
bet_obj.amount_to_bet -= asset_amount_bet;
|
||||
bet_obj.amount_reserved_for_fees -= fee_paid;
|
||||
});
|
||||
//TODO: cull_if_small is currently always true, remove the parameter if we don't find a
|
||||
// need for it soon
|
||||
if (cull_if_small)
|
||||
return maybe_cull_small_bet(db, bet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +290,7 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker
|
|||
{
|
||||
assert(taker_bet.amount_to_bet.asset_id == maker_bet.amount_to_bet.asset_id);
|
||||
assert(taker_bet.amount_to_bet.amount > 0 && maker_bet.amount_to_bet.amount > 0);
|
||||
assert(taker_bet.backer_multiplier >= maker_bet.backer_multiplier);
|
||||
assert(taker_bet.back_or_lay == bet_type::back ? taker_bet.backer_multiplier <= maker_bet.backer_multiplier : taker_bet.backer_multiplier >= maker_bet.backer_multiplier);
|
||||
assert(taker_bet.back_or_lay != maker_bet.back_or_lay);
|
||||
|
||||
int result = 0;
|
||||
|
|
@ -381,37 +337,80 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker
|
|||
|
||||
//idump((taker_amount_to_match)(maker_amount_to_match));
|
||||
|
||||
result |= bet_was_matched(db, taker_bet, taker_amount_to_match, maker_amount_to_match, maker_bet.backer_multiplier, true);
|
||||
result |= bet_was_matched(db, maker_bet, maker_amount_to_match, taker_amount_to_match, maker_bet.backer_multiplier, true) << 1;
|
||||
result |= bet_was_matched(db, taker_bet, taker_amount_to_match, maker_amount_to_match, maker_bet.backer_multiplier);
|
||||
result |= bet_was_matched(db, maker_bet, maker_amount_to_match, taker_amount_to_match, maker_bet.backer_multiplier) << 1;
|
||||
|
||||
assert(result != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// called from the bet_place_evaluator
|
||||
bool database::place_bet(const bet_object& new_bet_object)
|
||||
{
|
||||
bet_id_type bet_id = new_bet_object.id;
|
||||
const asset_object& bet_asset = get(new_bet_object.amount_to_bet.asset_id);
|
||||
|
||||
const auto& bet_odds_idx = get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||
|
||||
bet_type bet_type_to_match = new_bet_object.back_or_lay == bet_type::back ? bet_type::lay : bet_type::back;
|
||||
auto book_itr = bet_odds_idx.lower_bound(std::make_tuple(new_bet_object.betting_market_id, bet_type_to_match));
|
||||
auto book_end = bet_odds_idx.upper_bound(std::make_tuple(new_bet_object.betting_market_id, bet_type_to_match, new_bet_object.backer_multiplier));
|
||||
|
||||
// ilog("");
|
||||
// ilog("------------ order book ------------------");
|
||||
// for (auto itr = book_itr; itr != book_end; ++itr)
|
||||
// idump((*itr));
|
||||
// ilog("------------ order book ------------------");
|
||||
|
||||
int orders_matched_flags = 0;
|
||||
bool finished = false;
|
||||
while (!finished && book_itr != book_end)
|
||||
{
|
||||
auto old_book_itr = book_itr;
|
||||
++book_itr;
|
||||
// match returns 2 when only the old order was fully filled. In this case, we keep matching; otherwise, we stop.
|
||||
|
||||
orders_matched_flags = match_bet(*this, new_bet_object, *old_book_itr);
|
||||
|
||||
// we continue if the maker bet was completely consumed AND the taker bet was not
|
||||
finished = orders_matched_flags != 2;
|
||||
}
|
||||
|
||||
return (orders_matched_flags & 1) != 0;
|
||||
if (!(orders_matched_flags & 1))
|
||||
{
|
||||
// if the new (taker) bet was not completely consumed, we need to put whatever remains
|
||||
// of it on the books. But we only allow bets that can be exactly matched
|
||||
// on the books, so round the amount down if necessary
|
||||
share_type minimum_matchable_amount = new_bet_object.get_minimum_matchable_amount();
|
||||
share_type scale_factor = new_bet_object.amount_to_bet.amount / minimum_matchable_amount;
|
||||
share_type rounded_bet_amount = scale_factor * minimum_matchable_amount;
|
||||
//idump((new_bet_object.amount_to_bet.amount)(rounded_bet_amount)(minimum_matchable_amount)(scale_factor));
|
||||
|
||||
if (rounded_bet_amount == share_type())
|
||||
{
|
||||
// the remainder of the bet was too small to match, cancel the bet
|
||||
cancel_bet(new_bet_object, true);
|
||||
return true;
|
||||
}
|
||||
else if (rounded_bet_amount != new_bet_object.amount_to_bet.amount)
|
||||
{
|
||||
asset stake_returned = new_bet_object.amount_to_bet;
|
||||
stake_returned.amount -= rounded_bet_amount;
|
||||
|
||||
modify(new_bet_object, [&rounded_bet_amount](bet_object& modified_bet_object) {
|
||||
modified_bet_object.amount_to_bet.amount = rounded_bet_amount;
|
||||
});
|
||||
|
||||
adjust_balance(new_bet_object.bettor_id, stake_returned);
|
||||
// TODO: update global statistics
|
||||
bet_adjusted_operation bet_adjusted_op(new_bet_object.bettor_id, new_bet_object.id,
|
||||
stake_returned);
|
||||
// idump((bet_adjusted_op)(new_bet_object));
|
||||
push_applied_operation(std::move(bet_adjusted_op));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ struct get_impacted_account_visitor
|
|||
void operator()(const bet_matched_operation &){}
|
||||
void operator()(const bet_cancel_operation&){}
|
||||
void operator()(const bet_canceled_operation &){}
|
||||
void operator()(const bet_adjusted_operation &){}
|
||||
|
||||
void operator()( const tournament_create_operation& op )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,8 +94,6 @@ class bet_object : public graphene::db::abstract_object< bet_object >
|
|||
|
||||
bet_multiplier_type backer_multiplier;
|
||||
|
||||
share_type amount_reserved_for_fees; // same asset type as amount_to_bet
|
||||
|
||||
bet_type back_or_lay;
|
||||
|
||||
static share_type get_approximate_matching_amount(share_type bet_amount, bet_multiplier_type backer_multiplier, bet_type back_or_lay, bool round_up = false);
|
||||
|
|
@ -241,7 +239,10 @@ struct compare_bet_by_odds {
|
|||
return true;
|
||||
if (lhs_bet_type > rhs_bet_type)
|
||||
return false;
|
||||
return lhs_backer_multiplier < rhs_backer_multiplier;
|
||||
if (lhs_bet_type == bet_type::back)
|
||||
return lhs_backer_multiplier < rhs_backer_multiplier;
|
||||
else
|
||||
return lhs_backer_multiplier > rhs_backer_multiplier;
|
||||
}
|
||||
bool compare(const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
||||
bet_multiplier_type lhs_backer_multiplier, const bet_id_type& lhs_bet_id,
|
||||
|
|
@ -257,9 +258,9 @@ struct compare_bet_by_odds {
|
|||
if (lhs_bet_type > rhs_bet_type)
|
||||
return false;
|
||||
if (lhs_backer_multiplier < rhs_backer_multiplier)
|
||||
return true;
|
||||
return lhs_bet_type == bet_type::back;
|
||||
if (lhs_backer_multiplier > rhs_backer_multiplier)
|
||||
return false;
|
||||
return lhs_bet_type == bet_type::lay;
|
||||
return lhs_bet_id < rhs_bet_id;
|
||||
}
|
||||
};
|
||||
|
|
@ -381,7 +382,10 @@ struct compare_bet_by_bettor_then_odds {
|
|||
return true;
|
||||
if (lhs_bet_type > rhs_bet_type)
|
||||
return false;
|
||||
return lhs_backer_multiplier < rhs_backer_multiplier;
|
||||
if (lhs_bet_type == bet_type::back)
|
||||
return lhs_backer_multiplier < rhs_backer_multiplier;
|
||||
else
|
||||
return lhs_backer_multiplier > rhs_backer_multiplier;
|
||||
}
|
||||
bool compare(const betting_market_id_type& lhs_betting_market_id, const account_id_type& lhs_bettor_id,
|
||||
bet_type lhs_bet_type,
|
||||
|
|
@ -403,9 +407,10 @@ struct compare_bet_by_bettor_then_odds {
|
|||
if (lhs_bet_type > rhs_bet_type)
|
||||
return false;
|
||||
if (lhs_backer_multiplier < rhs_backer_multiplier)
|
||||
return true;
|
||||
return lhs_bet_type == bet_type::back;
|
||||
if (lhs_backer_multiplier > rhs_backer_multiplier)
|
||||
return false;
|
||||
return lhs_bet_type == bet_type::lay;
|
||||
|
||||
return lhs_bet_id < rhs_bet_id;
|
||||
}
|
||||
};
|
||||
|
|
@ -444,6 +449,6 @@ typedef generic_index<betting_market_position_object, betting_market_position_mu
|
|||
FC_REFLECT_DERIVED( graphene::chain::betting_market_rules_object, (graphene::db::object), (name)(description) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::betting_market_group_object, (graphene::db::object), (description)(event_id)(rules_id)(asset_id)(frozen)(total_matched_bets_amount) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::betting_market_object, (graphene::db::object), (group_id)(description)(payout_condition) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::bet_object, (graphene::db::object), (bettor_id)(betting_market_id)(amount_to_bet)(backer_multiplier)(amount_reserved_for_fees)(back_or_lay) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::bet_object, (graphene::db::object), (bettor_id)(betting_market_id)(amount_to_bet)(backer_multiplier)(back_or_lay) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::betting_market_position_object, (graphene::db::object), (bettor_id)(betting_market_id)(pay_if_payout_condition)(pay_if_not_payout_condition)(pay_if_canceled)(pay_if_not_canceled)(fees_collected) )
|
||||
|
|
|
|||
|
|
@ -239,7 +239,6 @@ struct bet_place_operation : public base_operation
|
|||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; // fixed fee charged upon placing the bet
|
||||
uint16_t percentage_fee = 2 * GRAPHENE_1_PERCENT; // charged when bet is matched
|
||||
};
|
||||
asset fee;
|
||||
|
||||
|
|
@ -257,11 +256,6 @@ struct bet_place_operation : public base_operation
|
|||
// would be 2 * GRAPHENE_BETTING_ODDS_PRECISION.
|
||||
bet_multiplier_type backer_multiplier;
|
||||
|
||||
// the amount the blockchain reserves to pay the percentage fee on matched bets.
|
||||
// when this bet is (partially) matched, the blockchain will take (part of) the fee. If this bet is canceled
|
||||
// the remaining amount will be returned to the bettor (same asset type as the amount_to_bet)
|
||||
share_type amount_reserved_for_fees;
|
||||
|
||||
bet_type back_or_lay;
|
||||
|
||||
extensions_type extensions;
|
||||
|
|
@ -278,24 +272,20 @@ struct bet_matched_operation : public base_operation
|
|||
struct fee_parameters_type {};
|
||||
|
||||
bet_matched_operation(){}
|
||||
bet_matched_operation(account_id_type bettor_id, bet_id_type bet_id, betting_market_id_type betting_market_id,
|
||||
asset amount_bet, share_type fees_paid,
|
||||
bet_matched_operation(account_id_type bettor_id, bet_id_type bet_id,
|
||||
asset amount_bet,
|
||||
bet_multiplier_type backer_multiplier,
|
||||
share_type guaranteed_winnings_returned) :
|
||||
bettor_id(bettor_id),
|
||||
bet_id(bet_id),
|
||||
betting_market_id(betting_market_id),
|
||||
amount_bet(amount_bet),
|
||||
fees_paid(fees_paid),
|
||||
backer_multiplier(backer_multiplier),
|
||||
guaranteed_winnings_returned(guaranteed_winnings_returned)
|
||||
{}
|
||||
|
||||
account_id_type bettor_id;
|
||||
bet_id_type bet_id;
|
||||
betting_market_id_type betting_market_id;
|
||||
asset amount_bet;
|
||||
share_type fees_paid; // same asset type as amount_bet
|
||||
bet_multiplier_type backer_multiplier; // the actual odds received
|
||||
share_type guaranteed_winnings_returned; // same asset type as amount_bet
|
||||
asset fee; // unimportant for a virtual op
|
||||
|
|
@ -332,17 +322,15 @@ struct bet_canceled_operation : public base_operation
|
|||
|
||||
bet_canceled_operation(){}
|
||||
bet_canceled_operation(account_id_type bettor_id, bet_id_type bet_id,
|
||||
asset stake_returned, share_type unused_fees_returned) :
|
||||
asset stake_returned) :
|
||||
bettor_id(bettor_id),
|
||||
bet_id(bet_id),
|
||||
stake_returned(stake_returned),
|
||||
unused_fees_returned(unused_fees_returned)
|
||||
stake_returned(stake_returned)
|
||||
{}
|
||||
|
||||
account_id_type bettor_id;
|
||||
bet_id_type bet_id;
|
||||
asset stake_returned;
|
||||
share_type unused_fees_returned; // same asset type as stake_returned
|
||||
asset fee; // unimportant for a virtual op
|
||||
|
||||
account_id_type fee_payer()const { return bettor_id; }
|
||||
|
|
@ -352,6 +340,35 @@ struct bet_canceled_operation : public base_operation
|
|||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
* virtual op generated when a bet amount is rounded down to an amount that can
|
||||
* match evenly at a given odds (the blockchain does this automatically at the time
|
||||
* the bet is placed on the order books). (note: there is no way a user can adjust their bet
|
||||
* after placing it, aside from canceling the bet and placing a new one)
|
||||
*/
|
||||
struct bet_adjusted_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {};
|
||||
|
||||
bet_adjusted_operation(){}
|
||||
bet_adjusted_operation(account_id_type bettor_id, bet_id_type bet_id,
|
||||
asset stake_returned) :
|
||||
bettor_id(bettor_id),
|
||||
bet_id(bet_id),
|
||||
stake_returned(stake_returned)
|
||||
{}
|
||||
|
||||
account_id_type bettor_id;
|
||||
bet_id_type bet_id;
|
||||
asset stake_returned;
|
||||
asset fee; // unimportant for a virtual op
|
||||
|
||||
account_id_type fee_payer()const { return bettor_id; }
|
||||
void validate()const { FC_ASSERT(false, "virtual operation"); }
|
||||
|
||||
/// This is a virtual operation; there is no fee
|
||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
|
@ -396,13 +413,16 @@ FC_REFLECT( graphene::chain::betting_market_group_cancel_unmatched_bets_operatio
|
|||
FC_REFLECT_ENUM( graphene::chain::bet_type, (back)(lay) )
|
||||
FC_REFLECT( graphene::chain::bet_place_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT( graphene::chain::bet_place_operation,
|
||||
(fee)(bettor_id)(betting_market_id)(amount_to_bet)(backer_multiplier)(amount_reserved_for_fees)(back_or_lay)(extensions) )
|
||||
(fee)(bettor_id)(betting_market_id)(amount_to_bet)(backer_multiplier)(back_or_lay)(extensions) )
|
||||
|
||||
FC_REFLECT( graphene::chain::bet_matched_operation::fee_parameters_type, )
|
||||
FC_REFLECT( graphene::chain::bet_matched_operation, (bettor_id)(bet_id)(betting_market_id)(amount_bet)(fees_paid)(backer_multiplier)(guaranteed_winnings_returned) )
|
||||
FC_REFLECT( graphene::chain::bet_matched_operation, (bettor_id)(bet_id)(amount_bet)(backer_multiplier)(guaranteed_winnings_returned) )
|
||||
|
||||
FC_REFLECT( graphene::chain::bet_cancel_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT( graphene::chain::bet_cancel_operation, (bettor_id) (bet_to_cancel) (extensions) )
|
||||
|
||||
FC_REFLECT( graphene::chain::bet_canceled_operation::fee_parameters_type, )
|
||||
FC_REFLECT( graphene::chain::bet_canceled_operation, (bettor_id)(bet_id)(stake_returned)(unused_fees_returned) )
|
||||
FC_REFLECT( graphene::chain::bet_canceled_operation, (bettor_id)(bet_id)(stake_returned) )
|
||||
|
||||
FC_REFLECT( graphene::chain::bet_adjusted_operation::fee_parameters_type, )
|
||||
FC_REFLECT( graphene::chain::bet_adjusted_operation, (bettor_id)(bet_id)(stake_returned) )
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ namespace graphene { namespace chain {
|
|||
tournament_payout_operation, // VIRTUAL
|
||||
tournament_leave_operation,
|
||||
betting_market_group_update_operation,
|
||||
betting_market_update_operation
|
||||
betting_market_update_operation,
|
||||
bet_adjusted_operation // VIRTUAL
|
||||
> operation;
|
||||
|
||||
/// @} // operations group
|
||||
|
|
|
|||
|
|
@ -80,13 +80,15 @@ binned_order_book bookie_api_impl::get_binned_order_book(graphene::chain::bettin
|
|||
}
|
||||
};
|
||||
|
||||
// iterate through both sides of the order book (backs at increasing odds then lays at decreasing odds)
|
||||
for (auto bet_odds_iter = bet_odds_idx.lower_bound(std::make_tuple(betting_market_id));
|
||||
bet_odds_iter != bet_odds_idx.end() && betting_market_id == bet_odds_iter->betting_market_id;
|
||||
++bet_odds_iter)
|
||||
{
|
||||
if (current_bin &&
|
||||
(bet_odds_iter->back_or_lay == current_bin->back_or_lay ||
|
||||
bet_odds_iter->backer_multiplier > current_bin->backer_multiplier))
|
||||
(bet_odds_iter->back_or_lay == current_bin->back_or_lay /* we have switched from back to lay bets */ ||
|
||||
(bet_odds_iter->back_or_lay == bet_type::back ? bet_odds_iter->backer_multiplier > current_bin->backer_multiplier :
|
||||
bet_odds_iter->backer_multiplier < current_bin->backer_multiplier)))
|
||||
flush_current_bin();
|
||||
|
||||
if (!current_bin)
|
||||
|
|
@ -94,9 +96,21 @@ binned_order_book bookie_api_impl::get_binned_order_book(graphene::chain::bettin
|
|||
// if there is no current bin, create one appropriate for the bet we're processing
|
||||
current_bin = graphene::chain::bet_object();
|
||||
|
||||
current_bin->backer_multiplier = (bet_odds_iter->backer_multiplier + bin_size - 1) / bin_size * bin_size;
|
||||
current_bin->backer_multiplier = std::min<graphene::chain::bet_multiplier_type>(current_bin->backer_multiplier, current_params.max_bet_multiplier);
|
||||
current_bin->back_or_lay = bet_odds_iter->back_or_lay == bet_type::back ? bet_type::lay : bet_type::back;
|
||||
// for back bets, we want to group all bets with odds from 3.0001 to 4 into the "4" bin
|
||||
// for lay bets, we want to group all bets with odds from 3 to 3.9999 into the "3" bin
|
||||
if (bet_odds_iter->back_or_lay == bet_type::back)
|
||||
{
|
||||
current_bin->backer_multiplier = (bet_odds_iter->backer_multiplier + bin_size - 1) / bin_size * bin_size;
|
||||
current_bin->backer_multiplier = std::min<graphene::chain::bet_multiplier_type>(current_bin->backer_multiplier, current_params.max_bet_multiplier);
|
||||
current_bin->back_or_lay = bet_type::lay;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_bin->backer_multiplier = bet_odds_iter->backer_multiplier / bin_size * bin_size;
|
||||
current_bin->backer_multiplier = std::max<graphene::chain::bet_multiplier_type>(current_bin->backer_multiplier, current_params.min_bet_multiplier);
|
||||
current_bin->back_or_lay = bet_type::back;
|
||||
}
|
||||
|
||||
current_bin->amount_to_bet.amount = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace graphene { namespace bookie {
|
|||
namespace detail
|
||||
{
|
||||
|
||||
class persistent_event_object : public graphene::db::abstract_object<event_object>
|
||||
class persistent_event_object : public graphene::db::abstract_object<persistent_event_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = bookie_objects;
|
||||
|
|
@ -124,6 +124,117 @@ void events_by_competitor_index::object_modified( const object& after )
|
|||
}
|
||||
#endif
|
||||
|
||||
//////////// betting_market_group_object //////////////////
|
||||
class persistent_betting_market_group_object : public graphene::db::abstract_object<persistent_betting_market_group_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = bookie_objects;
|
||||
static const uint8_t type_id = persistent_betting_market_group_object_type;
|
||||
|
||||
betting_market_group_object ephemeral_betting_market_group_object;
|
||||
|
||||
share_type total_matched_bets_amount;
|
||||
|
||||
betting_market_group_id_type get_betting_market_group_id() const { return ephemeral_betting_market_group_object.id; }
|
||||
};
|
||||
|
||||
struct by_betting_market_group_id;
|
||||
typedef multi_index_container<
|
||||
persistent_betting_market_group_object,
|
||||
indexed_by<
|
||||
ordered_unique<tag<by_id>, member<object, object_id_type, &object::id> >,
|
||||
ordered_unique<tag<by_betting_market_group_id>, const_mem_fun<persistent_betting_market_group_object, betting_market_group_id_type, &persistent_betting_market_group_object::get_betting_market_group_id> > > > persistent_betting_market_group_multi_index_type;
|
||||
|
||||
typedef generic_index<persistent_betting_market_group_object, persistent_betting_market_group_multi_index_type> persistent_betting_market_group_index;
|
||||
|
||||
//////////// betting_market_object //////////////////
|
||||
class persistent_betting_market_object : public graphene::db::abstract_object<persistent_betting_market_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = bookie_objects;
|
||||
static const uint8_t type_id = persistent_betting_market_object_type;
|
||||
|
||||
betting_market_object ephemeral_betting_market_object;
|
||||
|
||||
share_type total_matched_bets_amount;
|
||||
|
||||
betting_market_id_type get_betting_market_id() const { return ephemeral_betting_market_object.id; }
|
||||
};
|
||||
|
||||
struct by_betting_market_id;
|
||||
typedef multi_index_container<
|
||||
persistent_betting_market_object,
|
||||
indexed_by<
|
||||
ordered_unique<tag<by_id>, member<object, object_id_type, &object::id> >,
|
||||
ordered_unique<tag<by_betting_market_id>, const_mem_fun<persistent_betting_market_object, betting_market_id_type, &persistent_betting_market_object::get_betting_market_id> > > > persistent_betting_market_multi_index_type;
|
||||
|
||||
typedef generic_index<persistent_betting_market_object, persistent_betting_market_multi_index_type> persistent_betting_market_index;
|
||||
|
||||
//////////// bet_object //////////////////
|
||||
class persistent_bet_object : public graphene::db::abstract_object<persistent_bet_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = bookie_objects;
|
||||
static const uint8_t type_id = persistent_bet_object_type;
|
||||
|
||||
bet_object ephemeral_bet_object;
|
||||
|
||||
bet_id_type get_bet_id() const { return ephemeral_bet_object.id; }
|
||||
};
|
||||
|
||||
struct by_bet_id;
|
||||
typedef multi_index_container<
|
||||
persistent_bet_object,
|
||||
indexed_by<
|
||||
ordered_unique<tag<by_id>, member<object, object_id_type, &object::id> >,
|
||||
ordered_unique<tag<by_bet_id>, const_mem_fun<persistent_bet_object, bet_id_type, &persistent_bet_object::get_bet_id> > > > persistent_bet_multi_index_type;
|
||||
|
||||
|
||||
typedef generic_index<persistent_bet_object, persistent_bet_multi_index_type> persistent_bet_index;
|
||||
|
||||
/* As a plugin, we get notified of new/changed objects at the end of every block processed.
|
||||
* For most objects, that's fine, because we expect them to always be around until the end of
|
||||
* the block. However, with bet objects, it's possible that the user places a bet and it fills
|
||||
* and is removed during the same block, so need another strategy to detect them immediately after
|
||||
* they are created.
|
||||
* We do this by creating a secondary index on bet_object. We don't actually use it
|
||||
* to index any property of the bet, we just use it to register for callbacks.
|
||||
*/
|
||||
class persistent_bet_object_helper : public secondary_index
|
||||
{
|
||||
public:
|
||||
virtual ~persistent_bet_object_helper() {}
|
||||
|
||||
virtual void object_inserted(const object& obj) override;
|
||||
//virtual void object_removed( const object& obj ) override;
|
||||
//virtual void about_to_modify( const object& before ) override;
|
||||
virtual void object_modified(const object& after) override;
|
||||
void set_plugin_instance(bookie_plugin* instance) { _bookie_plugin = instance; }
|
||||
private:
|
||||
bookie_plugin* _bookie_plugin;
|
||||
};
|
||||
|
||||
void persistent_bet_object_helper::object_inserted(const object& obj)
|
||||
{
|
||||
const bet_object& bet_obj = *boost::polymorphic_downcast<const bet_object*>(&obj);
|
||||
_bookie_plugin->database().create<persistent_bet_object>([&](persistent_bet_object& saved_bet_obj) {
|
||||
saved_bet_obj.ephemeral_bet_object = bet_obj;
|
||||
});
|
||||
}
|
||||
void persistent_bet_object_helper::object_modified(const object& after)
|
||||
{
|
||||
database& db = _bookie_plugin->database();
|
||||
auto& persistent_bets_by_bet_id = db.get_index_type<persistent_bet_index>().indices().get<by_bet_id>();
|
||||
const bet_object& bet_obj = *boost::polymorphic_downcast<const bet_object*>(&after);
|
||||
auto iter = persistent_bets_by_bet_id.find(bet_obj.id);
|
||||
assert (iter != persistent_bets_by_bet_id.end());
|
||||
if (iter != persistent_bets_by_bet_id.end())
|
||||
db.modify(*iter, [&](persistent_bet_object& saved_bet_obj) {
|
||||
saved_bet_obj.ephemeral_bet_object = bet_obj;
|
||||
});
|
||||
}
|
||||
|
||||
//////////// end bet_object ///////////////////
|
||||
class bookie_plugin_impl
|
||||
{
|
||||
public:
|
||||
|
|
@ -175,13 +286,14 @@ class bookie_plugin_impl
|
|||
|
||||
bookie_plugin_impl::~bookie_plugin_impl()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void bookie_plugin_impl::on_objects_changed(const vector<object_id_type>& changed_object_ids)
|
||||
{
|
||||
graphene::chain::database& db = database();
|
||||
auto& event_id_index = db.get_index_type<persistent_event_object_index>().indices().get<by_event_id>();
|
||||
auto& betting_market_group_id_index = db.get_index_type<persistent_betting_market_group_index>().indices().get<by_betting_market_group_id>();
|
||||
auto& betting_market_id_index = db.get_index_type<persistent_betting_market_index>().indices().get<by_betting_market_id>();
|
||||
|
||||
for (const object_id_type& changed_object_id : changed_object_ids)
|
||||
{
|
||||
|
|
@ -232,6 +344,78 @@ void bookie_plugin_impl::on_objects_changed(const vector<object_id_type>& change
|
|||
});
|
||||
}
|
||||
}
|
||||
else if (changed_object_id.space() == betting_market_group_object::space_id &&
|
||||
changed_object_id.type() == betting_market_group_object::type_id)
|
||||
{
|
||||
betting_market_group_id_type changed_betting_market_group_id = changed_object_id;
|
||||
const betting_market_group_object* new_betting_market_group_obj = nullptr;
|
||||
try
|
||||
{
|
||||
new_betting_market_group_obj = &changed_betting_market_group_id(db);
|
||||
}
|
||||
catch (fc::exception& e)
|
||||
{
|
||||
}
|
||||
// new_betting_market_group_obj should point to the now-changed event_object, or null if it was removed from the database
|
||||
|
||||
const persistent_betting_market_group_object* old_betting_market_group_obj = nullptr;
|
||||
|
||||
auto persistent_betting_market_group_iter = betting_market_group_id_index.find(changed_betting_market_group_id);
|
||||
if (persistent_betting_market_group_iter != betting_market_group_id_index.end())
|
||||
old_betting_market_group_obj = &*persistent_betting_market_group_iter;
|
||||
|
||||
// and old_betting_market_group_obj is a pointer to our saved copy, or nullptr if it is a new object
|
||||
if (old_betting_market_group_obj && new_betting_market_group_obj)
|
||||
{
|
||||
ilog("Modifying persistent betting_market_group object ${id}", ("id", changed_betting_market_group_id));
|
||||
db.modify(*old_betting_market_group_obj, [&](persistent_betting_market_group_object& saved_betting_market_group_obj) {
|
||||
saved_betting_market_group_obj.ephemeral_betting_market_group_object = *new_betting_market_group_obj;
|
||||
});
|
||||
}
|
||||
else if (new_betting_market_group_obj)
|
||||
{
|
||||
ilog("Creating new persistent betting_market_group object ${id}", ("id", changed_betting_market_group_id));
|
||||
db.create<persistent_betting_market_group_object>([&](persistent_betting_market_group_object& saved_betting_market_group_obj) {
|
||||
saved_betting_market_group_obj.ephemeral_betting_market_group_object = *new_betting_market_group_obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (changed_object_id.space() == betting_market_object::space_id &&
|
||||
changed_object_id.type() == betting_market_object::type_id)
|
||||
{
|
||||
betting_market_id_type changed_betting_market_id = changed_object_id;
|
||||
const betting_market_object* new_betting_market_obj = nullptr;
|
||||
try
|
||||
{
|
||||
new_betting_market_obj = &changed_betting_market_id(db);
|
||||
}
|
||||
catch (fc::exception& e)
|
||||
{
|
||||
}
|
||||
// new_betting_market_obj should point to the now-changed event_object, or null if it was removed from the database
|
||||
|
||||
const persistent_betting_market_object* old_betting_market_obj = nullptr;
|
||||
|
||||
auto persistent_betting_market_iter = betting_market_id_index.find(changed_betting_market_id);
|
||||
if (persistent_betting_market_iter != betting_market_id_index.end())
|
||||
old_betting_market_obj = &*persistent_betting_market_iter;
|
||||
|
||||
// and old_betting_market_obj is a pointer to our saved copy, or nullptr if it is a new object
|
||||
if (old_betting_market_obj && new_betting_market_obj)
|
||||
{
|
||||
ilog("Modifying persistent betting_market object ${id}", ("id", changed_betting_market_id));
|
||||
db.modify(*old_betting_market_obj, [&](persistent_betting_market_object& saved_betting_market_obj) {
|
||||
saved_betting_market_obj.ephemeral_betting_market_object = *new_betting_market_obj;
|
||||
});
|
||||
}
|
||||
else if (new_betting_market_obj)
|
||||
{
|
||||
ilog("Creating new persistent betting_market object ${id}", ("id", changed_betting_market_id));
|
||||
db.create<persistent_betting_market_object>([&](persistent_betting_market_object& saved_betting_market_obj) {
|
||||
saved_betting_market_obj.ephemeral_betting_market_object = *new_betting_market_obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,29 +423,36 @@ void bookie_plugin_impl::on_block_applied( const signed_block& )
|
|||
{
|
||||
graphene::chain::database& db = database();
|
||||
const vector<optional<operation_history_object> >& hist = db.get_applied_operations();
|
||||
for( const optional< operation_history_object >& o_op : hist )
|
||||
for( const optional<operation_history_object>& o_op : hist )
|
||||
{
|
||||
if( !o_op.valid() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const operation_history_object& op = *o_op;
|
||||
if( op.op.which() == operation::tag< bet_matched_operation >::value )
|
||||
if( op.op.which() == operation::tag<bet_matched_operation>::value )
|
||||
{
|
||||
const bet_matched_operation& bet_matched_op = op.op.get<bet_matched_operation>();
|
||||
idump((bet_matched_op));
|
||||
const asset& amount_bet = bet_matched_op.amount_bet;
|
||||
// object may no longer exist
|
||||
//const bet_object& bet = bet_matched_op.bet_id(db);
|
||||
const betting_market_object& betting_market = bet_matched_op.betting_market_id(db);
|
||||
const betting_market_group_object& betting_market_group = betting_market.group_id(db);
|
||||
db.modify( betting_market_group, [&]( betting_market_group_object& obj ){
|
||||
obj.total_matched_bets_amount += amount_bet.amount;
|
||||
});
|
||||
auto& persistent_bets_by_bet_id = db.get_index_type<persistent_bet_index>().indices().get<by_bet_id>();
|
||||
auto bet_iter = persistent_bets_by_bet_id.find(bet_matched_op.bet_id);
|
||||
assert(bet_iter != persistent_bets_by_bet_id.end());
|
||||
if (bet_iter != persistent_bets_by_bet_id.end())
|
||||
{
|
||||
const bet_object& bet_obj = bet_iter->ephemeral_bet_object;
|
||||
const betting_market_object& betting_market = bet_obj.betting_market_id(db); // TODO: this needs to look at the persistent version
|
||||
const betting_market_group_object& betting_market_group = betting_market.group_id(db); // TODO: as does this
|
||||
db.modify( betting_market_group, [&]( betting_market_group_object& obj ){
|
||||
obj.total_matched_bets_amount += amount_bet.amount;
|
||||
});
|
||||
}
|
||||
}
|
||||
else if( op.op.which() == operation::tag< event_create_operation >::value )
|
||||
else if( op.op.which() == operation::tag<event_create_operation>::value )
|
||||
{
|
||||
FC_ASSERT(op.result.which() == operation_result::tag< object_id_type >::value);
|
||||
FC_ASSERT(op.result.which() == operation_result::tag<object_id_type>::value);
|
||||
//object_id_type object_id = op.result.get<object_id_type>();
|
||||
event_id_type object_id = op.result.get<object_id_type>();
|
||||
FC_ASSERT( db.find_object(object_id), "invalid event specified" );
|
||||
|
|
@ -271,7 +462,7 @@ void bookie_plugin_impl::on_block_applied( const signed_block& )
|
|||
localized_event_strings[pair.first].insert(event_string(object_id, pair.second));
|
||||
}
|
||||
}
|
||||
else if( op.op.which() == operation::tag< event_update_operation >::value )
|
||||
else if( op.op.which() == operation::tag<event_update_operation>::value )
|
||||
{
|
||||
const event_update_operation& event_create_op = op.op.get<event_update_operation>();
|
||||
if (!event_create_op.new_name.valid())
|
||||
|
|
@ -345,10 +536,8 @@ std::string bookie_plugin::plugin_name()const
|
|||
return "bookie";
|
||||
}
|
||||
|
||||
void bookie_plugin::plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg
|
||||
)
|
||||
void bookie_plugin::plugin_set_program_options(boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg)
|
||||
{
|
||||
//cli.add_options()
|
||||
// ("track-account", boost::program_options::value<std::vector<std::string>>()->composing()->multitoken(), "Account ID to track history for (may specify multiple times)")
|
||||
|
|
@ -363,8 +552,13 @@ void bookie_plugin::plugin_initialize(const boost::program_options::variables_ma
|
|||
database().changed_objects.connect([&](const vector<object_id_type>& changed_object_ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ my->on_objects_changed(changed_object_ids); });
|
||||
//auto event_index =
|
||||
database().add_index<primary_index<detail::persistent_event_object_index> >();
|
||||
//event_index->add_secondary_index<detail::events_by_competitor_index>();
|
||||
//LOAD_VALUE_SET(options, "tracked-accounts", my->_tracked_accounts, graphene::chain::account_id_type);
|
||||
database().add_index<primary_index<detail::persistent_betting_market_group_index> >();
|
||||
database().add_index<primary_index<detail::persistent_betting_market_index> >();
|
||||
database().add_index<primary_index<detail::persistent_bet_index> >();
|
||||
const primary_index<bet_object_index>& bet_object_idx = database().get_index_type<primary_index<bet_object_index> >();
|
||||
primary_index<bet_object_index>& nonconst_bet_object_idx = const_cast<primary_index<bet_object_index>&>(bet_object_idx);
|
||||
detail::persistent_bet_object_helper* persistent_bet_object_helper_index = nonconst_bet_object_idx.add_secondary_index<detail::persistent_bet_object_helper>();
|
||||
persistent_bet_object_helper_index->set_plugin_instance(this);
|
||||
|
||||
ilog("bookie plugin: plugin_startup() end");
|
||||
}
|
||||
|
|
@ -392,5 +586,8 @@ void bookie_plugin::get_events_containing_sub_string(std::vector<event_object>&
|
|||
}
|
||||
|
||||
} }
|
||||
FC_REFLECT_DERIVED( graphene::bookie::detail::persistent_event_object, (graphene::db::object), (event_object_id)(name)(season)(start_time)(event_group_id)(status)(scores) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::bookie::detail::persistent_event_object, (graphene::db::object), (event_object_id)(name)(season)(start_time)(event_group_id)(status)(scores) )
|
||||
FC_REFLECT_DERIVED( graphene::bookie::detail::persistent_betting_market_group_object, (graphene::db::object), (ephemeral_betting_market_group_object)(total_matched_bets_amount) )
|
||||
FC_REFLECT_DERIVED( graphene::bookie::detail::persistent_betting_market_object, (graphene::db::object), (ephemeral_betting_market_object) )
|
||||
FC_REFLECT_DERIVED( graphene::bookie::detail::persistent_bet_object, (graphene::db::object), (ephemeral_bet_object) )
|
||||
|
|
|
|||
|
|
@ -47,13 +47,16 @@ enum spaces {
|
|||
enum bookie_object_type
|
||||
{
|
||||
persistent_event_object_type,
|
||||
persistent_betting_market_group_object_type,
|
||||
persistent_betting_market_object_type,
|
||||
persistent_bet_object_type,
|
||||
BOOKIE_OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class bookie_plugin_impl;
|
||||
class bookie_plugin_impl;
|
||||
}
|
||||
|
||||
class bookie_plugin : public graphene::app::plugin
|
||||
|
|
@ -63,9 +66,8 @@ class bookie_plugin : public graphene::app::plugin
|
|||
virtual ~bookie_plugin();
|
||||
|
||||
std::string plugin_name()const override;
|
||||
virtual void plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg) override;
|
||||
virtual void plugin_set_program_options(boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg) override;
|
||||
virtual void plugin_initialize(const boost::program_options::variables_map& options) override;
|
||||
virtual void plugin_startup() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -1686,7 +1686,6 @@ class wallet_api
|
|||
bet_type back_or_lay,
|
||||
asset amount_to_bet,
|
||||
bet_multiplier_type backer_multiplier,
|
||||
share_type amount_reserved_for_fees,
|
||||
bool broadcast = false);
|
||||
|
||||
signed_transaction propose_resolve_betting_market_group(
|
||||
|
|
|
|||
|
|
@ -5408,7 +5408,6 @@ signed_transaction wallet_api::place_bet(
|
|||
bet_type back_or_lay,
|
||||
asset amount_to_bet,
|
||||
bet_multiplier_type backer_multiplier,
|
||||
share_type amount_reserved_for_fees,
|
||||
bool broadcast /*= false*/)
|
||||
{
|
||||
FC_ASSERT( !is_locked() );
|
||||
|
|
@ -5419,7 +5418,6 @@ signed_transaction wallet_api::place_bet(
|
|||
bet_place_op.betting_market_id = betting_market_id;
|
||||
bet_place_op.amount_to_bet = amount_to_bet;
|
||||
bet_place_op.backer_multiplier = backer_multiplier;
|
||||
bet_place_op.amount_reserved_for_fees = amount_reserved_for_fees;
|
||||
bet_place_op.back_or_lay = back_or_lay;
|
||||
|
||||
signed_transaction tx;
|
||||
|
|
|
|||
|
|
@ -135,12 +135,12 @@ BOOST_AUTO_TEST_CASE(simple_bet_win)
|
|||
transfer(account_id_type(), bob_id, asset(10000));
|
||||
|
||||
// place bets at 10:1
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 2);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 20);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
// reverse positions at 1:1
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -159,11 +159,11 @@ BOOST_AUTO_TEST_CASE(binned_order_books)
|
|||
transfer(account_id_type(), bob_id, asset(10000));
|
||||
|
||||
// place back bets at decimal odds of 1.55, 1.6, 1.65, 1.66, and 1.67
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
|
||||
const auto& bet_odds_idx = db.get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(binned_order_books)
|
|||
// compute the matching lay order
|
||||
share_type lay_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::back, false /* round down */);
|
||||
ilog("Alice is laying with ${lay_amount} at odds ${odds} to match the binned back amount ${back_amount}", ("lay_amount", lay_amount)("odds", binned_order.backer_multiplier)("back_amount", binned_order.amount_to_bet));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(lay_amount, asset_id_type()), binned_order.backer_multiplier, 2);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(lay_amount, asset_id_type()), binned_order.backer_multiplier);
|
||||
}
|
||||
|
||||
bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||
|
|
@ -201,11 +201,11 @@ BOOST_AUTO_TEST_CASE(binned_order_books)
|
|||
BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)) == bet_odds_idx.end());
|
||||
|
||||
// place lay bets at decimal odds of 1.55, 1.6, 1.65, 1.66, and 1.67
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
|
||||
binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1);
|
||||
idump((binned_orders_point_one));
|
||||
|
|
@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE(binned_order_books)
|
|||
// compute the matching lay order
|
||||
share_type back_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::lay, false /* round down */);
|
||||
ilog("Alice is backing with ${back_amount} at odds ${odds} to match the binned lay amount ${lay_amount}", ("back_amount", back_amount)("odds", binned_order.backer_multiplier)("lay_amount", binned_order.amount_to_bet));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier, 2);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier);
|
||||
}
|
||||
|
||||
bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||
|
|
@ -247,12 +247,12 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test )
|
|||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
|
||||
// have bob lay a bet for 1M (+20k fees) at 1:1 odds
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
// have alice back a matching bet at 1:1 odds (also costing 1.02M)
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(moneyline_betting_markets.id,
|
||||
|
|
@ -263,8 +263,8 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test )
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -281,25 +281,66 @@ BOOST_AUTO_TEST_CASE( cancel_unmatched_in_betting_group_test )
|
|||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
|
||||
// have bob lay a bet for 1M (+20k fees) at 1:1 odds
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
// have alice back a matching bet at 1:1 odds (also costing 1.02M)
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
// place unmatched
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 10);
|
||||
place_bet(bob_id, blackhawks_win_market.id, bet_type::lay, asset(600, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 20);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, blackhawks_win_market.id, bet_type::lay, asset(600, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 - 500 - 10);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000 - 600 - 20);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 500);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 600);
|
||||
|
||||
// cancel unmatched
|
||||
cancel_unmatched_bets(moneyline_betting_markets.id);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inexact_odds)
|
||||
{
|
||||
try
|
||||
{
|
||||
ACTORS( (alice)(bob) );
|
||||
CREATE_ICE_HOCKEY_BETTING_MARKET();
|
||||
|
||||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
share_type alice_expected_balance = 10000000;
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value);
|
||||
|
||||
// lay 47 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
alice_expected_balance -= 47;
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value);
|
||||
|
||||
// lay 100 at 1.91 odds (100:91) -- this is an inexact match, we should get refunded 9 and leave a bet for 91 on the books
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
alice_expected_balance -= 91;
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value);
|
||||
|
||||
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
share_type bob_expected_balance = 10000000;
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value);
|
||||
|
||||
// now have bob match it with a back of 300 at 1.91
|
||||
// This should:
|
||||
// match the full 47 @ 1.94 with 50
|
||||
// match the full 91 @ 1.91 with 100
|
||||
// leaving 150
|
||||
// back bets at 100:91 must be a multiple of 100, so refund 50
|
||||
// leaves a back bet of 100 @ 1.91 on the books
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(300, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100);
|
||||
bob_expected_balance -= 250;
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value);
|
||||
}
|
||||
FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( chained_market_create_test )
|
||||
{
|
||||
// Often you will want to create several objects that reference each other at the same time.
|
||||
|
|
@ -430,12 +471,12 @@ struct simple_bet_test_fixture : database_fixture {
|
|||
transfer(account_id_type(), bob_id, asset(10000));
|
||||
|
||||
// place bets at 10:1
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 2);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 20);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
// reverse positions at 1:1
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
capitals_win_betting_market_id = capitals_win_market.id;
|
||||
blackhawks_win_betting_market_id = blackhawks_win_market.id;
|
||||
|
|
@ -459,13 +500,13 @@ BOOST_AUTO_TEST_CASE( win )
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value;
|
||||
//rake_value = (-100 + 1100 - 1100) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
// alice starts with 10000, pays 100 (bet) + 2 (fee), wins 1100, then pays 1100 (bet) + 22 (fee), wins 0
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 - 2 + 1100 - 1100 - 22 + 0);
|
||||
// alice starts with 10000, pays 100 (bet), wins 1100, then pays 1100 (bet), wins 0
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 + 1100 - 1100 + 0);
|
||||
|
||||
rake_value = (-1000 - 1100 + 2200) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
// bob starts with 10000, pays 1000 (bet) + 20 (fee), wins 0, then pays 1100 (bet) + 22 (fee), wins 2200
|
||||
// bob starts with 10000, pays 1000 (bet), wins 0, then pays 1100 (bet), wins 2200
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 - 20 + 0 - 1100 - 22 + 2200 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 + 0 - 1100 + 2200 - rake_value);
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
|
|
@ -482,13 +523,13 @@ BOOST_AUTO_TEST_CASE( not_win )
|
|||
|
||||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-100 - 1100 + 2200) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
// alice starts with 10000, pays 100 (bet) + 2 (fee), wins 0, then pays 1100 (bet) + 22 (fee), wins 2200
|
||||
// alice starts with 10000, pays 100 (bet), wins 0, then pays 1100 (bet), wins 2200
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 - 2 + 0 - 1100 - 22 + 2200 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 + 0 - 1100 + 2200 - rake_value);
|
||||
|
||||
//rake_value = (-1000 + 1100 - 1100) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
// bob starts with 10000, pays 1000 (bet) + 20 (fee), wins 1100, then pays 1100 (bet) + 22 (fee), wins 0
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 - 20 + 1100 - 1100 - 22 + 0);
|
||||
// bob starts with 10000, pays 1000 (bet), wins 1100, then pays 1100 (bet), wins 0
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 + 1100 - 1100 + 0);
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
|
|
@ -523,21 +564,21 @@ struct simple_bet_test_fixture_2 : database_fixture {
|
|||
transfer(account_id_type(), bob_id, asset(10000));
|
||||
|
||||
// alice backs 1000 at 1:1, matches
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 20);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 20);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
// now alice lays at 2500 at 1:1. This should require a deposit of 500, with the remaining 200 being funded from exposure
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(2500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 50);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(2500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
// match the bet bit by bit. bob matches 500 of alice's 2500 bet. This effectively cancels half of bob's lay position
|
||||
// so he immediately gets 500 back. It reduces alice's back position, but doesn't return any money to her (all 2000 of her exposure
|
||||
// was already "promised" to her lay bet, so the 500 she would have received is placed in her refundable_unmatched_bets)
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 10);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
// match another 500, which will fully cancel bob's lay position and return the other 500 he had locked up in his position.
|
||||
// alice's back position is now canceled, 1500 remains of her unmatched lay bet, and the 500 from canceling her position has
|
||||
// been moved to her refundable_unmatched_bets
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 10);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
capitals_win_betting_market_id = capitals_win_market.id;
|
||||
}
|
||||
|
|
@ -554,9 +595,9 @@ BOOST_AUTO_TEST_CASE(sport_update_test)
|
|||
update_sport(ice_hockey.id, {{"en", "Hockey on Ice"}, {"zh_Hans", "冰"}, {"ja", "アイスホッケ"}});
|
||||
|
||||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -571,7 +612,7 @@ BOOST_AUTO_TEST_CASE(event_group_update_test)
|
|||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
const sport_object& ice_on_hockey = create_sport({{"en", "Hockey on Ice"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \
|
||||
fc::optional<object_id_type> sport_id = ice_on_hockey.id;
|
||||
|
|
@ -582,10 +623,10 @@ BOOST_AUTO_TEST_CASE(event_group_update_test)
|
|||
update_event_group(nhl.id, sport_id, fc::optional<internationalized_string_type>());
|
||||
update_event_group(nhl.id, sport_id, name);
|
||||
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(moneyline_betting_markets.id,
|
||||
|
|
@ -596,8 +637,8 @@ BOOST_AUTO_TEST_CASE(event_group_update_test)
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -613,7 +654,7 @@ BOOST_AUTO_TEST_CASE(event_update_test)
|
|||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
fc::optional<internationalized_string_type> empty;
|
||||
fc::optional<internationalized_string_type> name = internationalized_string_type({{"en", "Washington Capitals vs. Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホーク"}});
|
||||
|
|
@ -631,10 +672,10 @@ BOOST_AUTO_TEST_CASE(event_update_test)
|
|||
|
||||
update_event(capitals_vs_blackhawks.id, event_group_id , empty, empty, empty_bool);
|
||||
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(moneyline_betting_markets.id,
|
||||
|
|
@ -645,8 +686,8 @@ BOOST_AUTO_TEST_CASE(event_update_test)
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -667,9 +708,9 @@ BOOST_AUTO_TEST_CASE(betting_market_rules_update_test)
|
|||
update_betting_market_rules(betting_market_rules.id, name, desc);
|
||||
|
||||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -682,7 +723,7 @@ BOOST_AUTO_TEST_CASE(betting_market_group_update_test)
|
|||
CREATE_ICE_HOCKEY_BETTING_MARKET();
|
||||
|
||||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
fc::optional<internationalized_string_type> dempty;
|
||||
fc::optional<object_id_type> empty_object_id;
|
||||
|
|
@ -702,10 +743,10 @@ BOOST_AUTO_TEST_CASE(betting_market_group_update_test)
|
|||
update_betting_market_group(moneyline_betting_markets.id, new_desc, new_event, new_rule, freeze);
|
||||
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(moneyline_betting_markets.id,
|
||||
|
|
@ -716,8 +757,8 @@ BOOST_AUTO_TEST_CASE(betting_market_group_update_test)
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -730,7 +771,7 @@ BOOST_AUTO_TEST_CASE(betting_market_update_test)
|
|||
CREATE_ICE_HOCKEY_BETTING_MARKET();
|
||||
|
||||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
const betting_market_group_object& new_moneyline_betting_markets = create_betting_market_group({{"en", "New Moneyline"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type()); \
|
||||
fc::optional<object_id_type> betting_market_group = new_moneyline_betting_markets.id;
|
||||
|
|
@ -744,10 +785,10 @@ BOOST_AUTO_TEST_CASE(betting_market_update_test)
|
|||
update_betting_market(blackhawks_win_market.id, betting_market_group, fc::optional<internationalized_string_type>());
|
||||
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(new_moneyline_betting_markets.id,
|
||||
|
|
@ -758,8 +799,8 @@ BOOST_AUTO_TEST_CASE(betting_market_update_test)
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -780,9 +821,9 @@ BOOST_AUTO_TEST_SUITE(other_betting_tests)
|
|||
{ \
|
||||
if (1) \
|
||||
{ \
|
||||
edump(("###")); \
|
||||
elog("###"); \
|
||||
edump((e.to_detail_string())); \
|
||||
edump(("###")); \
|
||||
elog("###"); \
|
||||
} \
|
||||
FC_ASSERT(e.to_detail_string().find(reason) != \
|
||||
std::string::npos, "expected error hasn't occured");\
|
||||
|
|
@ -803,7 +844,7 @@ BOOST_FIXTURE_TEST_CASE( another_event_group_update_test, database_fixture)
|
|||
transfer(account_id_type(), alice_id, asset(10000000));
|
||||
transfer(account_id_type(), bob_id, asset(10000000));
|
||||
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
fc::optional<internationalized_string_type> name = internationalized_string_type({{"en", "IBM"}, {"zh_Hans", "國家冰球聯"}, {"ja", "ナショナルホッケーリー"}});
|
||||
|
||||
|
|
@ -832,10 +873,10 @@ BOOST_FIXTURE_TEST_CASE( another_event_group_update_test, database_fixture)
|
|||
//GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, sport_id, fc::optional<internationalized_string_type>()), fc::exception);
|
||||
TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional<internationalized_string_type>()), fc::exception, "invalid sport specified");
|
||||
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// caps win
|
||||
resolve_betting_market_group(moneyline_betting_markets.id,
|
||||
|
|
@ -846,8 +887,8 @@ BOOST_FIXTURE_TEST_CASE( another_event_group_update_test, database_fixture)
|
|||
uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage;
|
||||
uint32_t rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Rake value " + std::to_string(rake_value));
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 + 2000000 - rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -895,17 +936,17 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_sf_test )
|
|||
BOOST_TEST_MESSAGE("cilic_wins_market " << fc::variant(cilic_wins_market.id).as<std::string>());
|
||||
BOOST_TEST_MESSAGE("querrey_wins_market " << fc::variant(querrey_wins_market.id).as<std::string>());
|
||||
|
||||
place_bet(alice_id, berdych_wins_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, berdych_wins_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, berdych_wins_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, berdych_wins_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
place_bet(alice_id, cilic_wins_market.id, bet_type::back, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 100000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, cilic_wins_market.id, bet_type::lay, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 100000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, cilic_wins_market.id, bet_type::back, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, cilic_wins_market.id, bet_type::lay, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 100000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 100000);
|
||||
|
||||
// federer wins
|
||||
resolve_betting_market_group(moneyline_berdych_vs_federer.id,
|
||||
|
|
@ -915,8 +956,8 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_sf_test )
|
|||
uint32_t bob_rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Bob's rake value " + std::to_string(bob_rake_value));
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000 + 2000000 - bob_rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 100000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 100000 + 2000000 - bob_rake_value);
|
||||
|
||||
// cilic wins
|
||||
resolve_betting_market_group(moneyline_cilic_vs_querrey.id,
|
||||
|
|
@ -926,8 +967,8 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_sf_test )
|
|||
uint32_t alice_rake_value = (-100000 + 200000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Alice rake value " + std::to_string(alice_rake_value));
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000 + 200000 - alice_rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000 - 100000 - 2000 + 2000000 - bob_rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 100000 + 200000 - alice_rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 100000 + 2000000 - bob_rake_value);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -949,8 +990,8 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test )
|
|||
BOOST_TEST_MESSAGE("federer_wins_final_market " << fc::variant(federer_wins_final_market.id).as<std::string>());
|
||||
BOOST_TEST_MESSAGE("cilic_wins_final_market " << fc::variant(cilic_wins_final_market.id).as<std::string>());
|
||||
|
||||
place_bet(alice_id, cilic_wins_final_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(bob_id, cilic_wins_final_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */);
|
||||
place_bet(alice_id, cilic_wins_final_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
place_bet(bob_id, cilic_wins_final_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||
|
||||
betting_market_group_id_type moneyline_cilic_vs_federer_id = moneyline_cilic_vs_federer.id;
|
||||
auto cilic_wins_final_market_id = cilic_wins_final_market.id;
|
||||
|
|
@ -966,8 +1007,8 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test )
|
|||
const betting_market_group_object& betting_market_group = moneyline_cilic_vs_federer_id(db);
|
||||
BOOST_CHECK_EQUAL(betting_market_group.total_matched_bets_amount.value, 2000000);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000);
|
||||
|
||||
// federer wins
|
||||
resolve_betting_market_group(moneyline_cilic_vs_federer_id,
|
||||
|
|
@ -977,8 +1018,8 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test )
|
|||
uint32_t bob_rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100;
|
||||
BOOST_TEST_MESSAGE("Bob's rake value " + std::to_string(bob_rake_value));
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000 - bob_rake_value);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 + 2000000 - bob_rake_value);
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@ void database_fixture::verify_asset_supplies( const database& db )
|
|||
for (const bet_object& o : db.get_index_type<bet_object_index>().indices())
|
||||
{
|
||||
total_balances[o.amount_to_bet.asset_id] += o.amount_to_bet.amount;
|
||||
total_balances[o.amount_to_bet.asset_id] += o.amount_reserved_for_fees;
|
||||
}
|
||||
for (const betting_market_position_object& o : db.get_index_type<betting_market_position_index>().indices())
|
||||
{
|
||||
|
|
@ -1396,14 +1395,13 @@ void database_fixture::update_betting_market(betting_market_id_type betting_mark
|
|||
} FC_CAPTURE_AND_RETHROW( (betting_market_id) (group_id) (payout_condition) ) }
|
||||
|
||||
|
||||
void database_fixture::place_bet(account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, asset amount_to_bet, bet_multiplier_type backer_multiplier, share_type amount_reserved_for_fees)
|
||||
void database_fixture::place_bet(account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, asset amount_to_bet, bet_multiplier_type backer_multiplier)
|
||||
{ try {
|
||||
bet_place_operation bet_place_op;
|
||||
bet_place_op.bettor_id = bettor_id;
|
||||
bet_place_op.betting_market_id = betting_market_id;
|
||||
bet_place_op.amount_to_bet = amount_to_bet;
|
||||
bet_place_op.backer_multiplier = backer_multiplier;
|
||||
bet_place_op.amount_reserved_for_fees = amount_reserved_for_fees;
|
||||
bet_place_op.back_or_lay = back_or_lay;
|
||||
|
||||
trx.operations.push_back(bet_place_op);
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ struct database_fixture {
|
|||
/*fc::optional<internationalized_string_type> description,*/
|
||||
fc::optional<internationalized_string_type> payout_condition);
|
||||
|
||||
void place_bet(account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, asset amount_to_bet, bet_multiplier_type backer_multiplier, share_type amount_reserved_for_fees);
|
||||
void place_bet(account_id_type bettor_id, betting_market_id_type betting_market_id, bet_type back_or_lay, asset amount_to_bet, bet_multiplier_type backer_multiplier);
|
||||
void resolve_betting_market_group(betting_market_group_id_type betting_market_group_id, std::map<betting_market_id_type, betting_market_resolution_type> resolutions);
|
||||
void cancel_unmatched_bets(betting_market_group_id_type betting_market_group_id);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue