ppy marketplace 1 - add evaluators and objects
This commit is contained in:
parent
d8ca4d4625
commit
3032185b5c
15 changed files with 1057 additions and 2 deletions
|
|
@ -61,6 +61,7 @@ add_library( graphene_chain
|
|||
protocol/vote.cpp
|
||||
protocol/tournament.cpp
|
||||
protocol/small_ops.cpp
|
||||
protocol/offer.cpp
|
||||
|
||||
genesis_state.cpp
|
||||
get_config.cpp
|
||||
|
|
@ -115,6 +116,8 @@ add_library( graphene_chain
|
|||
|
||||
affiliate_payout.cpp
|
||||
|
||||
offer_evaluator.cpp
|
||||
|
||||
${HEADERS}
|
||||
${PROTOCOL_HEADERS}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp"
|
||||
|
|
|
|||
|
|
@ -721,6 +721,7 @@ void database::_apply_block( const signed_block& next_block )
|
|||
update_withdraw_permissions();
|
||||
update_tournaments();
|
||||
update_betting_markets(next_block.timestamp);
|
||||
finalize_expired_offers();
|
||||
|
||||
// n.b., update_maintenance_flag() happens this late
|
||||
// because get_slot_time() / get_slot_at_time() is needed above
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include <graphene/chain/tournament_object.hpp>
|
||||
#include <graphene/chain/match_object.hpp>
|
||||
#include <graphene/chain/game_object.hpp>
|
||||
#include <graphene/chain/offer_object.hpp>
|
||||
|
||||
|
||||
#include <graphene/chain/sport_object.hpp>
|
||||
|
|
@ -77,6 +78,7 @@
|
|||
#include <graphene/chain/event_evaluator.hpp>
|
||||
#include <graphene/chain/betting_market_evaluator.hpp>
|
||||
#include <graphene/chain/tournament_evaluator.hpp>
|
||||
#include <graphene/chain/offer_evaluator.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||
|
||||
|
|
@ -169,6 +171,11 @@ const uint8_t betting_market_position_object::type_id;
|
|||
const uint8_t global_betting_statistics_object::space_id;
|
||||
const uint8_t global_betting_statistics_object::type_id;
|
||||
|
||||
const uint8_t offer_object::space_id;
|
||||
const uint8_t offer_object::type_id;
|
||||
|
||||
const uint8_t offer_history_object::space_id;
|
||||
const uint8_t offer_history_object::type_id;
|
||||
|
||||
void database::initialize_evaluators()
|
||||
{
|
||||
|
|
@ -243,6 +250,9 @@ void database::initialize_evaluators()
|
|||
register_evaluator<lottery_reward_evaluator>();
|
||||
register_evaluator<lottery_end_evaluator>();
|
||||
register_evaluator<sweeps_vesting_claim_evaluator>();
|
||||
register_evaluator<offer_evaluator>();
|
||||
register_evaluator<bid_evaluator>();
|
||||
register_evaluator<finalize_offer_evaluator>();
|
||||
}
|
||||
|
||||
void database::initialize_indexes()
|
||||
|
|
@ -284,6 +294,7 @@ void database::initialize_indexes()
|
|||
tournament_details_idx->add_secondary_index<tournament_players_index>();
|
||||
add_index< primary_index<match_index> >();
|
||||
add_index< primary_index<game_index> >();
|
||||
add_index< primary_index<offer_index> >();
|
||||
|
||||
//Implementation object indexes
|
||||
add_index< primary_index<transaction_index > >();
|
||||
|
|
@ -313,6 +324,7 @@ void database::initialize_indexes()
|
|||
|
||||
add_index< primary_index<lottery_balance_index > >();
|
||||
add_index< primary_index<sweeps_vesting_balance_index > >();
|
||||
add_index< primary_index<offer_history_index > >();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,6 +293,19 @@ struct get_impacted_account_visitor
|
|||
void operator()( const sweeps_vesting_claim_operation& op ) {
|
||||
_impacted.insert( op.account );
|
||||
}
|
||||
|
||||
void operator()( const offer_operation& op )
|
||||
{
|
||||
_impacted.insert( op.issuer );
|
||||
}
|
||||
void operator()( const bid_operation& op )
|
||||
{
|
||||
_impacted.insert( op.bidder );
|
||||
}
|
||||
void operator()( const finalize_offer_operation& op )
|
||||
{
|
||||
_impacted.insert( op.fee_paying_account );
|
||||
}
|
||||
};
|
||||
|
||||
void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
|
|
@ -705,4 +705,30 @@ void database::update_betting_markets(fc::time_point_sec current_block_time)
|
|||
remove_completed_events();
|
||||
}
|
||||
|
||||
void database::finalize_expired_offers(){
|
||||
try {
|
||||
detail::with_skip_flags( *this,
|
||||
get_node_properties().skip_flags | skip_authority_check, [&](){
|
||||
transaction_evaluation_state cancel_context(this);
|
||||
|
||||
//Cancel expired limit orders
|
||||
auto& limit_index = get_index_type<offer_index>().indices().get<by_expiration_date>();
|
||||
auto itr = limit_index.begin();
|
||||
while( itr != limit_index.end() && itr->offer_expiration_date <= head_block_time() )
|
||||
{
|
||||
const offer_object& offer = *itr;
|
||||
++itr;
|
||||
|
||||
finalize_offer_operation finalize;
|
||||
finalize.fee_paying_account = offer.transfer_agent_id;
|
||||
finalize.offer_id = offer.id;
|
||||
finalize.fee = current_fee_schedule().calculate_fee( finalize );
|
||||
finalize.result = offer.bidder ? result_type::Expired : result_type::ExpiredNoBid;
|
||||
|
||||
cancel_context.skip_fee_schedule_check = true;
|
||||
apply_operation(cancel_context, finalize);
|
||||
}
|
||||
});
|
||||
} FC_CAPTURE_AND_RETHROW()}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -519,6 +519,7 @@ namespace graphene { namespace chain {
|
|||
void update_betting_markets(fc::time_point_sec current_block_time);
|
||||
bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true,
|
||||
const asset_bitasset_data_object* bitasset_ptr = nullptr );
|
||||
void finalize_expired_offers();
|
||||
|
||||
///Steps performed only at maintenance intervals
|
||||
///@{
|
||||
|
|
|
|||
34
libraries/chain/include/graphene/chain/offer_evaluator.hpp
Normal file
34
libraries/chain/include/graphene/chain/offer_evaluator.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <graphene/chain/protocol/operations.hpp>
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class offer_evaluator : public evaluator<offer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef offer_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const offer_operation& o );
|
||||
object_id_type do_apply( const offer_operation& o );
|
||||
};
|
||||
|
||||
class bid_evaluator : public evaluator<bid_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef bid_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const bid_operation& o );
|
||||
void_result do_apply( const bid_operation& o );
|
||||
};
|
||||
|
||||
class finalize_offer_evaluator : public evaluator<finalize_offer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef finalize_offer_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const finalize_offer_operation& op );
|
||||
void_result do_apply( const finalize_offer_operation& op );
|
||||
};
|
||||
|
||||
}}
|
||||
117
libraries/chain/include/graphene/chain/offer_object.hpp
Normal file
117
libraries/chain/include/graphene/chain/offer_object.hpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/operations.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class database;
|
||||
|
||||
/**
|
||||
* @brief This class represents an offer on the object graph
|
||||
* @ingroup object
|
||||
* @ingroup protocol
|
||||
*
|
||||
*/
|
||||
struct by_expiration_date{};
|
||||
class offer_object : public graphene::db::abstract_object<offer_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = offer_object_type;
|
||||
|
||||
account_id_type issuer;
|
||||
|
||||
account_id_type transfer_agent_id;
|
||||
uint32_t item_id;
|
||||
optional<account_id_type> bidder;
|
||||
optional<asset> bid_price;
|
||||
asset minimum_price;
|
||||
asset maximum_price;
|
||||
|
||||
bool buying_item;
|
||||
fc::time_point_sec offer_expiration_date;
|
||||
|
||||
offer_id_type get_id()const { return id; }
|
||||
};
|
||||
|
||||
class offer_history_object : public graphene::db::abstract_object<offer_history_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_offer_history_object_type;
|
||||
|
||||
account_id_type issuer;
|
||||
|
||||
account_id_type transfer_agent_id;
|
||||
uint32_t item_id;
|
||||
optional<account_id_type> bidder;
|
||||
optional<asset> bid_price;
|
||||
asset minimum_price;
|
||||
asset maximum_price;
|
||||
|
||||
bool buying_item;
|
||||
fc::time_point_sec offer_expiration_date;
|
||||
|
||||
offer_history_id_type get_id()const { return id; }
|
||||
};
|
||||
|
||||
struct compare_by_expiration_date {
|
||||
bool operator()( const fc::time_point_sec& o1, const fc::time_point_sec& o2 ) const {
|
||||
return o1 > o2;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef multi_index_container<
|
||||
offer_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique<
|
||||
tag<by_expiration_date>,
|
||||
member< offer_object, fc::time_point_sec, &offer_object::offer_expiration_date >,
|
||||
compare_by_expiration_date
|
||||
>
|
||||
>
|
||||
> offer_multi_index_type;
|
||||
|
||||
typedef multi_index_container<
|
||||
offer_history_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique<
|
||||
tag<by_expiration_date>,
|
||||
member< offer_history_object, fc::time_point_sec, &offer_history_object::offer_expiration_date >,
|
||||
compare_by_expiration_date
|
||||
>
|
||||
>
|
||||
> offer_history_multi_index_type;
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef generic_index<offer_object, offer_multi_index_type> offer_index;
|
||||
|
||||
typedef generic_index<offer_history_object, offer_history_multi_index_type> offer_history_index;
|
||||
|
||||
}}
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::offer_object,
|
||||
(graphene::db::object),
|
||||
(issuer)
|
||||
(transfer_agent_id)(item_id)
|
||||
(bidder)(bid_price)
|
||||
(minimum_price)(maximum_price)
|
||||
(buying_item)
|
||||
(offer_expiration_date)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::offer_history_object,
|
||||
(graphene::db::object),
|
||||
(issuer)
|
||||
(transfer_agent_id)(item_id)
|
||||
(bidder)(bid_price)
|
||||
(minimum_price)(maximum_price)
|
||||
(buying_item)
|
||||
(offer_expiration_date)
|
||||
)
|
||||
106
libraries/chain/include/graphene/chain/protocol/offer.hpp
Normal file
106
libraries/chain/include/graphene/chain/protocol/offer.hpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
#include <graphene/chain/protocol/memo.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/*
|
||||
* @class offer_operation
|
||||
* @brief To place an offer to buy or sell an item, a user broadcasts a proposed transaction
|
||||
* @ingroup operations
|
||||
* @pre amount.asset_id->issuer == issuer
|
||||
* @pre issuer != from because this is pointless, use a normal transfer operation
|
||||
*/
|
||||
struct offer_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||
uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
|
||||
};
|
||||
|
||||
account_id_type transfer_agent_id;
|
||||
uint32_t item_id;
|
||||
|
||||
// /**
|
||||
// * minimum_price.asset_id == maximum_price.asset_id.
|
||||
// * to set fixed price without auction minimum_price == maximum_price
|
||||
// * If buying_item is true, and minimum_price != maximum_price, the user is proposing a “reverse auction”
|
||||
// * where bidders can offer to sell the item for progressively lower prices.
|
||||
// * In this case, minimum_price functions as the sell-it-now price for the reverse auction
|
||||
// */
|
||||
|
||||
asset fee;
|
||||
account_id_type issuer;
|
||||
|
||||
/// minimum_price is minimum bid price. 0 if no minimum_price required
|
||||
asset minimum_price;
|
||||
/// buy_it_now price. 0 if no maximum price
|
||||
asset maximum_price;
|
||||
/// true means user wants to buy item, false mean user is selling item
|
||||
bool buying_item;
|
||||
/// not transaction expiration date
|
||||
fc::time_point_sec offer_expiration_date;
|
||||
|
||||
/// User provided data encrypted to the memo key of the "to" account
|
||||
optional<memo_data> memo;
|
||||
extensions_type extensions;
|
||||
|
||||
account_id_type fee_payer()const { return transfer_agent_id; }
|
||||
void validate()const;
|
||||
share_type calculate_fee(const fee_parameters_type& k)const;
|
||||
};
|
||||
|
||||
struct bid_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||
uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
|
||||
};
|
||||
|
||||
asset fee;
|
||||
account_id_type bidder;
|
||||
|
||||
asset bid_price;
|
||||
offer_id_type offer_id;
|
||||
|
||||
extensions_type extensions;
|
||||
|
||||
account_id_type fee_payer()const { return bidder; }
|
||||
void validate()const;
|
||||
share_type calculate_fee(const fee_parameters_type& k)const;
|
||||
};
|
||||
|
||||
enum class result_type {Expired = 0, ExpiredNoBid = 1};
|
||||
|
||||
struct finalize_offer_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||
uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
|
||||
};
|
||||
|
||||
asset fee;
|
||||
account_id_type fee_paying_account;
|
||||
|
||||
offer_id_type offer_id;
|
||||
|
||||
fc::enum_type<uint8_t,result_type> result;
|
||||
|
||||
extensions_type extensions;
|
||||
|
||||
account_id_type fee_payer()const { return fee_paying_account; }
|
||||
void validate()const;
|
||||
share_type calculate_fee(const fee_parameters_type& k)const;
|
||||
};
|
||||
|
||||
}} // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::offer_operation::fee_parameters_type, (fee)(price_per_kbyte) );
|
||||
FC_REFLECT( graphene::chain::offer_operation, (fee)(issuer)(memo)(minimum_price)(maximum_price)(buying_item)(transfer_agent_id)(item_id)(offer_expiration_date)(extensions) );
|
||||
|
||||
FC_REFLECT( graphene::chain::bid_operation::fee_parameters_type, (fee)(price_per_kbyte) );
|
||||
FC_REFLECT( graphene::chain::bid_operation, (fee)(bidder)(bid_price)(offer_id)(extensions) );
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::result_type, (Expired)(ExpiredNoBid) );
|
||||
FC_REFLECT( graphene::chain::finalize_offer_operation::fee_parameters_type, (fee)(price_per_kbyte) );
|
||||
FC_REFLECT( graphene::chain::finalize_offer_operation, (fee)(fee_paying_account)(offer_id)(result)(extensions) );
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
#include <graphene/chain/protocol/event.hpp>
|
||||
#include <graphene/chain/protocol/betting_market.hpp>
|
||||
#include <graphene/chain/protocol/tournament.hpp>
|
||||
#include <graphene/chain/protocol/offer.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -135,7 +136,10 @@ namespace graphene { namespace chain {
|
|||
ticket_purchase_operation,
|
||||
lottery_reward_operation,
|
||||
lottery_end_operation,
|
||||
sweeps_vesting_claim_operation
|
||||
sweeps_vesting_claim_operation,
|
||||
offer_operation,
|
||||
bid_operation,
|
||||
finalize_offer_operation
|
||||
> operation;
|
||||
|
||||
/// @} // operations group
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ namespace graphene { namespace chain {
|
|||
betting_market_group_object_type,
|
||||
betting_market_object_type,
|
||||
bet_object_type,
|
||||
offer_object_type,
|
||||
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
|
||||
};
|
||||
|
||||
|
|
@ -199,7 +200,8 @@ namespace graphene { namespace chain {
|
|||
impl_betting_market_position_object_type,
|
||||
impl_global_betting_statistics_object_type,
|
||||
impl_lottery_balance_object_type,
|
||||
impl_sweeps_vesting_balance_object_type
|
||||
impl_sweeps_vesting_balance_object_type,
|
||||
impl_offer_history_object_type
|
||||
};
|
||||
|
||||
//typedef fc::unsigned_int object_id_type;
|
||||
|
|
@ -230,6 +232,7 @@ namespace graphene { namespace chain {
|
|||
class betting_market_group_object;
|
||||
class betting_market_object;
|
||||
class bet_object;
|
||||
class offer_object;
|
||||
|
||||
typedef object_id< protocol_ids, account_object_type, account_object> account_id_type;
|
||||
typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type;
|
||||
|
|
@ -256,6 +259,7 @@ namespace graphene { namespace chain {
|
|||
typedef object_id< protocol_ids, betting_market_group_object_type, betting_market_group_object> betting_market_group_id_type;
|
||||
typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type;
|
||||
typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type;
|
||||
typedef object_id< protocol_ids, offer_object_type, offer_object> offer_id_type;
|
||||
|
||||
// implementation types
|
||||
class global_property_object;
|
||||
|
|
@ -279,6 +283,7 @@ namespace graphene { namespace chain {
|
|||
class global_betting_statistics_object;
|
||||
class lottery_balance_object;
|
||||
class sweeps_vesting_balance_object;
|
||||
class offer_history_object;
|
||||
|
||||
typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type;
|
||||
typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type;
|
||||
|
|
@ -307,6 +312,7 @@ namespace graphene { namespace chain {
|
|||
typedef object_id< implementation_ids, impl_global_betting_statistics_object_type, global_betting_statistics_object > global_betting_statistics_id_type;
|
||||
typedef object_id< implementation_ids, impl_lottery_balance_object_type, lottery_balance_object > lottery_balance_id_type;
|
||||
typedef object_id< implementation_ids, impl_sweeps_vesting_balance_object_type, sweeps_vesting_balance_object> sweeps_vesting_balance_id_type;
|
||||
typedef object_id< implementation_ids, impl_offer_history_object_type, offer_history_object> offer_history_id_type;
|
||||
|
||||
typedef fc::array<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
|
||||
typedef fc::ripemd160 block_id_type;
|
||||
|
|
@ -436,6 +442,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
|
|||
(betting_market_group_object_type)
|
||||
(betting_market_object_type)
|
||||
(bet_object_type)
|
||||
(offer_object_type)
|
||||
(OBJECT_TYPE_COUNT)
|
||||
)
|
||||
FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
||||
|
|
@ -463,6 +470,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
|||
(impl_global_betting_statistics_object_type)
|
||||
(impl_lottery_balance_object_type)
|
||||
(impl_sweeps_vesting_balance_object_type)
|
||||
(impl_offer_history_object_type)
|
||||
)
|
||||
|
||||
FC_REFLECT_TYPENAME( graphene::chain::share_type )
|
||||
|
|
@ -489,6 +497,7 @@ FC_REFLECT_TYPENAME( graphene::chain::betting_market_group_id_type )
|
|||
FC_REFLECT_TYPENAME( graphene::chain::betting_market_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::bet_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::tournament_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::offer_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::global_property_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::dynamic_global_property_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::asset_dynamic_data_id_type )
|
||||
|
|
@ -505,6 +514,7 @@ FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type )
|
|||
FC_REFLECT_TYPENAME( graphene::chain::betting_market_position_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::global_betting_statistics_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::offer_history_id_type )
|
||||
|
||||
FC_REFLECT( graphene::chain::void_t, )
|
||||
|
||||
|
|
|
|||
173
libraries/chain/offer_evaluator.cpp
Normal file
173
libraries/chain/offer_evaluator.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#include <graphene/chain/offer_evaluator.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/offer_object.hpp>
|
||||
#include <graphene/chain/exceptions.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <graphene/chain/is_authorized_asset.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void_result offer_evaluator::do_evaluate( const offer_operation& op )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
FC_ASSERT( op.offer_expiration_date > d.head_block_time() );
|
||||
FC_ASSERT( op.item_id > 0 );
|
||||
FC_ASSERT( op.fee.amount >= 0 );
|
||||
FC_ASSERT( op.minimum_price.amount >= 0 && op.maximum_price.amount > 0);
|
||||
FC_ASSERT( op.minimum_price.asset_id == op.maximum_price.asset_id );
|
||||
FC_ASSERT( op.maximum_price >= op.minimum_price );
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type offer_evaluator::do_apply( const offer_operation& o )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
if (o.buying_item)
|
||||
{
|
||||
d.adjust_balance( o.issuer, -o.maximum_price);
|
||||
d.adjust_balance( o.transfer_agent_id, o.maximum_price );
|
||||
}
|
||||
|
||||
const auto& offer_obj = db().create<offer_object>( [&]( offer_object& obj ){
|
||||
obj.issuer = o.issuer;
|
||||
|
||||
obj.transfer_agent_id = o.transfer_agent_id;
|
||||
obj.item_id = o.item_id;
|
||||
|
||||
obj.minimum_price = o.minimum_price;
|
||||
obj.maximum_price = o.maximum_price;
|
||||
|
||||
obj.buying_item = o.buying_item;
|
||||
obj.offer_expiration_date = o.offer_expiration_date;
|
||||
auto& idx = d.get_index_type<account_index>().indices().get<by_id>();
|
||||
auto acc = idx.find(o.issuer);
|
||||
FC_ASSERT(acc != idx.end());
|
||||
|
||||
});
|
||||
|
||||
return offer_obj.id;
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
void_result bid_evaluator::do_evaluate( const bid_operation& op )
|
||||
{ try {
|
||||
database& d = db();
|
||||
offer_object offer = op.offer_id(d);
|
||||
|
||||
FC_ASSERT( op.bid_price.asset_id == offer.minimum_price.asset_id);
|
||||
FC_ASSERT( offer.transfer_agent_id(d).whitelisted_accounts.find(op.bidder) != offer.transfer_agent_id(d).whitelisted_accounts.end() );
|
||||
FC_ASSERT( offer.minimum_price.amount == 0 || op.bid_price >= offer.minimum_price);
|
||||
FC_ASSERT( offer.maximum_price.amount == 0 || op.bid_price <= offer.maximum_price);
|
||||
if (offer.bidder) {
|
||||
FC_ASSERT((offer.buying_item && op.bid_price < *offer.bid_price) || (!offer.buying_item && op.bid_price > *offer.bid_price));
|
||||
}
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
void_result bid_evaluator::do_apply( const bid_operation& op )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
offer_object offer = op.offer_id(d);
|
||||
|
||||
if (!offer.buying_item)
|
||||
{
|
||||
if(offer.bidder)
|
||||
{
|
||||
d.adjust_balance( *offer.bidder, *offer.bid_price );
|
||||
d.adjust_balance( offer.transfer_agent_id, -(*offer.bid_price ));
|
||||
}
|
||||
d.adjust_balance( op.bidder, -op.bid_price);
|
||||
d.adjust_balance( offer.transfer_agent_id, op.bid_price );
|
||||
}
|
||||
d.modify( op.offer_id(d), [&]( offer_object& o )
|
||||
{
|
||||
if (op.bid_price == ( offer.buying_item ? offer.minimum_price : offer.maximum_price ) ) {
|
||||
o.offer_expiration_date = d.head_block_time();
|
||||
}
|
||||
o.bidder = op.bidder;
|
||||
o.bid_price = op.bid_price;
|
||||
});
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
void_result finalize_offer_evaluator::do_evaluate(const finalize_offer_operation& op)
|
||||
{ try {
|
||||
database& d = db();
|
||||
offer_object offer = op.offer_id(d);
|
||||
|
||||
// FC_ASSERT(*offer.bid_price == (offer.buying_item ? offer.minimum_price : offer.maximum_price));
|
||||
|
||||
if (op.result != result_type::ExpiredNoBid)
|
||||
{
|
||||
FC_ASSERT(offer.bidder);
|
||||
FC_ASSERT((*offer.bid_price).amount >= 0);
|
||||
} else
|
||||
{
|
||||
FC_ASSERT(!offer.bidder);
|
||||
}
|
||||
|
||||
switch (op.result) {
|
||||
case result_type::Expired:
|
||||
case result_type::ExpiredNoBid:
|
||||
FC_ASSERT(offer.offer_expiration_date <= d.head_block_time());
|
||||
break;
|
||||
default:
|
||||
FC_THROW_EXCEPTION( fc::assert_exception, "finalize_offer_operation: unknown result type." );
|
||||
break;
|
||||
}
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
void_result finalize_offer_evaluator::do_apply(const finalize_offer_operation& op) {
|
||||
database& d = db();
|
||||
|
||||
offer_object offer = op.offer_id(d);
|
||||
|
||||
if (op.result != result_type::ExpiredNoBid)
|
||||
{
|
||||
if (offer.buying_item)
|
||||
{
|
||||
d.adjust_balance(*offer.bidder, *offer.bid_price);
|
||||
d.adjust_balance(offer.transfer_agent_id, -offer.maximum_price);
|
||||
if (offer.bid_price < offer.maximum_price)
|
||||
{
|
||||
d.adjust_balance(offer.issuer, offer.maximum_price - *offer.bid_price);
|
||||
}
|
||||
} else
|
||||
{
|
||||
d.adjust_balance(offer.transfer_agent_id, -(*offer.bid_price));
|
||||
d.adjust_balance(offer.issuer, *offer.bid_price);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (offer.buying_item)
|
||||
{
|
||||
d.adjust_balance(offer.issuer, offer.maximum_price);
|
||||
d.adjust_balance(offer.transfer_agent_id, -offer.maximum_price);
|
||||
}
|
||||
}
|
||||
d.create<offer_history_object>( [&]( offer_history_object& obj ) {
|
||||
obj.issuer = offer.issuer;
|
||||
|
||||
obj.transfer_agent_id = offer.transfer_agent_id;
|
||||
obj.item_id = offer.item_id;
|
||||
obj.bidder = offer.bidder;
|
||||
obj.bid_price = offer.bid_price;
|
||||
obj.minimum_price = offer.minimum_price;
|
||||
obj.maximum_price = offer.maximum_price;
|
||||
|
||||
obj.buying_item = offer.buying_item;
|
||||
obj.offer_expiration_date = offer.offer_expiration_date;
|
||||
std::cout << "get id" << uint64_t(obj.get_id()) << std::endl;
|
||||
});
|
||||
d.remove(op.offer_id(d));
|
||||
return void_result();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
46
libraries/chain/protocol/offer.cpp
Normal file
46
libraries/chain/protocol/offer.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include <graphene/chain/protocol/offer.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
share_type offer_operation::calculate_fee( const fee_parameters_type& schedule )const
|
||||
{
|
||||
share_type core_fee_required = schedule.fee;
|
||||
return core_fee_required;
|
||||
}
|
||||
|
||||
|
||||
void offer_operation::validate()const
|
||||
{
|
||||
FC_ASSERT( item_id > 0 );
|
||||
FC_ASSERT( fee.amount >= 0 );
|
||||
FC_ASSERT( minimum_price.asset_id == maximum_price.asset_id );
|
||||
FC_ASSERT( minimum_price.amount >= 0 && maximum_price.amount > 0);
|
||||
FC_ASSERT( maximum_price >= minimum_price );
|
||||
|
||||
// FC_ASSERT( offer_expiration_date >= fc::time_point::now() );
|
||||
}
|
||||
|
||||
share_type bid_operation::calculate_fee( const fee_parameters_type& schedule )const
|
||||
{
|
||||
share_type core_fee_required = schedule.fee;
|
||||
return core_fee_required;
|
||||
}
|
||||
|
||||
|
||||
void bid_operation::validate()const
|
||||
{
|
||||
FC_ASSERT( fee.amount.value >= 0 );
|
||||
FC_ASSERT( bid_price.amount.value >= 0 );
|
||||
}
|
||||
|
||||
void finalize_offer_operation::validate() const {
|
||||
FC_ASSERT ( offer_id != offer_id_type() );
|
||||
FC_ASSERT( fee.amount.value >= 0 );
|
||||
}
|
||||
|
||||
share_type finalize_offer_operation::calculate_fee( const fee_parameters_type& k) const {
|
||||
share_type core_fee_required = k.fee;
|
||||
return core_fee_required;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
#include <graphene/chain/tournament_object.hpp>
|
||||
#include <graphene/chain/match_object.hpp>
|
||||
#include <graphene/chain/game_object.hpp>
|
||||
#include <graphene/chain/offer_object.hpp>
|
||||
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
#include <iostream>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/offer_object.hpp>
|
||||
#include <graphene/account_history/account_history_plugin.hpp>
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
|
@ -1821,6 +1822,513 @@ BOOST_AUTO_TEST_CASE( vesting_balance_withdraw_test )
|
|||
// TODO: Test with non-core asset and Bob account
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
offer_id_type buy_offer;
|
||||
offer_id_type sell_offer;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_offer_test)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
fc::ecc::private_key agent_pk = generate_private_key("agent");
|
||||
fc::ecc::private_key issuer_pk = generate_private_key("issuer");
|
||||
|
||||
const asset_object &bitusd = create_bitasset("STUB");
|
||||
const account_object &agent = create_account("agent", agent_pk.get_public_key());
|
||||
const account_object &issuer = create_account("issuer", issuer_pk.get_public_key());
|
||||
|
||||
transfer(committee_account(db), issuer, asset(10000));
|
||||
transfer(committee_account(db), agent, asset(10000));
|
||||
upgrade_to_lifetime_member(agent);
|
||||
|
||||
bool params[] = {true, false};
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
offer_operation offer_op;
|
||||
|
||||
offer_op.item_id = 13;
|
||||
offer_op.issuer = issuer.id;
|
||||
offer_op.buying_item = is_buying_offer;
|
||||
offer_op.maximum_price = asset(100);
|
||||
offer_op.minimum_price = asset(10);
|
||||
offer_op.transfer_agent_id = agent.id;
|
||||
// +1 second
|
||||
offer_op.offer_expiration_date = db.head_block_time() + fc::microseconds(3000000);
|
||||
|
||||
trx.operations.push_back(offer_op);
|
||||
offer_operation &op = trx.operations.back().get<offer_operation>();
|
||||
|
||||
//REQUIRE_THROW_WITH_VALUE(op, offer_expiration_date, db.head_block_time());
|
||||
|
||||
// //positive prices
|
||||
REQUIRE_OP_VALIDATION_FAILURE(op, minimum_price, asset(-1));
|
||||
REQUIRE_OP_VALIDATION_FAILURE(op, maximum_price, asset(-1));
|
||||
|
||||
REQUIRE_OP_VALIDATION_FAILURE(op, fee, asset(-1));
|
||||
|
||||
// // min price > max price check
|
||||
REQUIRE_OP_VALIDATION_FAILURE(op, maximum_price, asset(1));
|
||||
|
||||
// different asset for min/max
|
||||
REQUIRE_OP_VALIDATION_FAILURE(op, minimum_price, asset(1, bitusd.id));
|
||||
|
||||
offer_id_type offer_id = db.get_index_type<primary_index<simple_index<offer_object>>>().get_next_id();
|
||||
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
const offer_object &d = offer_id(db);
|
||||
|
||||
BOOST_CHECK(d.space_id == protocol_ids);
|
||||
BOOST_CHECK(d.type_id == offer_object_type);
|
||||
|
||||
//empty bid
|
||||
BOOST_CHECK(!d.bid_price);
|
||||
BOOST_CHECK(!d.bidder);
|
||||
|
||||
// data integrity
|
||||
BOOST_CHECK(d.issuer == issuer.id);
|
||||
BOOST_CHECK(d.maximum_price == asset(100));
|
||||
BOOST_CHECK(d.minimum_price == asset(10));
|
||||
BOOST_CHECK(d.transfer_agent_id == agent.id);
|
||||
BOOST_CHECK(d.buying_item == is_buying_offer);
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
buy_offer = offer_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sell_offer = offer_id;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (fc::exception &e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bid_test)
|
||||
{
|
||||
try
|
||||
{
|
||||
INVOKE(create_offer_test);
|
||||
const account_object &agent = get_account("agent");
|
||||
const account_object &issuer = get_account("issuer");
|
||||
const account_object &bidder = create_account("bidder", generate_private_key("bidder").get_public_key());
|
||||
transfer(committee_account(db), bidder, asset(10000));
|
||||
|
||||
account_id_type bidder_id = bidder.id;
|
||||
account_id_type agent_id = agent.id;
|
||||
account_id_type issuer_id = issuer.id;
|
||||
|
||||
const offer_object &offer_obj = buy_offer(db);
|
||||
|
||||
bid_operation bid_op;
|
||||
bid_op.offer_id = offer_obj.id;
|
||||
bid_op.bid_price = asset(offer_obj.minimum_price.amount + 1, offer_obj.minimum_price.asset_id);
|
||||
bid_op.bidder = bidder.id;
|
||||
trx.operations.push_back(bid_op);
|
||||
|
||||
// exception due to empty whitelist
|
||||
GRAPHENE_REQUIRE_THROW(PUSH_TX(db, trx, ~0), fc::exception);
|
||||
|
||||
trx.operations.clear();
|
||||
|
||||
//adding whitelist
|
||||
account_whitelist_operation wop;
|
||||
wop.authorizing_account = agent.id;
|
||||
wop.account_to_list = bidder.id;
|
||||
wop.new_listing = account_whitelist_operation::white_listed;
|
||||
trx.operations.clear();
|
||||
trx.operations.push_back(wop);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
trx.operations.clear();
|
||||
|
||||
bool params[] = {true, false};
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
asset bid;
|
||||
asset exp_delta_agent;
|
||||
asset exp_delta_bidder;
|
||||
|
||||
int64_t agent_balance = get_balance(agent_id(db), asset_id_type()(db));
|
||||
int64_t issuer_balance = get_balance(issuer_id(db), asset_id_type()(db));
|
||||
int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db));
|
||||
|
||||
const offer_object &offer_obj = is_buying_offer ? buy_offer(db) : sell_offer(db);
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
bid = asset(offer_obj.maximum_price.amount - 1, asset_id_type());
|
||||
exp_delta_agent = asset(0);
|
||||
exp_delta_bidder = asset(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bid = asset(offer_obj.minimum_price.amount + 1, asset_id_type());
|
||||
exp_delta_agent = bid;
|
||||
exp_delta_bidder = -bid;
|
||||
}
|
||||
|
||||
bid_op.offer_id = offer_obj.id;
|
||||
|
||||
bid_op.bid_price = bid;
|
||||
bid_op.bidder = bidder.id;
|
||||
|
||||
trx.operations.push_back(bid_op);
|
||||
bid_operation &op = trx.operations.back().get<bid_operation>();
|
||||
|
||||
//REQUIRE_THROW_WITH_VALUE(op, bid_price, asset(-1, asset_id_type()));
|
||||
//REQUIRE_THROW_WITH_VALUE(op, bid_price, asset(offer_obj.maximum_price.amount + 1, offer_obj.minimum_price.asset_id));
|
||||
// REQUIRE_THROW_WITH_VALUE(op, offer_id, offer_id_type());
|
||||
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(agent_id(db), asset_id_type()(db)),
|
||||
(agent_balance + exp_delta_agent.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
|
||||
(bidder_balance + exp_delta_bidder.amount).value);
|
||||
|
||||
//not empty bid
|
||||
BOOST_CHECK(offer_obj.bid_price);
|
||||
BOOST_CHECK(offer_obj.bidder);
|
||||
|
||||
// data integrity
|
||||
BOOST_CHECK(offer_obj.bidder == bidder.id);
|
||||
BOOST_CHECK(offer_obj.issuer == issuer.id);
|
||||
BOOST_CHECK(offer_obj.transfer_agent_id == agent.id);
|
||||
BOOST_CHECK(offer_obj.maximum_price == asset(100));
|
||||
BOOST_CHECK(offer_obj.minimum_price == asset(10));
|
||||
BOOST_CHECK(offer_obj.bid_price == bid);
|
||||
});
|
||||
}
|
||||
catch (fc::exception &e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(second_bid_test)
|
||||
{
|
||||
try
|
||||
{
|
||||
INVOKE(bid_test);
|
||||
const account_object &agent = get_account("agent");
|
||||
const account_object &bidder = get_account("bidder");
|
||||
const account_object &bidder2 = create_account("bidder2", generate_private_key("bidder2").get_public_key());
|
||||
|
||||
//adding whitelist
|
||||
account_whitelist_operation wop;
|
||||
wop.authorizing_account = agent.id;
|
||||
wop.account_to_list = bidder2.id;
|
||||
wop.new_listing = account_whitelist_operation::white_listed;
|
||||
trx.operations.push_back(wop);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
account_id_type agent_id = agent.id;
|
||||
account_id_type bidder_id = bidder.id;
|
||||
account_id_type bidder2_id = bidder2.id;
|
||||
|
||||
transfer(committee_account(db), bidder2, asset(10000));
|
||||
|
||||
bool params[] = {true, false};
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
asset bid;
|
||||
asset exp_delta_agent;
|
||||
asset exp_delta_bidder;
|
||||
asset exp_delta_bidder2;
|
||||
|
||||
int64_t agent_balance = get_balance(agent_id(db), asset_id_type()(db));
|
||||
int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db));
|
||||
int64_t bidder2_balance = get_balance(bidder2_id(db), asset_id_type()(db));
|
||||
|
||||
const offer_object &offer_obj = is_buying_offer ? buy_offer(db) : sell_offer(db);
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
bid = asset((*offer_obj.bid_price).amount - 1, asset_id_type());
|
||||
exp_delta_agent = asset(0);
|
||||
exp_delta_bidder = asset(0);
|
||||
exp_delta_bidder2 = asset(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bid = asset((*offer_obj.bid_price).amount + 1, asset_id_type());
|
||||
exp_delta_agent = bid - (*offer_obj.bid_price);
|
||||
exp_delta_bidder = *offer_obj.bid_price;
|
||||
exp_delta_bidder2 = -bid;
|
||||
}
|
||||
|
||||
bid_operation bid_op;
|
||||
trx.operations.push_back(bid_op);
|
||||
bid_op.offer_id = offer_obj.id;
|
||||
bid_op.bid_price = bid;
|
||||
bid_op.bidder = bidder2.id;
|
||||
|
||||
trx.operations.clear();
|
||||
trx.operations.push_back(bid_op);
|
||||
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(agent_id(db), asset_id_type()(db)),
|
||||
(agent_balance + exp_delta_agent.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
|
||||
(bidder_balance + exp_delta_bidder.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bidder2_id(db), asset_id_type()(db)),
|
||||
(bidder2_balance + exp_delta_bidder2.amount).value);
|
||||
|
||||
//not empty bid
|
||||
BOOST_CHECK(offer_obj.bid_price);
|
||||
BOOST_CHECK(offer_obj.bidder);
|
||||
|
||||
// data integrity
|
||||
BOOST_CHECK(offer_obj.bidder == bidder2.id);
|
||||
BOOST_CHECK(offer_obj.transfer_agent_id == agent.id);
|
||||
BOOST_CHECK(offer_obj.maximum_price == asset(100));
|
||||
BOOST_CHECK(offer_obj.minimum_price == asset(10));
|
||||
BOOST_CHECK(offer_obj.bid_price == bid);
|
||||
});
|
||||
|
||||
const offer_object &offer_obj = *db.get_index_type<offer_index>().indices().get<by_id>().begin();
|
||||
}
|
||||
catch (fc::exception &e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(buyout_offer_test)
|
||||
{
|
||||
try
|
||||
{
|
||||
INVOKE(create_offer_test);
|
||||
const account_object &agent = get_account("agent");
|
||||
const account_object &issuer = get_account("issuer");
|
||||
const account_object &bidder = create_account("bidder", generate_private_key("bidder").get_public_key());
|
||||
|
||||
account_id_type agent_id = agent.id;
|
||||
account_id_type issuer_id = issuer.id;
|
||||
account_id_type bidder_id = bidder.id;
|
||||
|
||||
//adding whitelist
|
||||
account_whitelist_operation wop;
|
||||
wop.authorizing_account = agent.id;
|
||||
wop.account_to_list = bidder.id;
|
||||
wop.new_listing = account_whitelist_operation::white_listed;
|
||||
trx.operations.push_back(wop);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
transfer(committee_account(db), bidder, asset(10000));
|
||||
|
||||
bool params[] = {true, false};
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
const offer_object &offer_obj = is_buying_offer ? buy_offer(db) : sell_offer(db);
|
||||
|
||||
asset bid;
|
||||
asset exp_delta_agent;
|
||||
asset exp_delta_bidder;
|
||||
asset exp_delta_issuer;
|
||||
|
||||
int64_t agent_balance = get_balance(agent_id(db), asset_id_type()(db));
|
||||
int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db));
|
||||
int64_t issuer_balance = get_balance(issuer_id(db), asset_id_type()(db));
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
bid = asset(offer_obj.minimum_price.amount, asset_id_type());
|
||||
exp_delta_agent = -offer_obj.maximum_price;
|
||||
exp_delta_bidder = offer_obj.minimum_price;
|
||||
exp_delta_issuer = offer_obj.maximum_price - offer_obj.minimum_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
bid = asset(offer_obj.maximum_price.amount, asset_id_type());
|
||||
exp_delta_agent = asset(0);
|
||||
exp_delta_bidder = -offer_obj.maximum_price.amount;
|
||||
exp_delta_issuer = (offer_obj.maximum_price).amount;
|
||||
}
|
||||
|
||||
bid_operation bid_op;
|
||||
trx.operations.push_back(bid_op);
|
||||
bid_op.offer_id = offer_obj.id;
|
||||
bid_op.bid_price = bid;
|
||||
bid_op.bidder = bidder.id;
|
||||
|
||||
trx.operations.clear();
|
||||
trx.operations.push_back(bid_op);
|
||||
|
||||
PUSH_TX(db, trx, ~0);
|
||||
|
||||
offer_object cached_offer_obj = offer_obj;
|
||||
|
||||
offer_history_id_type history_id = db.get_index<offer_history_object>().get_next_id();
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(agent_id(db), asset_id_type()(db)),
|
||||
(agent_balance + exp_delta_agent.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
|
||||
(bidder_balance + exp_delta_bidder.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
|
||||
(issuer_balance + exp_delta_issuer.amount).value);
|
||||
|
||||
BOOST_CHECK(!db.find(buy_offer));
|
||||
BOOST_CHECK(!db.find(sell_offer));
|
||||
|
||||
BOOST_CHECK(db.find(history_id));
|
||||
|
||||
offer_history_object history_obj = history_id(db);
|
||||
|
||||
BOOST_CHECK(cached_offer_obj.bid_price == history_obj.bid_price);
|
||||
BOOST_CHECK(cached_offer_obj.bidder == history_obj.bidder);
|
||||
BOOST_CHECK(cached_offer_obj.buying_item == history_obj.buying_item);
|
||||
BOOST_CHECK(cached_offer_obj.issuer == history_obj.issuer);
|
||||
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price);
|
||||
BOOST_CHECK(cached_offer_obj.minimum_price == history_obj.minimum_price);
|
||||
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date);
|
||||
BOOST_CHECK(cached_offer_obj.transfer_agent_id == history_obj.transfer_agent_id);
|
||||
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
|
||||
});
|
||||
}
|
||||
catch (fc::exception &e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(expire_with_bid_offer_test)
|
||||
{
|
||||
|
||||
bool params[] = {true, false};
|
||||
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
INVOKE(bid_test);
|
||||
const offer_object &offer_obj = is_buying_offer ? buy_offer(db) : sell_offer(db);
|
||||
const account_object &agent = get_account("agent");
|
||||
const account_object &issuer = get_account("issuer");
|
||||
const account_object &bidder = get_account("bidder");
|
||||
|
||||
account_id_type agent_id = agent.id;
|
||||
account_id_type issuer_id = issuer.id;
|
||||
account_id_type bidder_id = bidder.id;
|
||||
|
||||
int64_t agent_balance = get_balance(agent_id(db), asset_id_type()(db));
|
||||
int64_t issuer_balance = get_balance(issuer_id(db), asset_id_type()(db));
|
||||
int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db));
|
||||
|
||||
asset exp_delta_agent;
|
||||
asset exp_delta_issuer;
|
||||
asset exp_delta_bidder;
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
exp_delta_agent = -offer_obj.maximum_price;
|
||||
exp_delta_issuer = offer_obj.maximum_price - *offer_obj.bid_price;
|
||||
exp_delta_bidder = *offer_obj.bid_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_delta_agent = -(*offer_obj.bid_price);
|
||||
exp_delta_issuer = *offer_obj.bid_price;
|
||||
exp_delta_bidder = asset(0);
|
||||
}
|
||||
|
||||
offer_object cached_offer_obj = offer_obj;
|
||||
|
||||
offer_history_id_type history_id = db.get_index<offer_history_object>().get_next_id();
|
||||
|
||||
generate_blocks(5);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(agent_id(db), asset_id_type()(db)),
|
||||
(agent_balance + exp_delta_agent.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
|
||||
(issuer_balance + exp_delta_issuer.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
|
||||
(bidder_balance + exp_delta_bidder.amount).value);
|
||||
|
||||
BOOST_CHECK(!db.find(buy_offer));
|
||||
BOOST_CHECK(!db.find(sell_offer));
|
||||
|
||||
BOOST_CHECK(db.find(history_id));
|
||||
|
||||
offer_history_object history_obj = history_id(db);
|
||||
|
||||
BOOST_CHECK(cached_offer_obj.bid_price == history_obj.bid_price);
|
||||
BOOST_CHECK(cached_offer_obj.bidder == history_obj.bidder);
|
||||
BOOST_CHECK(cached_offer_obj.buying_item == history_obj.buying_item);
|
||||
BOOST_CHECK(cached_offer_obj.issuer == history_obj.issuer);
|
||||
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price);
|
||||
BOOST_CHECK(cached_offer_obj.minimum_price == history_obj.minimum_price);
|
||||
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date);
|
||||
BOOST_CHECK(cached_offer_obj.transfer_agent_id == history_obj.transfer_agent_id);
|
||||
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(expire_no_bid_offer_test)
|
||||
{
|
||||
|
||||
bool params[] = {true, false};
|
||||
|
||||
std::for_each(params, params + 1, [&](bool is_buying_offer) {
|
||||
INVOKE(create_offer_test);
|
||||
const offer_object &offer_obj = is_buying_offer ? buy_offer(db) : sell_offer(db);
|
||||
const account_object &agent = get_account("agent");
|
||||
const account_object &issuer = get_account("issuer");
|
||||
|
||||
account_id_type agent_id = agent.id;
|
||||
account_id_type issuer_id = issuer.id;
|
||||
|
||||
int64_t agent_balance = get_balance(agent_id(db), asset_id_type()(db));
|
||||
int64_t issuer_balance = get_balance(issuer_id(db), asset_id_type()(db));
|
||||
|
||||
asset exp_delta_agent;
|
||||
asset exp_delta_issuer;
|
||||
|
||||
if (is_buying_offer)
|
||||
{
|
||||
exp_delta_agent = -offer_obj.maximum_price;
|
||||
exp_delta_issuer = offer_obj.maximum_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_delta_agent = asset(0);
|
||||
exp_delta_issuer = asset(0);
|
||||
}
|
||||
|
||||
offer_object cached_offer_obj = offer_obj;
|
||||
|
||||
offer_history_id_type history_id = db.get_index<offer_history_object>().get_next_id();
|
||||
|
||||
generate_blocks(5);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(agent_id(db), asset_id_type()(db)),
|
||||
(agent_balance + exp_delta_agent.amount).value);
|
||||
BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
|
||||
(issuer_balance + exp_delta_issuer.amount).value);
|
||||
|
||||
BOOST_CHECK(!db.find(buy_offer));
|
||||
BOOST_CHECK(!db.find(sell_offer));
|
||||
|
||||
BOOST_CHECK(db.find(history_id));
|
||||
|
||||
offer_history_object history_obj = history_id(db);
|
||||
|
||||
BOOST_CHECK(cached_offer_obj.bid_price == history_obj.bid_price);
|
||||
BOOST_CHECK(cached_offer_obj.bidder == history_obj.bidder);
|
||||
BOOST_CHECK(cached_offer_obj.buying_item == history_obj.buying_item);
|
||||
BOOST_CHECK(cached_offer_obj.issuer == history_obj.issuer);
|
||||
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price);
|
||||
BOOST_CHECK(cached_offer_obj.minimum_price == history_obj.minimum_price);
|
||||
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date);
|
||||
BOOST_CHECK(cached_offer_obj.transfer_agent_id == history_obj.transfer_agent_id);
|
||||
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
|
||||
});
|
||||
}
|
||||
// TODO: Write linear VBO tests
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
Loading…
Reference in a new issue