Finish delayed (live) betting.
Remove the ability to change the event of a betting market group after creation.
This commit is contained in:
parent
08a8e11374
commit
b505c375af
13 changed files with 376 additions and 164 deletions
|
|
@ -42,7 +42,7 @@ void_result betting_market_rules_create_evaluator::do_evaluate(const betting_mar
|
||||||
object_id_type betting_market_rules_create_evaluator::do_apply(const betting_market_rules_create_operation& op)
|
object_id_type betting_market_rules_create_evaluator::do_apply(const betting_market_rules_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const betting_market_rules_object& new_betting_market_rules =
|
const betting_market_rules_object& new_betting_market_rules =
|
||||||
db().create<betting_market_rules_object>( [&]( betting_market_rules_object& betting_market_rules_obj ) {
|
db().create<betting_market_rules_object>([&](betting_market_rules_object& betting_market_rules_obj) {
|
||||||
betting_market_rules_obj.name = op.name;
|
betting_market_rules_obj.name = op.name;
|
||||||
betting_market_rules_obj.description = op.description;
|
betting_market_rules_obj.description = op.description;
|
||||||
});
|
});
|
||||||
|
|
@ -52,27 +52,25 @@ object_id_type betting_market_rules_create_evaluator::do_apply(const betting_mar
|
||||||
void_result betting_market_rules_update_evaluator::do_evaluate(const betting_market_rules_update_operation& op)
|
void_result betting_market_rules_update_evaluator::do_evaluate(const betting_market_rules_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
FC_ASSERT(trx_state->_is_proposed_trx);
|
FC_ASSERT(trx_state->_is_proposed_trx);
|
||||||
FC_ASSERT(op.new_name.valid() || op.new_description.valid());
|
_rules = &op.betting_market_rules_id(db());
|
||||||
|
FC_ASSERT(op.new_name.valid() || op.new_description.valid(), "nothing to update");
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_rules_update_evaluator::do_apply(const betting_market_rules_update_operation& op)
|
void_result betting_market_rules_update_evaluator::do_apply(const betting_market_rules_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
database& _db = db();
|
db().modify(*_rules, [&](betting_market_rules_object& betting_market_rules) {
|
||||||
_db.modify(
|
if (op.new_name.valid())
|
||||||
_db.get(op.betting_market_rules_id),
|
betting_market_rules.name = *op.new_name;
|
||||||
[&]( betting_market_rules_object& bmro )
|
if (op.new_description.valid())
|
||||||
{
|
betting_market_rules.description = *op.new_description;
|
||||||
if( op.new_name.valid() )
|
});
|
||||||
bmro.name = *op.new_name;
|
return void_result();
|
||||||
if( op.new_description.valid() )
|
|
||||||
bmro.description = *op.new_description;
|
|
||||||
});
|
|
||||||
return void_result();
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_group_create_evaluator::do_evaluate(const betting_market_group_create_operation& op)
|
void_result betting_market_group_create_evaluator::do_evaluate(const betting_market_group_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
|
database& d = db();
|
||||||
FC_ASSERT(trx_state->_is_proposed_trx);
|
FC_ASSERT(trx_state->_is_proposed_trx);
|
||||||
|
|
||||||
// the event_id in the operation can be a relative id. If it is,
|
// the event_id in the operation can be a relative id. If it is,
|
||||||
|
|
@ -84,10 +82,10 @@ void_result betting_market_group_create_evaluator::do_evaluate(const betting_mar
|
||||||
FC_ASSERT(resolved_event_id.space() == event_id_type::space_id &&
|
FC_ASSERT(resolved_event_id.space() == event_id_type::space_id &&
|
||||||
resolved_event_id.type() == event_id_type::type_id,
|
resolved_event_id.type() == event_id_type::type_id,
|
||||||
"event_id must refer to a event_id_type");
|
"event_id must refer to a event_id_type");
|
||||||
event_id = resolved_event_id;
|
_event_id = resolved_event_id;
|
||||||
FC_ASSERT( db().find_object(event_id), "Invalid event specified" );
|
FC_ASSERT(d.find_object(_event_id), "Invalid event specified");
|
||||||
|
|
||||||
FC_ASSERT( db().find_object(op.asset_id), "Invalid asset specified" );
|
FC_ASSERT(d.find_object(op.asset_id), "Invalid asset specified");
|
||||||
|
|
||||||
// the rules_id in the operation can be a relative id. If it is,
|
// the rules_id in the operation can be a relative id. If it is,
|
||||||
// resolve it and verify that it is truly rules
|
// resolve it and verify that it is truly rules
|
||||||
|
|
@ -98,97 +96,101 @@ void_result betting_market_group_create_evaluator::do_evaluate(const betting_mar
|
||||||
FC_ASSERT(resolved_rules_id.space() == betting_market_rules_id_type::space_id &&
|
FC_ASSERT(resolved_rules_id.space() == betting_market_rules_id_type::space_id &&
|
||||||
resolved_rules_id.type() == betting_market_rules_id_type::type_id,
|
resolved_rules_id.type() == betting_market_rules_id_type::type_id,
|
||||||
"rules_id must refer to a betting_market_rules_id_type");
|
"rules_id must refer to a betting_market_rules_id_type");
|
||||||
rules_id = resolved_rules_id;
|
_rules_id = resolved_rules_id;
|
||||||
FC_ASSERT( db().find_object(rules_id), "Invalid rules specified" );
|
FC_ASSERT(d.find_object(_rules_id), "Invalid rules specified");
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW((op)) }
|
||||||
|
|
||||||
object_id_type betting_market_group_create_evaluator::do_apply(const betting_market_group_create_operation& op)
|
object_id_type betting_market_group_create_evaluator::do_apply(const betting_market_group_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const betting_market_group_object& new_betting_market_group =
|
const betting_market_group_object& new_betting_market_group =
|
||||||
db().create<betting_market_group_object>( [&]( betting_market_group_object& betting_market_group_obj ) {
|
db().create<betting_market_group_object>([&](betting_market_group_object& betting_market_group_obj) {
|
||||||
betting_market_group_obj.event_id = event_id;
|
betting_market_group_obj.event_id = _event_id;
|
||||||
betting_market_group_obj.rules_id = rules_id;
|
betting_market_group_obj.rules_id = _rules_id;
|
||||||
betting_market_group_obj.description = op.description;
|
betting_market_group_obj.description = op.description;
|
||||||
betting_market_group_obj.asset_id = op.asset_id;
|
betting_market_group_obj.asset_id = op.asset_id;
|
||||||
betting_market_group_obj.frozen = false;
|
betting_market_group_obj.frozen = false;
|
||||||
betting_market_group_obj.delay_bets = false;
|
betting_market_group_obj.delay_bets = false;
|
||||||
});
|
});
|
||||||
return new_betting_market_group.id;
|
return new_betting_market_group.id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_group_update_evaluator::do_evaluate(const betting_market_group_update_operation& op)
|
void_result betting_market_group_update_evaluator::do_evaluate(const betting_market_group_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
|
database& d = db();
|
||||||
FC_ASSERT(trx_state->_is_proposed_trx);
|
FC_ASSERT(trx_state->_is_proposed_trx);
|
||||||
FC_ASSERT(op.new_event_id.valid() ||
|
_betting_market_group = &op.betting_market_group_id(d);
|
||||||
op.new_description.valid() ||
|
|
||||||
|
FC_ASSERT(op.new_description.valid() ||
|
||||||
op.new_rules_id.valid() ||
|
op.new_rules_id.valid() ||
|
||||||
op.freeze.valid() ||
|
op.freeze.valid() ||
|
||||||
op.delay_bets.valid(), "nothing to change");
|
op.delay_bets.valid(), "nothing to change");
|
||||||
|
|
||||||
// the event_id in the operation can be a relative id. If it is,
|
|
||||||
// resolve it and verify that it is truly an event
|
|
||||||
if (op.new_event_id.valid())
|
|
||||||
{
|
|
||||||
object_id_type resolved_event_id = *op.new_event_id;
|
|
||||||
if (is_relative(*op.new_event_id))
|
|
||||||
resolved_event_id = get_relative_id(*op.new_event_id);
|
|
||||||
|
|
||||||
FC_ASSERT(resolved_event_id.space() == event_id_type::space_id &&
|
|
||||||
resolved_event_id.type() == event_id_type::type_id,
|
|
||||||
"event_id must refer to a event_id_type");
|
|
||||||
event_id = resolved_event_id;
|
|
||||||
FC_ASSERT( db().find_object(event_id), "invalid event specified" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.new_rules_id.valid())
|
if (op.new_rules_id.valid())
|
||||||
{
|
{
|
||||||
// the rules_id in the operation can be a relative id. If it is,
|
// the rules_id in the operation can be a relative id. If it is,
|
||||||
// resolve it and verify that it is truly rules
|
// resolve it and verify that it is truly rules
|
||||||
object_id_type resolved_rules_id = *op.new_rules_id;
|
object_id_type resolved_rules_id = *op.new_rules_id;
|
||||||
if (is_relative(*op.new_rules_id))
|
if (is_relative(*op.new_rules_id))
|
||||||
resolved_rules_id = get_relative_id(*op.new_rules_id);
|
resolved_rules_id = get_relative_id(*op.new_rules_id);
|
||||||
|
|
||||||
FC_ASSERT(resolved_rules_id.space() == betting_market_rules_id_type::space_id &&
|
FC_ASSERT(resolved_rules_id.space() == betting_market_rules_id_type::space_id &&
|
||||||
resolved_rules_id.type() == betting_market_rules_id_type::type_id,
|
resolved_rules_id.type() == betting_market_rules_id_type::type_id,
|
||||||
"rules_id must refer to a betting_market_rules_id_type");
|
"rules_id must refer to a betting_market_rules_id_type");
|
||||||
rules_id = resolved_rules_id;
|
_rules_id = resolved_rules_id;
|
||||||
FC_ASSERT( db().find_object(rules_id), "invalid rules specified" );
|
FC_ASSERT(d.find_object(_rules_id), "invalid rules specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.freeze.valid())
|
if (op.freeze.valid())
|
||||||
{
|
FC_ASSERT(_betting_market_group->frozen != *op.freeze, "freeze would not change the state of the betting market group");
|
||||||
const auto& _betting_market_group = &op.betting_market_group_id(db());
|
|
||||||
FC_ASSERT(_betting_market_group->frozen != *op.freeze, "freeze would not change the state of the betting market group");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.delay_bets.valid())
|
if (op.delay_bets.valid())
|
||||||
{
|
FC_ASSERT(_betting_market_group->delay_bets != *op.delay_bets, "delay_bets would not change the state of the betting market group");
|
||||||
const auto& _betting_market_group = &op.betting_market_group_id(db());
|
|
||||||
FC_ASSERT(_betting_market_group->delay_bets != *op.delay_bets, "delay_bets would not change the state of the betting market group");
|
|
||||||
}
|
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_group_update_evaluator::do_apply(const betting_market_group_update_operation& op)
|
void_result betting_market_group_update_evaluator::do_apply(const betting_market_group_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
database& _db = db();
|
database& d = db();
|
||||||
_db.modify(
|
d.modify(*_betting_market_group, [&](betting_market_group_object& betting_market_group) {
|
||||||
_db.get(op.betting_market_group_id),
|
if (op.new_description.valid())
|
||||||
[&]( betting_market_group_object& bmgo )
|
betting_market_group.description = *op.new_description;
|
||||||
{
|
if (op.new_rules_id.valid())
|
||||||
if( op.new_description.valid() )
|
betting_market_group.rules_id = _rules_id;
|
||||||
bmgo.description = *op.new_description;
|
if (op.freeze.valid())
|
||||||
if( op.new_event_id.valid() )
|
betting_market_group.frozen = *op.freeze;
|
||||||
bmgo.event_id = event_id;
|
if (op.delay_bets.valid())
|
||||||
if( op.new_rules_id.valid() )
|
{
|
||||||
bmgo.rules_id = rules_id;
|
assert(_betting_market_group->delay_bets != *op.delay_bets); // we checked this in evaluate
|
||||||
if( op.freeze.valid() )
|
betting_market_group.delay_bets = *op.delay_bets;
|
||||||
bmgo.frozen = *op.freeze;
|
if (!*op.delay_bets)
|
||||||
if( op.delay_bets.valid() )
|
{
|
||||||
bmgo.delay_bets = *op.delay_bets;
|
// we have switched from delayed to not-delayed. if there are any delayed bets,
|
||||||
});
|
// push them through now.
|
||||||
return void_result();
|
const auto& bet_odds_idx = d.get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||||
|
auto bet_iter = bet_odds_idx.begin();
|
||||||
|
bool last = bet_iter == bet_odds_idx.end() || !bet_iter->end_of_delay;
|
||||||
|
while (!last)
|
||||||
|
{
|
||||||
|
const bet_object& delayed_bet = *bet_iter;
|
||||||
|
++bet_iter;
|
||||||
|
last = bet_iter == bet_odds_idx.end() || !bet_iter->end_of_delay;
|
||||||
|
|
||||||
|
const betting_market_object& betting_market = delayed_bet.betting_market_id(d);
|
||||||
|
if (betting_market.group_id == op.betting_market_group_id && !_betting_market_group->frozen)
|
||||||
|
{
|
||||||
|
d.modify(delayed_bet, [](bet_object& bet_obj) {
|
||||||
|
// clear the end_of_delay, which will re-sort the bet into its place in the book
|
||||||
|
bet_obj.end_of_delay.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
d.place_bet(delayed_bet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_create_evaluator::do_evaluate(const betting_market_create_operation& op)
|
void_result betting_market_create_evaluator::do_evaluate(const betting_market_create_operation& op)
|
||||||
|
|
@ -204,8 +206,8 @@ void_result betting_market_create_evaluator::do_evaluate(const betting_market_cr
|
||||||
FC_ASSERT(resolved_betting_market_group_id.space() == betting_market_group_id_type::space_id &&
|
FC_ASSERT(resolved_betting_market_group_id.space() == betting_market_group_id_type::space_id &&
|
||||||
resolved_betting_market_group_id.type() == betting_market_group_id_type::type_id,
|
resolved_betting_market_group_id.type() == betting_market_group_id_type::type_id,
|
||||||
"betting_market_group_id must refer to a betting_market_group_id_type");
|
"betting_market_group_id must refer to a betting_market_group_id_type");
|
||||||
group_id = resolved_betting_market_group_id;
|
_group_id = resolved_betting_market_group_id;
|
||||||
FC_ASSERT( db().find_object(group_id), "Invalid betting_market_group specified" );
|
FC_ASSERT(db().find_object(_group_id), "Invalid betting_market_group specified");
|
||||||
|
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
@ -213,32 +215,34 @@ void_result betting_market_create_evaluator::do_evaluate(const betting_market_cr
|
||||||
object_id_type betting_market_create_evaluator::do_apply(const betting_market_create_operation& op)
|
object_id_type betting_market_create_evaluator::do_apply(const betting_market_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const betting_market_object& new_betting_market =
|
const betting_market_object& new_betting_market =
|
||||||
db().create<betting_market_object>( [&]( betting_market_object& betting_market_obj ) {
|
db().create<betting_market_object>([&](betting_market_object& betting_market_obj) {
|
||||||
betting_market_obj.group_id = group_id;
|
betting_market_obj.group_id = _group_id;
|
||||||
betting_market_obj.description = op.description;
|
betting_market_obj.description = op.description;
|
||||||
betting_market_obj.payout_condition = op.payout_condition;
|
betting_market_obj.payout_condition = op.payout_condition;
|
||||||
});
|
});
|
||||||
return new_betting_market.id;
|
return new_betting_market.id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result betting_market_update_evaluator::do_evaluate(const betting_market_update_operation& op)
|
void_result betting_market_update_evaluator::do_evaluate(const betting_market_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
|
database& d = db();
|
||||||
FC_ASSERT(trx_state->_is_proposed_trx);
|
FC_ASSERT(trx_state->_is_proposed_trx);
|
||||||
|
_betting_market = &op.betting_market_id(d);
|
||||||
FC_ASSERT(op.new_group_id.valid() || op.new_description.valid() || op.new_payout_condition.valid(), "nothing to change");
|
FC_ASSERT(op.new_group_id.valid() || op.new_description.valid() || op.new_payout_condition.valid(), "nothing to change");
|
||||||
|
|
||||||
if (op.new_group_id.valid())
|
if (op.new_group_id.valid())
|
||||||
{
|
{
|
||||||
// the betting_market_group_id in the operation can be a relative id. If it is,
|
// the betting_market_group_id in the operation can be a relative id. If it is,
|
||||||
// resolve it and verify that it is truly an betting_market_group
|
// resolve it and verify that it is truly an betting_market_group
|
||||||
object_id_type resolved_betting_market_group_id = *op.new_group_id;
|
object_id_type resolved_betting_market_group_id = *op.new_group_id;
|
||||||
if (is_relative(*op.new_group_id))
|
if (is_relative(*op.new_group_id))
|
||||||
resolved_betting_market_group_id = get_relative_id(*op.new_group_id);
|
resolved_betting_market_group_id = get_relative_id(*op.new_group_id);
|
||||||
|
|
||||||
FC_ASSERT(resolved_betting_market_group_id.space() == betting_market_group_id_type::space_id &&
|
FC_ASSERT(resolved_betting_market_group_id.space() == betting_market_group_id_type::space_id &&
|
||||||
resolved_betting_market_group_id.type() == betting_market_group_id_type::type_id,
|
resolved_betting_market_group_id.type() == betting_market_group_id_type::type_id,
|
||||||
"betting_market_group_id must refer to a betting_market_group_id_type");
|
"betting_market_group_id must refer to a betting_market_group_id_type");
|
||||||
group_id = resolved_betting_market_group_id;
|
_group_id = resolved_betting_market_group_id;
|
||||||
FC_ASSERT( db().find_object(group_id), "invalid betting_market_group specified" );
|
FC_ASSERT(d.find_object(_group_id), "invalid betting_market_group specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
return void_result();
|
return void_result();
|
||||||
|
|
@ -246,19 +250,15 @@ void_result betting_market_update_evaluator::do_evaluate(const betting_market_up
|
||||||
|
|
||||||
void_result betting_market_update_evaluator::do_apply(const betting_market_update_operation& op)
|
void_result betting_market_update_evaluator::do_apply(const betting_market_update_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
database& _db = db();
|
db().modify(*_betting_market, [&](betting_market_object& betting_market) {
|
||||||
_db.modify(
|
if (op.new_group_id.valid())
|
||||||
_db.get(op.betting_market_id),
|
betting_market.group_id = _group_id;
|
||||||
[&]( betting_market_object& bmo )
|
if (op.new_payout_condition.valid())
|
||||||
{
|
betting_market.payout_condition = *op.new_payout_condition;
|
||||||
if( op.new_group_id.valid() )
|
if (op.new_description.valid())
|
||||||
bmo.group_id = group_id;
|
betting_market.description = *op.new_description;
|
||||||
if( op.new_payout_condition.valid() )
|
});
|
||||||
bmo.payout_condition = *op.new_payout_condition;
|
return void_result();
|
||||||
if( op.new_description.valid() )
|
|
||||||
bmo.description = *op.new_description;
|
|
||||||
});
|
|
||||||
return void_result();
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result bet_place_evaluator::do_evaluate(const bet_place_operation& op)
|
void_result bet_place_evaluator::do_evaluate(const bet_place_operation& op)
|
||||||
|
|
@ -276,18 +276,18 @@ void_result bet_place_evaluator::do_evaluate(const bet_place_operation& op)
|
||||||
_asset = &_betting_market_group->asset_id(d);
|
_asset = &_betting_market_group->asset_id(d);
|
||||||
FC_ASSERT( is_authorized_asset( d, *fee_paying_account, *_asset ) );
|
FC_ASSERT( is_authorized_asset( d, *fee_paying_account, *_asset ) );
|
||||||
|
|
||||||
const chain_parameters& current_params = d.get_global_properties().parameters;
|
_current_params = &d.get_global_properties().parameters;
|
||||||
|
|
||||||
// are their odds valid
|
// are their odds valid
|
||||||
FC_ASSERT( op.backer_multiplier >= current_params.min_bet_multiplier &&
|
FC_ASSERT( op.backer_multiplier >= _current_params->min_bet_multiplier &&
|
||||||
op.backer_multiplier <= current_params.max_bet_multiplier,
|
op.backer_multiplier <= _current_params->max_bet_multiplier,
|
||||||
"Bet odds are outside the blockchain's limits" );
|
"Bet odds are outside the blockchain's limits" );
|
||||||
if (!current_params.permitted_betting_odds_increments.empty())
|
if (!_current_params->permitted_betting_odds_increments.empty())
|
||||||
{
|
{
|
||||||
bet_multiplier_type allowed_increment;
|
bet_multiplier_type allowed_increment;
|
||||||
const auto iter = current_params.permitted_betting_odds_increments.upper_bound(op.backer_multiplier);
|
const auto iter = _current_params->permitted_betting_odds_increments.upper_bound(op.backer_multiplier);
|
||||||
if (iter == current_params.permitted_betting_odds_increments.end())
|
if (iter == _current_params->permitted_betting_odds_increments.end())
|
||||||
allowed_increment = std::prev(current_params.permitted_betting_odds_increments.end())->second;
|
allowed_increment = std::prev(_current_params->permitted_betting_odds_increments.end())->second;
|
||||||
else
|
else
|
||||||
allowed_increment = iter->second;
|
allowed_increment = iter->second;
|
||||||
FC_ASSERT(op.backer_multiplier % allowed_increment == 0, "Bet odds must be a multiple of ${allowed_increment}", ("allowed_increment", allowed_increment));
|
FC_ASSERT(op.backer_multiplier % allowed_increment == 0, "Bet odds must be a multiple of ${allowed_increment}", ("allowed_increment", allowed_increment));
|
||||||
|
|
@ -306,20 +306,22 @@ object_id_type bet_place_evaluator::do_apply(const bet_place_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
database& d = db();
|
database& d = db();
|
||||||
const bet_object& new_bet =
|
const bet_object& new_bet =
|
||||||
d.create<bet_object>( [&]( bet_object& bet_obj ) {
|
d.create<bet_object>([&](bet_object& bet_obj) {
|
||||||
bet_obj.bettor_id = op.bettor_id;
|
bet_obj.bettor_id = op.bettor_id;
|
||||||
bet_obj.betting_market_id = op.betting_market_id;
|
bet_obj.betting_market_id = op.betting_market_id;
|
||||||
bet_obj.amount_to_bet = op.amount_to_bet;
|
bet_obj.amount_to_bet = op.amount_to_bet;
|
||||||
bet_obj.backer_multiplier = op.backer_multiplier;
|
bet_obj.backer_multiplier = op.backer_multiplier;
|
||||||
bet_obj.back_or_lay = op.back_or_lay;
|
bet_obj.back_or_lay = op.back_or_lay;
|
||||||
});
|
if (_betting_market_group->delay_bets)
|
||||||
|
bet_obj.end_of_delay = d.head_block_time() + _current_params->live_betting_delay_time;
|
||||||
|
});
|
||||||
|
|
||||||
bet_id_type new_bet_id = new_bet.id; // save the bet id here, new_bet may be deleted during place_bet()
|
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);
|
d.adjust_balance(fee_paying_account->id, -op.amount_to_bet);
|
||||||
|
|
||||||
//bool bet_matched =
|
if (!_betting_market_group->delay_bets || _current_params->live_betting_delay_time <= 0)
|
||||||
d.place_bet(new_bet);
|
d.place_bet(new_bet);
|
||||||
|
|
||||||
return new_bet_id;
|
return new_bet_id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
@ -341,9 +343,9 @@ void_result bet_cancel_evaluator::do_apply(const bet_cancel_operation& op)
|
||||||
|
|
||||||
void_result betting_market_group_resolve_evaluator::do_evaluate(const betting_market_group_resolve_operation& op)
|
void_result betting_market_group_resolve_evaluator::do_evaluate(const betting_market_group_resolve_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const database& d = db();
|
database& d = db();
|
||||||
_betting_market_group = &op.betting_market_group_id(d);
|
_betting_market_group = &op.betting_market_group_id(d);
|
||||||
db().validate_betting_market_group_resolutions(*_betting_market_group, op.resolutions);
|
d.validate_betting_market_group_resolutions(*_betting_market_group, op.resolutions);
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
|
@ -355,8 +357,7 @@ void_result betting_market_group_resolve_evaluator::do_apply(const betting_marke
|
||||||
|
|
||||||
void_result betting_market_group_cancel_unmatched_bets_evaluator::do_evaluate(const betting_market_group_cancel_unmatched_bets_operation& op)
|
void_result betting_market_group_cancel_unmatched_bets_evaluator::do_evaluate(const betting_market_group_cancel_unmatched_bets_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
const database& d = db();
|
_betting_market_group = &op.betting_market_group_id(db());
|
||||||
_betting_market_group = &op.betting_market_group_id(d);
|
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ void database::cancel_bet( const bet_object& bet, bool create_virtual_op )
|
||||||
void database::cancel_all_unmatched_bets_on_betting_market(const betting_market_object& betting_market)
|
void database::cancel_all_unmatched_bets_on_betting_market(const betting_market_object& betting_market)
|
||||||
{
|
{
|
||||||
const auto& bet_odds_idx = get_index_type<bet_object_index>().indices().get<by_odds>();
|
const auto& bet_odds_idx = get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||||
|
|
||||||
|
// first, cancel all bets on the active books
|
||||||
auto book_itr = bet_odds_idx.lower_bound(std::make_tuple(betting_market.id));
|
auto book_itr = bet_odds_idx.lower_bound(std::make_tuple(betting_market.id));
|
||||||
auto book_end = bet_odds_idx.upper_bound(std::make_tuple(betting_market.id));
|
auto book_end = bet_odds_idx.upper_bound(std::make_tuple(betting_market.id));
|
||||||
while (book_itr != book_end)
|
while (book_itr != book_end)
|
||||||
|
|
@ -34,6 +36,18 @@ void database::cancel_all_unmatched_bets_on_betting_market(const betting_market_
|
||||||
++book_itr;
|
++book_itr;
|
||||||
cancel_bet(*old_book_itr, true);
|
cancel_bet(*old_book_itr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// then, cancel any delayed bets on that market. We don't have an index for
|
||||||
|
// that, so walk through all delayed bets
|
||||||
|
book_itr = bet_odds_idx.begin();
|
||||||
|
while (book_itr != bet_odds_idx.end() &&
|
||||||
|
book_itr->end_of_delay)
|
||||||
|
{
|
||||||
|
auto old_book_itr = book_itr;
|
||||||
|
++book_itr;
|
||||||
|
if (old_book_itr->betting_market_id == betting_market.id)
|
||||||
|
cancel_bet(*old_book_itr, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::cancel_all_betting_markets_for_event(const event_object& event_obj)
|
void database::cancel_all_betting_markets_for_event(const event_object& event_obj)
|
||||||
|
|
|
||||||
|
|
@ -540,6 +540,7 @@ void database::_apply_block( const signed_block& next_block )
|
||||||
perform_chain_maintenance(next_block, global_props);
|
perform_chain_maintenance(next_block, global_props);
|
||||||
|
|
||||||
create_block_summary(next_block);
|
create_block_summary(next_block);
|
||||||
|
place_delayed_bets(); // must happen after update_global_dynamic_data() updates the time
|
||||||
clear_expired_transactions();
|
clear_expired_transactions();
|
||||||
clear_expired_proposals();
|
clear_expired_proposals();
|
||||||
clear_expired_orders();
|
clear_expired_orders();
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,53 @@ void database::clear_expired_transactions()
|
||||||
transaction_idx.remove(*dedupe_index.begin());
|
transaction_idx.remove(*dedupe_index.begin());
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
} FC_CAPTURE_AND_RETHROW() }
|
||||||
|
|
||||||
|
void database::place_delayed_bets()
|
||||||
|
{ try {
|
||||||
|
// If any bets have been placed during live betting where bets are delayed for a few seconds, see if there are
|
||||||
|
// any bets whose delays have expired.
|
||||||
|
|
||||||
|
// Delayed bets are sorted to the beginning of the order book, so if there are any bets that need placing,
|
||||||
|
// they're right at the front of the book
|
||||||
|
const auto& bet_odds_idx = get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||||
|
auto iter = bet_odds_idx.begin();
|
||||||
|
|
||||||
|
// we use an awkward looping mechanism here because there's a case where we are processing the
|
||||||
|
// last delayed bet before the "real" order book starts and `iter` was pointing at the first
|
||||||
|
// real order. The place_bet() call can cause the that real order to be deleted, so we need
|
||||||
|
// to decide whether this is the last delayed bet before `place_bet` is called.
|
||||||
|
bool last = iter == bet_odds_idx.end() ||
|
||||||
|
!iter->end_of_delay ||
|
||||||
|
*iter->end_of_delay > head_block_time();
|
||||||
|
while (!last)
|
||||||
|
{
|
||||||
|
const bet_object& bet_to_place = *iter;
|
||||||
|
++iter;
|
||||||
|
|
||||||
|
last = iter == bet_odds_idx.end() ||
|
||||||
|
!iter->end_of_delay ||
|
||||||
|
*iter->end_of_delay > head_block_time();
|
||||||
|
|
||||||
|
// it's possible that the betting market was active when the bet was placed,
|
||||||
|
// but has been frozen before the delay expired. If that's the case here,
|
||||||
|
// don't try to match the bet.
|
||||||
|
// Since this check happens every block, this could impact performance if a
|
||||||
|
// market with many delayed bets is frozen for a long time.
|
||||||
|
// Our current understanding is that the witnesses will typically cancel all unmatched
|
||||||
|
// bets on frozen markets to avoid this.
|
||||||
|
const betting_market_object& betting_market = bet_to_place.betting_market_id(*this);
|
||||||
|
const betting_market_group_object& betting_market_group = betting_market.group_id(*this);
|
||||||
|
if (!betting_market_group.frozen)
|
||||||
|
{
|
||||||
|
modify(bet_to_place, [](bet_object& bet_obj) {
|
||||||
|
// clear the end_of_delay, which will re-sort the bet into its place in the book
|
||||||
|
bet_obj.end_of_delay.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
place_bet(bet_to_place);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} FC_CAPTURE_AND_RETHROW() }
|
||||||
|
|
||||||
void database::clear_expired_proposals()
|
void database::clear_expired_proposals()
|
||||||
{
|
{
|
||||||
const auto& proposal_expiration_index = get_index_type<proposal_index>().indices().get<by_expiration>();
|
const auto& proposal_expiration_index = get_index_type<proposal_index>().indices().get<by_expiration>();
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void_result do_evaluate( const betting_market_rules_update_operation& o );
|
void_result do_evaluate( const betting_market_rules_update_operation& o );
|
||||||
void_result do_apply( const betting_market_rules_update_operation& o );
|
void_result do_apply( const betting_market_rules_update_operation& o );
|
||||||
|
private:
|
||||||
|
const betting_market_rules_object* _rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
class betting_market_group_create_evaluator : public evaluator<betting_market_group_create_evaluator>
|
class betting_market_group_create_evaluator : public evaluator<betting_market_group_create_evaluator>
|
||||||
|
|
@ -52,11 +54,11 @@ namespace graphene { namespace chain {
|
||||||
public:
|
public:
|
||||||
typedef betting_market_group_create_operation operation_type;
|
typedef betting_market_group_create_operation operation_type;
|
||||||
|
|
||||||
void_result do_evaluate( const betting_market_group_create_operation& o );
|
void_result do_evaluate(const betting_market_group_create_operation& o);
|
||||||
object_id_type do_apply( const betting_market_group_create_operation& o );
|
object_id_type do_apply(const betting_market_group_create_operation& o);
|
||||||
private:
|
private:
|
||||||
event_id_type event_id;
|
event_id_type _event_id;
|
||||||
betting_market_rules_id_type rules_id;
|
betting_market_rules_id_type _rules_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class betting_market_group_update_evaluator : public evaluator<betting_market_group_update_evaluator>
|
class betting_market_group_update_evaluator : public evaluator<betting_market_group_update_evaluator>
|
||||||
|
|
@ -64,11 +66,11 @@ namespace graphene { namespace chain {
|
||||||
public:
|
public:
|
||||||
typedef betting_market_group_update_operation operation_type;
|
typedef betting_market_group_update_operation operation_type;
|
||||||
|
|
||||||
void_result do_evaluate( const betting_market_group_update_operation& o );
|
void_result do_evaluate(const betting_market_group_update_operation& o);
|
||||||
void_result do_apply( const betting_market_group_update_operation& o );
|
void_result do_apply(const betting_market_group_update_operation& o);
|
||||||
private:
|
private:
|
||||||
event_id_type event_id;
|
betting_market_rules_id_type _rules_id;
|
||||||
betting_market_rules_id_type rules_id;
|
const betting_market_group_object* _betting_market_group;
|
||||||
};
|
};
|
||||||
|
|
||||||
class betting_market_create_evaluator : public evaluator<betting_market_create_evaluator>
|
class betting_market_create_evaluator : public evaluator<betting_market_create_evaluator>
|
||||||
|
|
@ -79,7 +81,7 @@ namespace graphene { namespace chain {
|
||||||
void_result do_evaluate( const betting_market_create_operation& o );
|
void_result do_evaluate( const betting_market_create_operation& o );
|
||||||
object_id_type do_apply( const betting_market_create_operation& o );
|
object_id_type do_apply( const betting_market_create_operation& o );
|
||||||
private:
|
private:
|
||||||
betting_market_group_id_type group_id;
|
betting_market_group_id_type _group_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class betting_market_update_evaluator : public evaluator<betting_market_update_evaluator>
|
class betting_market_update_evaluator : public evaluator<betting_market_update_evaluator>
|
||||||
|
|
@ -90,7 +92,8 @@ namespace graphene { namespace chain {
|
||||||
void_result do_evaluate( const betting_market_update_operation& o );
|
void_result do_evaluate( const betting_market_update_operation& o );
|
||||||
void_result do_apply( const betting_market_update_operation& o );
|
void_result do_apply( const betting_market_update_operation& o );
|
||||||
private:
|
private:
|
||||||
betting_market_group_id_type group_id;
|
const betting_market_object* _betting_market;
|
||||||
|
betting_market_group_id_type _group_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class bet_place_evaluator : public evaluator<bet_place_evaluator>
|
class bet_place_evaluator : public evaluator<bet_place_evaluator>
|
||||||
|
|
@ -103,6 +106,7 @@ namespace graphene { namespace chain {
|
||||||
private:
|
private:
|
||||||
const betting_market_group_object* _betting_market_group;
|
const betting_market_group_object* _betting_market_group;
|
||||||
const betting_market_object* _betting_market;
|
const betting_market_object* _betting_market;
|
||||||
|
const chain_parameters* _current_params;
|
||||||
const asset_object* _asset;
|
const asset_object* _asset;
|
||||||
share_type _stake_plus_fees;
|
share_type _stake_plus_fees;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ class bet_object : public graphene::db::abstract_object< bet_object >
|
||||||
|
|
||||||
bet_type back_or_lay;
|
bet_type back_or_lay;
|
||||||
|
|
||||||
|
fc::optional<fc::time_point_sec> end_of_delay;
|
||||||
|
|
||||||
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);
|
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);
|
||||||
|
|
||||||
// returns the amount of a bet that completely matches this bet
|
// returns the amount of a bet that completely matches this bet
|
||||||
|
|
@ -161,78 +163,121 @@ typedef generic_index<betting_market_object, betting_market_object_multi_index_t
|
||||||
struct compare_bet_by_odds {
|
struct compare_bet_by_odds {
|
||||||
bool operator()(const bet_object& lhs, const bet_object& rhs) const
|
bool operator()(const bet_object& lhs, const bet_object& rhs) const
|
||||||
{
|
{
|
||||||
return compare(lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier, lhs.id,
|
return compare(lhs.end_of_delay, lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier, lhs.id,
|
||||||
rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier, rhs.id);
|
rhs.end_of_delay, rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier, rhs.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0>
|
template<typename T0>
|
||||||
bool operator() (const std::tuple<T0>& lhs, const bet_object& rhs) const
|
bool operator() (const std::tuple<T0>& lhs, const bet_object& rhs) const
|
||||||
{
|
{
|
||||||
return compare(std::get<0>(lhs), rhs.betting_market_id);
|
return compare(fc::optional<time_point_sec>(), std::get<0>(lhs), rhs.end_of_delay, rhs.betting_market_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0>
|
template<typename T0>
|
||||||
bool operator() (const bet_object& lhs, const std::tuple<T0>& rhs) const
|
bool operator() (const bet_object& lhs, const std::tuple<T0>& rhs) const
|
||||||
{
|
{
|
||||||
return compare(lhs.betting_market_id, std::get<0>(rhs));
|
return compare(lhs.end_of_delay, lhs.betting_market_id, fc::optional<time_point_sec>(), std::get<0>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1>
|
template<typename T0, typename T1>
|
||||||
bool operator() (const std::tuple<T0, T1>& lhs, const bet_object& rhs) const
|
bool operator() (const std::tuple<T0, T1>& lhs, const bet_object& rhs) const
|
||||||
{
|
{
|
||||||
return compare(std::get<0>(lhs), std::get<1>(lhs), rhs.betting_market_id, rhs.back_or_lay);
|
return compare(fc::optional<fc::time_point_sec>(), std::get<0>(lhs), std::get<1>(lhs), rhs.end_of_delay, rhs.betting_market_id, rhs.back_or_lay);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1>
|
template<typename T0, typename T1>
|
||||||
bool operator() (const bet_object& lhs, const std::tuple<T0, T1>& rhs) const
|
bool operator() (const bet_object& lhs, const std::tuple<T0, T1>& rhs) const
|
||||||
{
|
{
|
||||||
return compare(lhs.betting_market_id, lhs.back_or_lay, std::get<0>(rhs), std::get<1>(rhs));
|
return compare(lhs.end_of_delay, lhs.betting_market_id, lhs.back_or_lay, fc::optional<time_point_sec>(), std::get<0>(rhs), std::get<1>(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1, typename T2>
|
template<typename T0, typename T1, typename T2>
|
||||||
bool operator() (const std::tuple<T0, T1, T2>& lhs, const bet_object& rhs) const
|
bool operator() (const std::tuple<T0, T1, T2>& lhs, const bet_object& rhs) const
|
||||||
{
|
{
|
||||||
return compare(std::get<0>(lhs), std::get<1>(lhs), std::get<2>(lhs),
|
return compare(fc::optional<time_point_sec>(), std::get<0>(lhs), std::get<1>(lhs), std::get<2>(lhs),
|
||||||
rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier);
|
rhs.end_of_delay, rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1, typename T2>
|
template<typename T0, typename T1, typename T2>
|
||||||
bool operator() (const bet_object& lhs, const std::tuple<T0, T1, T2>& rhs) const
|
bool operator() (const bet_object& lhs, const std::tuple<T0, T1, T2>& rhs) const
|
||||||
{
|
{
|
||||||
return compare(lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier,
|
return compare(lhs.end_of_delay, lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier,
|
||||||
std::get<0>(rhs), std::get<1>(rhs), std::get<2>(rhs));
|
fc::optional<time_point_sec>(), std::get<0>(rhs), std::get<1>(rhs), std::get<2>(rhs));
|
||||||
}
|
}
|
||||||
template<typename T0, typename T1, typename T2, typename T3>
|
template<typename T0, typename T1, typename T2, typename T3>
|
||||||
bool operator() (const std::tuple<T0, T1, T2, T3>& lhs, const bet_object& rhs) const
|
bool operator() (const std::tuple<T0, T1, T2, T3>& lhs, const bet_object& rhs) const
|
||||||
{
|
{
|
||||||
return compare(std::get<0>(lhs), std::get<1>(lhs), std::get<2>(lhs), std::get<3>(lhs),
|
return compare(fc::optional<time_point_sec>(), std::get<0>(lhs), std::get<1>(lhs), std::get<2>(lhs), std::get<3>(lhs),
|
||||||
rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier, rhs.id);
|
rhs.end_of_delay, rhs.betting_market_id, rhs.back_or_lay, rhs.backer_multiplier, rhs.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1, typename T2, typename T3>
|
template<typename T0, typename T1, typename T2, typename T3>
|
||||||
bool operator() (const bet_object& lhs, const std::tuple<T0, T1, T2, T3>& rhs) const
|
bool operator() (const bet_object& lhs, const std::tuple<T0, T1, T2, T3>& rhs) const
|
||||||
{
|
{
|
||||||
return compare(lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier, lhs.id,
|
return compare(lhs.end_of_delay, lhs.betting_market_id, lhs.back_or_lay, lhs.backer_multiplier, lhs.id,
|
||||||
std::get<0>(rhs), std::get<1>(rhs), std::get<2>(rhs), std::get<3>(rhs));
|
fc::optional<time_point_sec>(), std::get<0>(rhs), std::get<1>(rhs), std::get<2>(rhs), std::get<3>(rhs));
|
||||||
}
|
}
|
||||||
bool compare(const betting_market_id_type& lhs_betting_market_id, const betting_market_id_type& rhs_betting_market_id) const
|
bool compare(const fc::optional<fc::time_point_sec>& lhs_end_of_delay,
|
||||||
|
const betting_market_id_type& lhs_betting_market_id,
|
||||||
|
const fc::optional<fc::time_point_sec>& rhs_end_of_delay,
|
||||||
|
const betting_market_id_type& rhs_betting_market_id) const
|
||||||
{
|
{
|
||||||
|
// if either bet is delayed, sort the delayed bet to the
|
||||||
|
// front. If both are delayed, the delay expiring soonest
|
||||||
|
// comes first.
|
||||||
|
if (lhs_end_of_delay || rhs_end_of_delay)
|
||||||
|
{
|
||||||
|
if (!rhs_end_of_delay)
|
||||||
|
return true;
|
||||||
|
if (!lhs_end_of_delay)
|
||||||
|
return false;
|
||||||
|
return *lhs_end_of_delay < *rhs_end_of_delay;
|
||||||
|
}
|
||||||
|
|
||||||
return lhs_betting_market_id < rhs_betting_market_id;
|
return lhs_betting_market_id < rhs_betting_market_id;
|
||||||
}
|
}
|
||||||
bool compare(const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
bool compare(const fc::optional<fc::time_point_sec>& lhs_end_of_delay,
|
||||||
|
const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
||||||
|
const fc::optional<fc::time_point_sec>& rhs_end_of_delay,
|
||||||
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type) const
|
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type) const
|
||||||
{
|
{
|
||||||
|
// if either bet is delayed, sort the delayed bet to the
|
||||||
|
// front. If both are delayed, the delay expiring soonest
|
||||||
|
// comes first.
|
||||||
|
if (lhs_end_of_delay || rhs_end_of_delay)
|
||||||
|
{
|
||||||
|
if (!rhs_end_of_delay)
|
||||||
|
return true;
|
||||||
|
if (!lhs_end_of_delay)
|
||||||
|
return false;
|
||||||
|
return *lhs_end_of_delay < *rhs_end_of_delay;
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs_betting_market_id < rhs_betting_market_id)
|
if (lhs_betting_market_id < rhs_betting_market_id)
|
||||||
return true;
|
return true;
|
||||||
if (lhs_betting_market_id > rhs_betting_market_id)
|
if (lhs_betting_market_id > rhs_betting_market_id)
|
||||||
return false;
|
return false;
|
||||||
return lhs_bet_type < rhs_bet_type;
|
return lhs_bet_type < rhs_bet_type;
|
||||||
}
|
}
|
||||||
bool compare(const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
bool compare(const fc::optional<fc::time_point_sec>& lhs_end_of_delay,
|
||||||
|
const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
||||||
bet_multiplier_type lhs_backer_multiplier,
|
bet_multiplier_type lhs_backer_multiplier,
|
||||||
|
const fc::optional<fc::time_point_sec>& rhs_end_of_delay,
|
||||||
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type,
|
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type,
|
||||||
bet_multiplier_type rhs_backer_multiplier) const
|
bet_multiplier_type rhs_backer_multiplier) const
|
||||||
{
|
{
|
||||||
|
// if either bet is delayed, sort the delayed bet to the
|
||||||
|
// front. If both are delayed, the delay expiring soonest
|
||||||
|
// comes first.
|
||||||
|
if (lhs_end_of_delay || rhs_end_of_delay)
|
||||||
|
{
|
||||||
|
if (!rhs_end_of_delay)
|
||||||
|
return true;
|
||||||
|
if (!lhs_end_of_delay)
|
||||||
|
return false;
|
||||||
|
return *lhs_end_of_delay < *rhs_end_of_delay;
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs_betting_market_id < rhs_betting_market_id)
|
if (lhs_betting_market_id < rhs_betting_market_id)
|
||||||
return true;
|
return true;
|
||||||
if (lhs_betting_market_id > rhs_betting_market_id)
|
if (lhs_betting_market_id > rhs_betting_market_id)
|
||||||
|
|
@ -246,11 +291,33 @@ struct compare_bet_by_odds {
|
||||||
else
|
else
|
||||||
return lhs_backer_multiplier > rhs_backer_multiplier;
|
return lhs_backer_multiplier > rhs_backer_multiplier;
|
||||||
}
|
}
|
||||||
bool compare(const betting_market_id_type& lhs_betting_market_id, bet_type lhs_bet_type,
|
bool compare(const fc::optional<fc::time_point_sec>& lhs_end_of_delay,
|
||||||
|
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,
|
bet_multiplier_type lhs_backer_multiplier, const bet_id_type& lhs_bet_id,
|
||||||
|
const fc::optional<fc::time_point_sec>& rhs_end_of_delay,
|
||||||
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type,
|
const betting_market_id_type& rhs_betting_market_id, bet_type rhs_bet_type,
|
||||||
bet_multiplier_type rhs_backer_multiplier, const bet_id_type& rhs_bet_id) const
|
bet_multiplier_type rhs_backer_multiplier, const bet_id_type& rhs_bet_id) const
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// if either bet is delayed, sort the delayed bet to the
|
||||||
|
// front. If both are delayed, the delay expiring soonest
|
||||||
|
// comes first.
|
||||||
|
if (lhs_end_of_delay || rhs_end_of_delay)
|
||||||
|
{
|
||||||
|
if (!rhs_end_of_delay)
|
||||||
|
return true;
|
||||||
|
if (!lhs_end_of_delay)
|
||||||
|
return false;
|
||||||
|
if (*lhs_end_of_delay < *rhs_end_of_delay)
|
||||||
|
return true;
|
||||||
|
if (*lhs_end_of_delay > *rhs_end_of_delay)
|
||||||
|
return false;
|
||||||
|
// if both bets have the same delay, prefer the one
|
||||||
|
// that was placed first (lowest id)
|
||||||
|
return lhs_bet_id < rhs_bet_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if neither bet was delayed
|
||||||
if (lhs_betting_market_id < rhs_betting_market_id)
|
if (lhs_betting_market_id < rhs_betting_market_id)
|
||||||
return true;
|
return true;
|
||||||
if (lhs_betting_market_id > rhs_betting_market_id)
|
if (lhs_betting_market_id > rhs_betting_market_id)
|
||||||
|
|
@ -451,6 +518,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_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)(delay_bets)(total_matched_bets_amount) )
|
FC_REFLECT_DERIVED( graphene::chain::betting_market_group_object, (graphene::db::object), (description)(event_id)(rules_id)(asset_id)(frozen)(delay_bets)(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::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)(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)(end_of_delay) )
|
||||||
|
|
||||||
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) )
|
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) )
|
||||||
|
|
|
||||||
|
|
@ -464,6 +464,7 @@ namespace graphene { namespace chain {
|
||||||
void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block);
|
void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block);
|
||||||
void update_last_irreversible_block();
|
void update_last_irreversible_block();
|
||||||
void clear_expired_transactions();
|
void clear_expired_transactions();
|
||||||
|
void place_delayed_bets();
|
||||||
void clear_expired_proposals();
|
void clear_expired_proposals();
|
||||||
void clear_expired_orders();
|
void clear_expired_orders();
|
||||||
void update_expired_feeds();
|
void update_expired_feeds();
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,6 @@ struct betting_market_group_update_operation : public base_operation
|
||||||
|
|
||||||
optional<internationalized_string_type> new_description;
|
optional<internationalized_string_type> new_description;
|
||||||
|
|
||||||
optional<object_id_type> new_event_id;
|
|
||||||
|
|
||||||
optional<object_id_type> new_rules_id;
|
optional<object_id_type> new_rules_id;
|
||||||
|
|
||||||
optional<bool> freeze;
|
optional<bool> freeze;
|
||||||
|
|
@ -388,7 +386,7 @@ FC_REFLECT( graphene::chain::betting_market_group_create_operation,
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::betting_market_group_update_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::betting_market_group_update_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::betting_market_group_update_operation,
|
FC_REFLECT( graphene::chain::betting_market_group_update_operation,
|
||||||
(fee)(betting_market_group_id)(new_description)(new_event_id)(new_rules_id)(freeze)(delay_bets)(extensions) )
|
(fee)(betting_market_group_id)(new_description)(new_rules_id)(freeze)(delay_bets)(extensions) )
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::betting_market_create_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::betting_market_create_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::betting_market_create_operation,
|
FC_REFLECT( graphene::chain::betting_market_create_operation,
|
||||||
|
|
|
||||||
|
|
@ -1658,7 +1658,6 @@ class wallet_api
|
||||||
fc::time_point_sec expiration_time,
|
fc::time_point_sec expiration_time,
|
||||||
betting_market_group_id_type betting_market_group_id,
|
betting_market_group_id_type betting_market_group_id,
|
||||||
fc::optional<internationalized_string_type> description,
|
fc::optional<internationalized_string_type> description,
|
||||||
fc::optional<object_id_type> event_id,
|
|
||||||
fc::optional<object_id_type> rules_id,
|
fc::optional<object_id_type> rules_id,
|
||||||
fc::optional<bool> freeze,
|
fc::optional<bool> freeze,
|
||||||
bool broadcast = false);
|
bool broadcast = false);
|
||||||
|
|
|
||||||
|
|
@ -5308,7 +5308,6 @@ signed_transaction wallet_api::propose_update_betting_market_group(
|
||||||
fc::time_point_sec expiration_time,
|
fc::time_point_sec expiration_time,
|
||||||
betting_market_group_id_type betting_market_group_id,
|
betting_market_group_id_type betting_market_group_id,
|
||||||
fc::optional<internationalized_string_type> description,
|
fc::optional<internationalized_string_type> description,
|
||||||
fc::optional<object_id_type> event_id,
|
|
||||||
fc::optional<object_id_type> rules_id,
|
fc::optional<object_id_type> rules_id,
|
||||||
fc::optional<bool> freeze,
|
fc::optional<bool> freeze,
|
||||||
bool broadcast /*= false*/)
|
bool broadcast /*= false*/)
|
||||||
|
|
@ -5319,7 +5318,6 @@ signed_transaction wallet_api::propose_update_betting_market_group(
|
||||||
betting_market_group_update_operation betting_market_group_update_op;
|
betting_market_group_update_operation betting_market_group_update_op;
|
||||||
betting_market_group_update_op.betting_market_group_id = betting_market_group_id;
|
betting_market_group_update_op.betting_market_group_id = betting_market_group_id;
|
||||||
betting_market_group_update_op.new_description = description;
|
betting_market_group_update_op.new_description = description;
|
||||||
betting_market_group_update_op.new_event_id = event_id;
|
|
||||||
betting_market_group_update_op.new_rules_id = rules_id;
|
betting_market_group_update_op.new_rules_id = rules_id;
|
||||||
betting_market_group_update_op.freeze = freeze;
|
betting_market_group_update_op.freeze = freeze;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,92 @@ BOOST_AUTO_TEST_CASE(persistent_objects_test)
|
||||||
FC_LOG_AND_RETHROW()
|
FC_LOG_AND_RETHROW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(delayed_bets_test) // test live betting
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& bet_odds_idx = db.get_index_type<bet_object_index>().indices().get<by_odds>();
|
||||||
|
|
||||||
|
ACTORS( (alice)(bob) );
|
||||||
|
|
||||||
|
{
|
||||||
|
// we're generating blocks, and the hacky way we keep references to the objects generated
|
||||||
|
// in this macro doesn't work, so do this in an anonymous scope to prevent us from using
|
||||||
|
// the variables it declares outside later in the function
|
||||||
|
|
||||||
|
CREATE_ICE_HOCKEY_BETTING_MARKET();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_blocks(1);
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(db.get_index_type<betting_market_group_object_index>().indices().get<by_id>().size(), 1);
|
||||||
|
const betting_market_group_object& caps_vs_blackhawks_moneyline_betting_market = *db.get_index_type<betting_market_group_object_index>().indices().get<by_id>().begin();
|
||||||
|
BOOST_REQUIRE_EQUAL(db.get_index_type<betting_market_object_index>().indices().get<by_id>().size(), 2);
|
||||||
|
const betting_market_object& capitals_win_market = *db.get_index_type<betting_market_object_index>().indices().get<by_id>().begin();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
update_betting_market_group(caps_vs_blackhawks_moneyline_betting_market.id,
|
||||||
|
fc::optional<internationalized_string_type>(),
|
||||||
|
fc::optional<object_id_type>(),
|
||||||
|
fc::optional<bool>(),
|
||||||
|
true);
|
||||||
|
generate_blocks(1);
|
||||||
|
|
||||||
|
transfer(account_id_type(), alice_id, asset(10000000));
|
||||||
|
transfer(account_id_type(), bob_id, asset(10000000));
|
||||||
|
share_type alice_expected_balance = 10000000;
|
||||||
|
share_type bob_expected_balance = 10000000;
|
||||||
|
BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value);
|
||||||
|
BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value);
|
||||||
|
|
||||||
|
generate_blocks(1);
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("Testing basic delayed bet mechanics");
|
||||||
|
// alice backs 100 at odds 2
|
||||||
|
BOOST_TEST_MESSAGE("Alice places a back bet of 100 at odds 2.0");
|
||||||
|
bet_id_type delayed_back_bet = place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||||
|
generate_blocks(1);
|
||||||
|
|
||||||
|
// verify the bet hasn't been placed in the active book
|
||||||
|
auto first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
BOOST_CHECK(first_bet_in_market == bet_odds_idx.end());
|
||||||
|
|
||||||
|
// after 3 blocks, the delay should have expired and it will be promoted to the active book
|
||||||
|
generate_blocks(2);
|
||||||
|
first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
auto last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
BOOST_CHECK(first_bet_in_market != bet_odds_idx.end());
|
||||||
|
BOOST_CHECK(std::distance(first_bet_in_market, last_bet_in_market) == 1);
|
||||||
|
|
||||||
|
// bob lays 100 at odds 2 to match alice's bet currently on the books
|
||||||
|
BOOST_TEST_MESSAGE("Bob places a lay bet of 100 at odds 2.0");
|
||||||
|
bet_id_type delayed_lay_bet = place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||||
|
generate_blocks(1);
|
||||||
|
|
||||||
|
// bob's bet will still be delayed, so the active order book will only contain alice's bet
|
||||||
|
first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
BOOST_CHECK(std::distance(first_bet_in_market, last_bet_in_market) == 1);
|
||||||
|
|
||||||
|
// once bob's bet's delay has expired, the two bets will annihilate each other, leaving
|
||||||
|
// an empty order book
|
||||||
|
generate_blocks(2);
|
||||||
|
BOOST_CHECK(bet_odds_idx.empty());
|
||||||
|
|
||||||
|
// now test that when we cancel all bets on a market, delayed bets get canceled too
|
||||||
|
BOOST_TEST_MESSAGE("Alice places a back bet of 100 at odds 2.0");
|
||||||
|
delayed_back_bet = place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||||
|
generate_blocks(1);
|
||||||
|
first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id));
|
||||||
|
BOOST_CHECK(!bet_odds_idx.empty());
|
||||||
|
BOOST_CHECK(first_bet_in_market == bet_odds_idx.end());
|
||||||
|
BOOST_TEST_MESSAGE("Cancel all bets");
|
||||||
|
cancel_unmatched_bets(caps_vs_blackhawks_moneyline_betting_market.id);
|
||||||
|
BOOST_CHECK(bet_odds_idx.empty());
|
||||||
|
}
|
||||||
|
FC_LOG_AND_RETHROW()
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( chained_market_create_test )
|
BOOST_AUTO_TEST_CASE( chained_market_create_test )
|
||||||
{
|
{
|
||||||
|
|
@ -785,10 +871,10 @@ BOOST_AUTO_TEST_CASE(betting_market_group_update_test)
|
||||||
fc::optional<object_id_type> new_rule = new_betting_market_rules.id;
|
fc::optional<object_id_type> new_rule = new_betting_market_rules.id;
|
||||||
fc::optional<bool> empty_bool;
|
fc::optional<bool> empty_bool;
|
||||||
|
|
||||||
update_betting_market_group(moneyline_betting_markets.id, new_desc, empty_object_id, empty_object_id, empty_bool, empty_bool);
|
update_betting_market_group(moneyline_betting_markets.id, new_desc, empty_object_id, empty_bool, empty_bool);
|
||||||
update_betting_market_group(moneyline_betting_markets.id, dempty, new_event, empty_object_id, empty_bool, empty_bool);
|
update_betting_market_group(moneyline_betting_markets.id, dempty, empty_object_id, empty_bool, empty_bool);
|
||||||
update_betting_market_group(moneyline_betting_markets.id, dempty, empty_object_id, new_rule, empty_bool, empty_bool);
|
update_betting_market_group(moneyline_betting_markets.id, dempty, new_rule, empty_bool, empty_bool);
|
||||||
update_betting_market_group(moneyline_betting_markets.id, new_desc, new_event, new_rule, empty_bool, empty_bool);
|
update_betting_market_group(moneyline_betting_markets.id, new_desc, new_rule, empty_bool, empty_bool);
|
||||||
|
|
||||||
transfer(account_id_type(), bob_id, asset(10000000));
|
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);
|
place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||||
|
|
@ -1044,7 +1130,7 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test )
|
||||||
fc::optional<bool> empty_bool;
|
fc::optional<bool> empty_bool;
|
||||||
fc::optional<bool> true_bool = true;
|
fc::optional<bool> true_bool = true;
|
||||||
update_betting_market_group(moneyline_cilic_vs_federer_id, empty_str,
|
update_betting_market_group(moneyline_cilic_vs_federer_id, empty_str,
|
||||||
empty_obj, empty_obj,
|
empty_obj,
|
||||||
empty_bool, true_bool);
|
empty_bool, true_bool);
|
||||||
|
|
||||||
place_bet(alice_id, cilic_wins_final_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
place_bet(alice_id, cilic_wins_final_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION);
|
||||||
|
|
|
||||||
|
|
@ -1357,21 +1357,18 @@ const betting_market_group_object& database_fixture::create_betting_market_group
|
||||||
|
|
||||||
void database_fixture::update_betting_market_group(betting_market_group_id_type betting_market_group_id,
|
void database_fixture::update_betting_market_group(betting_market_group_id_type betting_market_group_id,
|
||||||
fc::optional<internationalized_string_type> description,
|
fc::optional<internationalized_string_type> description,
|
||||||
fc::optional<object_id_type> event_id,
|
|
||||||
fc::optional<object_id_type> rules_id,
|
fc::optional<object_id_type> rules_id,
|
||||||
fc::optional<bool> freeze,
|
fc::optional<bool> freeze,
|
||||||
fc::optional<bool> delay_bets
|
fc::optional<bool> delay_bets)
|
||||||
)
|
|
||||||
{ try {
|
{ try {
|
||||||
betting_market_group_update_operation betting_market_group_update_op;
|
betting_market_group_update_operation betting_market_group_update_op;
|
||||||
betting_market_group_update_op.betting_market_group_id = betting_market_group_id;
|
betting_market_group_update_op.betting_market_group_id = betting_market_group_id;
|
||||||
betting_market_group_update_op.new_description = description;
|
betting_market_group_update_op.new_description = description;
|
||||||
betting_market_group_update_op.new_event_id = event_id;
|
|
||||||
betting_market_group_update_op.new_rules_id = rules_id;
|
betting_market_group_update_op.new_rules_id = rules_id;
|
||||||
betting_market_group_update_op.freeze = freeze;
|
betting_market_group_update_op.freeze = freeze;
|
||||||
betting_market_group_update_op.delay_bets = delay_bets;
|
betting_market_group_update_op.delay_bets = delay_bets;
|
||||||
process_operation_by_witnesses(betting_market_group_update_op);
|
process_operation_by_witnesses(betting_market_group_update_op);
|
||||||
} FC_CAPTURE_AND_RETHROW( (betting_market_group_id)(description)(event_id)(rules_id)(freeze)(delay_bets)) }
|
} FC_CAPTURE_AND_RETHROW( (betting_market_group_id)(description)(rules_id)(freeze)(delay_bets)) }
|
||||||
|
|
||||||
|
|
||||||
const betting_market_object& database_fixture::create_betting_market(betting_market_group_id_type group_id, internationalized_string_type payout_condition)
|
const betting_market_object& database_fixture::create_betting_market(betting_market_group_id_type group_id, internationalized_string_type payout_condition)
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,6 @@ struct database_fixture {
|
||||||
const betting_market_group_object& create_betting_market_group(internationalized_string_type description, event_id_type event_id, betting_market_rules_id_type rules_id, asset_id_type asset_id);
|
const betting_market_group_object& create_betting_market_group(internationalized_string_type description, event_id_type event_id, betting_market_rules_id_type rules_id, asset_id_type asset_id);
|
||||||
void update_betting_market_group(betting_market_group_id_type betting_market_group_id,
|
void update_betting_market_group(betting_market_group_id_type betting_market_group_id,
|
||||||
fc::optional<internationalized_string_type> description,
|
fc::optional<internationalized_string_type> description,
|
||||||
fc::optional<object_id_type> event_id,
|
|
||||||
fc::optional<object_id_type> rules_id,
|
fc::optional<object_id_type> rules_id,
|
||||||
fc::optional<bool> freeze,
|
fc::optional<bool> freeze,
|
||||||
fc::optional<bool> delay_bets);
|
fc::optional<bool> delay_bets);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue