Start implementing bettimg_market_resolve op
This commit is contained in:
parent
fd38d385ca
commit
784b11059f
9 changed files with 126 additions and 12 deletions
|
|
@ -209,6 +209,7 @@ struct get_impacted_account_visitor
|
||||||
void operator()( const event_create_operation& op ) {}
|
void operator()( const event_create_operation& op ) {}
|
||||||
void operator()( const betting_market_group_create_operation& op ) {}
|
void operator()( const betting_market_group_create_operation& op ) {}
|
||||||
void operator()( const betting_market_create_operation& op ) {}
|
void operator()( const betting_market_create_operation& op ) {}
|
||||||
|
void operator()( const betting_market_resolve_operation& op ) {}
|
||||||
void operator()( const bet_place_operation& op )
|
void operator()( const bet_place_operation& op )
|
||||||
{
|
{
|
||||||
_impacted.insert( op.bettor_id );
|
_impacted.insert( op.bettor_id );
|
||||||
|
|
|
||||||
|
|
@ -179,4 +179,17 @@ void_result bet_cancel_evaluator::do_apply(const bet_cancel_operation& op)
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
void_result betting_market_resolve_evaluator::do_evaluate(const betting_market_resolve_operation& op)
|
||||||
|
{ try {
|
||||||
|
const database& d = db();
|
||||||
|
_betting_market = &op.betting_market_id(d);
|
||||||
|
return void_result();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
void_result betting_market_resolve_evaluator::do_apply(const betting_market_resolve_operation& op)
|
||||||
|
{ try {
|
||||||
|
db().resolve_betting_market(*_betting_market, op.resolution);
|
||||||
|
return void_result();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,50 @@ void database::cancel_bet( const bet_object& bet, bool create_virtual_op )
|
||||||
remove(bet);
|
remove(bet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void database::resolve_betting_market(const betting_market_object& betting_market,
|
||||||
|
betting_market_resolution_type resolution)
|
||||||
|
{
|
||||||
|
// TODO: cancel all unmatched bets on the books for this market
|
||||||
|
auto& index = get_index_type<betting_market_position_index>().indices().get<by_bettor_betting_market>();
|
||||||
|
auto position_itr = index.lower_bound(std::make_tuple(betting_market.id));
|
||||||
|
while (position_itr != index.end() &&
|
||||||
|
position_itr->betting_market_id == betting_market.id)
|
||||||
|
{
|
||||||
|
const betting_market_position_object& position = *position_itr;
|
||||||
|
++position_itr;
|
||||||
|
|
||||||
|
share_type payout_amount = 0;
|
||||||
|
switch (resolution)
|
||||||
|
{
|
||||||
|
case betting_market_resolution_type::win:
|
||||||
|
payout_amount += position.pay_if_payout_condition;
|
||||||
|
payout_amount += position.pay_if_not_canceled;
|
||||||
|
break;
|
||||||
|
case betting_market_resolution_type::not_win:
|
||||||
|
payout_amount += position.pay_if_not_payout_condition;
|
||||||
|
payout_amount += position.pay_if_not_canceled;
|
||||||
|
break;
|
||||||
|
case betting_market_resolution_type::cancel:
|
||||||
|
payout_amount += position.pay_if_canceled;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
adjust_balance(position.bettor_id, asset(payout_amount, betting_market.asset_id));
|
||||||
|
//TODO: pay the fees to the correct (dividend-distribution) account
|
||||||
|
adjust_balance(account_id_type(), asset(position.fees_collected, betting_market.asset_id));
|
||||||
|
//TODO: generate a virtual op to notify the bettor that they won or lost
|
||||||
|
|
||||||
|
remove(position);
|
||||||
|
}
|
||||||
|
remove(betting_market);
|
||||||
|
}
|
||||||
|
|
||||||
bool maybe_cull_small_bet( database& db, const bet_object& bet_object_to_cull )
|
bool maybe_cull_small_bet( database& db, const bet_object& bet_object_to_cull )
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we
|
* There are times when this bet can't be matched (for example, it's now laying a 2:1 bet for
|
||||||
* have hit the limit where the seller is asking for nothing in return. When this
|
* 1 satoshi, so it could only be matched by half a satoshi). Remove these bets from
|
||||||
* happens we must refund any balance back to the seller, it is too small to be
|
* the books.
|
||||||
* sold at the sale price.
|
|
||||||
*
|
|
||||||
* If the order is a taker order (as opposed to a maker order), so the price is
|
|
||||||
* set by the counterparty, this check is deferred until the order becomes unmatched
|
|
||||||
* (see #555) -- however, detecting this condition is the responsibility of the caller.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( bet_object_to_cull.get_matching_amount() == 0 )
|
if( bet_object_to_cull.get_matching_amount() == 0 )
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,7 @@ void database::initialize_evaluators()
|
||||||
register_evaluator<betting_market_group_create_evaluator>();
|
register_evaluator<betting_market_group_create_evaluator>();
|
||||||
register_evaluator<betting_market_create_evaluator>();
|
register_evaluator<betting_market_create_evaluator>();
|
||||||
register_evaluator<bet_place_evaluator>();
|
register_evaluator<bet_place_evaluator>();
|
||||||
|
register_evaluator<betting_market_resolve_evaluator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::initialize_indexes()
|
void database::initialize_indexes()
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,15 @@ namespace graphene { namespace chain {
|
||||||
const bet_object* _bet_to_cancel;
|
const bet_object* _bet_to_cancel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class betting_market_resolve_evaluator : public evaluator<betting_market_resolve_evaluator>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef betting_market_resolve_operation operation_type;
|
||||||
|
|
||||||
|
void_result do_evaluate( const betting_market_resolve_operation& o );
|
||||||
|
void_result do_apply( const betting_market_resolve_operation& o );
|
||||||
|
private:
|
||||||
|
const betting_market_object* _betting_market;
|
||||||
|
};
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ typedef multi_index_container<
|
||||||
typedef generic_index<bet_object, bet_object_multi_index_type> bet_object_index;
|
typedef generic_index<bet_object, bet_object_multi_index_type> bet_object_index;
|
||||||
|
|
||||||
struct by_bettor_betting_market{};
|
struct by_bettor_betting_market{};
|
||||||
|
struct by_betting_market_bettor{};
|
||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
betting_market_position_object,
|
betting_market_position_object,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
|
|
@ -243,8 +244,13 @@ typedef multi_index_container<
|
||||||
composite_key<
|
composite_key<
|
||||||
betting_market_position_object,
|
betting_market_position_object,
|
||||||
member<betting_market_position_object, account_id_type, &betting_market_position_object::bettor_id>,
|
member<betting_market_position_object, account_id_type, &betting_market_position_object::bettor_id>,
|
||||||
member<betting_market_position_object, betting_market_id_type, &betting_market_position_object::betting_market_id>
|
member<betting_market_position_object, betting_market_id_type, &betting_market_position_object::betting_market_id> > >,
|
||||||
> > > > betting_market_position_multi_index_type;
|
ordered_unique< tag<by_betting_market_bettor>,
|
||||||
|
composite_key<
|
||||||
|
betting_market_position_object,
|
||||||
|
member<betting_market_position_object, betting_market_id_type, &betting_market_position_object::betting_market_id>,
|
||||||
|
member<betting_market_position_object, account_id_type, &betting_market_position_object::bettor_id> > >
|
||||||
|
> > betting_market_position_multi_index_type;
|
||||||
|
|
||||||
typedef generic_index<betting_market_position_object, betting_market_position_multi_index_type> betting_market_position_index;
|
typedef generic_index<betting_market_position_object, betting_market_position_multi_index_type> betting_market_position_index;
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,8 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
/// @{ @group Betting Market Helpers
|
/// @{ @group Betting Market Helpers
|
||||||
void cancel_bet(const bet_object& bet, bool create_virtual_op = true);
|
void cancel_bet(const bet_object& bet, bool create_virtual_op = true);
|
||||||
|
void resolve_betting_market(const betting_market_object& betting_market,
|
||||||
|
betting_market_resolution_type resolution);
|
||||||
/**
|
/**
|
||||||
* @brief Process a new bet
|
* @brief Process a new bet
|
||||||
* @param new_bet_object The new bet to process
|
* @param new_bet_object The new bet to process
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ namespace graphene { namespace chain {
|
||||||
betting_market_group_create_operation,
|
betting_market_group_create_operation,
|
||||||
betting_market_create_operation,
|
betting_market_create_operation,
|
||||||
bet_place_operation,
|
bet_place_operation,
|
||||||
|
betting_market_resolve_operation,
|
||||||
bet_matched_operation, // VIRTUAL
|
bet_matched_operation, // VIRTUAL
|
||||||
bet_cancel_operation,
|
bet_cancel_operation,
|
||||||
bet_canceled_operation // VIRTUAL
|
bet_canceled_operation // VIRTUAL
|
||||||
|
|
|
||||||
|
|
@ -1809,7 +1809,7 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test )
|
||||||
const betting_market_object& market = *db.get_index_type<betting_market_object_index>().indices().begin();
|
const betting_market_object& market = *db.get_index_type<betting_market_object_index>().indices().begin();
|
||||||
|
|
||||||
{
|
{
|
||||||
// have bob lay a bet at 1:1 odds
|
// have bob lay a bet for 1M (+20k fees) at 1:1 odds
|
||||||
signed_transaction tx;
|
signed_transaction tx;
|
||||||
bet_place_operation bet_op;
|
bet_place_operation bet_op;
|
||||||
bet_op.bettor_id = bob_id;
|
bet_op.bettor_id = bob_id;
|
||||||
|
|
@ -1826,7 +1826,7 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test )
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// have alice back a matching bet at 1:1 odds
|
// have alice back a matching bet at 1:1 odds (also costing 1.02M)
|
||||||
signed_transaction tx;
|
signed_transaction tx;
|
||||||
bet_place_operation bet_op;
|
bet_place_operation bet_op;
|
||||||
bet_op.bettor_id = alice_id;
|
bet_op.bettor_id = alice_id;
|
||||||
|
|
@ -1841,6 +1841,52 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test )
|
||||||
sign(tx, alice_private_key);
|
sign(tx, alice_private_key);
|
||||||
db.push_transaction(tx);
|
db.push_transaction(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// caps win
|
||||||
|
{
|
||||||
|
proposal_create_operation proposal_op;
|
||||||
|
proposal_op.fee_paying_account = (*active_witnesses.begin())(db).witness_account;
|
||||||
|
betting_market_resolve_operation betting_market_resolve_op;
|
||||||
|
betting_market_resolve_op.betting_market_id = market.id;
|
||||||
|
betting_market_resolve_op.resolution = betting_market_resolution_type::win;
|
||||||
|
proposal_op.proposed_ops.emplace_back(betting_market_resolve_op);
|
||||||
|
proposal_op.expiration_time = db.head_block_time() + fc::days(1);
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back(proposal_op);
|
||||||
|
set_expiration(db, tx);
|
||||||
|
sign(tx, init_account_priv_key);
|
||||||
|
|
||||||
|
db.push_transaction(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(db.get_index_type<proposal_index>().indices().size(), 1);
|
||||||
|
{
|
||||||
|
const proposal_object& prop = *db.get_index_type<proposal_index>().indices().begin();
|
||||||
|
|
||||||
|
for (const witness_id_type& witness_id : active_witnesses)
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Approving market resolve witness " << fc::variant(witness_id).as<std::string>());
|
||||||
|
const witness_object& witness = witness_id(db);
|
||||||
|
const account_object& witness_account = witness.witness_account(db);
|
||||||
|
|
||||||
|
proposal_update_operation pup;
|
||||||
|
pup.proposal = prop.id;
|
||||||
|
pup.fee_paying_account = witness_account.id;
|
||||||
|
pup.active_approvals_to_add.insert(witness_account.id);
|
||||||
|
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( pup );
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign(tx, init_account_priv_key);
|
||||||
|
|
||||||
|
db.push_transaction(tx, ~0);
|
||||||
|
if (db.get_index_type<proposal_index>().indices().size() == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000);
|
||||||
|
BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue