ppy marketplace 2 - batch sale, offer_object escrow

This commit is contained in:
sierra19XX 2020-06-19 15:02:03 +00:00
parent 3b4350b1c7
commit 5093b94128
8 changed files with 401 additions and 386 deletions

View file

@ -720,7 +720,7 @@ void database::finalize_expired_offers(){
++itr; ++itr;
finalize_offer_operation finalize; finalize_offer_operation finalize;
finalize.fee_paying_account = offer.transfer_agent_id; finalize.fee_paying_account = offer.issuer;
finalize.offer_id = offer.id; finalize.offer_id = offer.id;
finalize.fee = current_fee_schedule().calculate_fee( finalize ); finalize.fee = current_fee_schedule().calculate_fee( finalize );
finalize.result = offer.bidder ? result_type::Expired : result_type::ExpiredNoBid; finalize.result = offer.bidder ? result_type::Expired : result_type::ExpiredNoBid;

View file

@ -2,33 +2,37 @@
#include <graphene/chain/evaluator.hpp> #include <graphene/chain/evaluator.hpp>
#include <graphene/chain/database.hpp> #include <graphene/chain/database.hpp>
namespace graphene { namespace chain { namespace graphene
{
namespace chain
{
class offer_evaluator : public evaluator<offer_evaluator> class offer_evaluator : public evaluator<offer_evaluator>
{ {
public: public:
typedef offer_operation operation_type; typedef offer_operation operation_type;
void_result do_evaluate( const offer_operation& o ); void_result do_evaluate(const offer_operation &o);
object_id_type do_apply( 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 ); class bid_evaluator : public evaluator<bid_evaluator>
void_result do_apply( const bid_operation& o ); {
}; public:
typedef bid_operation operation_type;
class finalize_offer_evaluator : public evaluator<finalize_offer_evaluator> void_result do_evaluate(const bid_operation &o);
{ void_result do_apply(const bid_operation &o);
public: };
typedef finalize_offer_operation operation_type;
void_result do_evaluate( const finalize_offer_operation& op ); class finalize_offer_evaluator : public evaluator<finalize_offer_evaluator>
void_result do_apply( const finalize_offer_operation& op ); {
}; 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);
};
} // namespace chain
} // namespace graphene

View file

@ -2,116 +2,106 @@
#include <graphene/chain/protocol/operations.hpp> #include <graphene/chain/protocol/operations.hpp>
#include <graphene/db/generic_index.hpp> #include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain { namespace graphene
class database; {
namespace chain
{
class database;
/** /**
* @brief This class represents an offer on the object graph * @brief This class represents an offer on the object graph
* @ingroup object * @ingroup object
* @ingroup protocol * @ingroup protocol
* *
*/ */
struct by_expiration_date{}; struct by_expiration_date
class offer_object : public graphene::db::abstract_object<offer_object> {
};
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;
set<uint32_t> item_ids;
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;
set<uint32_t> item_ids;
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
{ {
public: return o1 > o2;
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 * @ingroup object_index
*/ */
typedef multi_index_container< typedef multi_index_container<
offer_object, offer_object,
indexed_by< indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >, ordered_unique<tag<by_id>, member<object, object_id_type, &object::id>>,
ordered_non_unique< ordered_non_unique<
tag<by_expiration_date>, tag<by_expiration_date>,
member< offer_object, fc::time_point_sec, &offer_object::offer_expiration_date >, member<offer_object, fc::time_point_sec, &offer_object::offer_expiration_date>,
compare_by_expiration_date compare_by_expiration_date>>>
> offer_multi_index_type;
>
> offer_multi_index_type;
typedef multi_index_container< typedef multi_index_container<
offer_history_object, offer_history_object,
indexed_by< indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >, ordered_unique<tag<by_id>, member<object, object_id_type, &object::id>>,
ordered_non_unique< ordered_non_unique<
tag<by_expiration_date>, tag<by_expiration_date>,
member< offer_history_object, fc::time_point_sec, &offer_history_object::offer_expiration_date >, member<offer_history_object, fc::time_point_sec, &offer_history_object::offer_expiration_date>,
compare_by_expiration_date compare_by_expiration_date>>>
> offer_history_multi_index_type;
>
> offer_history_multi_index_type;
/** /**
* @ingroup object_index * @ingroup object_index
*/ */
typedef generic_index<offer_object, offer_multi_index_type> offer_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; typedef generic_index<offer_history_object, offer_history_multi_index_type> offer_history_index;
}} } // namespace chain
} // namespace graphene
FC_REFLECT_DERIVED( graphene::chain::offer_object, FC_REFLECT_DERIVED(graphene::chain::offer_object,
(graphene::db::object), (graphene::db::object),
(issuer) (issuer)(item_ids)(bidder)(bid_price)(minimum_price)(maximum_price)(buying_item)(offer_expiration_date))
(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, FC_REFLECT_DERIVED(graphene::chain::offer_history_object,
(graphene::db::object), (graphene::db::object),
(issuer) (issuer)(item_ids)(bidder)(bid_price)(minimum_price)(maximum_price)(buying_item)(offer_expiration_date))
(transfer_agent_id)(item_id)
(bidder)(bid_price)
(minimum_price)(maximum_price)
(buying_item)
(offer_expiration_date)
)

View file

@ -2,105 +2,115 @@
#include <graphene/chain/protocol/base.hpp> #include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp> #include <graphene/chain/protocol/memo.hpp>
namespace graphene { namespace chain { namespace graphene
{
namespace chain
{
/* /*
* @class offer_operation * @class offer_operation
* @brief To place an offer to buy or sell an item, a user broadcasts a proposed transaction * @brief To place an offer to buy or sell an item, a user broadcasts a proposed transaction
* @ingroup operations * @ingroup operations
* @pre amount.asset_id->issuer == issuer * @pre amount.asset_id->issuer == issuer
* @pre issuer != from because this is pointless, use a normal transfer operation * @pre issuer != from because this is pointless, use a normal transfer operation
*/ */
struct offer_operation : public base_operation struct offer_operation : public base_operation
{
struct fee_parameters_type
{ {
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
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 set<uint32_t> item_ids;
// /**
// * 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 issuer; }
void validate() const;
share_type calculate_fee(const fee_parameters_type &k) const;
};
struct bid_operation : public base_operation
{
struct fee_parameters_type
{ {
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
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}; asset fee;
account_id_type bidder;
struct finalize_offer_operation : public base_operation 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
{ {
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; uint32_t price_per_kbyte = 10 * GRAPHENE_BLOCKCHAIN_PRECISION; /// only required for large memos.
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 asset fee;
account_id_type fee_paying_account;
FC_REFLECT( graphene::chain::offer_operation::fee_parameters_type, (fee)(price_per_kbyte) ); offer_id_type offer_id;
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::enum_type<uint8_t, result_type> result;
FC_REFLECT( graphene::chain::bid_operation, (fee)(bidder)(bid_price)(offer_id)(extensions) );
FC_REFLECT_ENUM( graphene::chain::result_type, (Expired)(ExpiredNoBid) ); extensions_type extensions;
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) ); account_id_type fee_payer() const { return fee_paying_account; }
void validate() const;
share_type calculate_fee(const fee_parameters_type &k) const;
};
} // namespace chain
} // namespace graphene
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)(item_ids)(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));

View file

@ -6,125 +6,143 @@
#include <graphene/chain/is_authorized_asset.hpp> #include <graphene/chain/is_authorized_asset.hpp>
#include <iostream> #include <iostream>
namespace graphene { namespace chain { namespace graphene
{
namespace chain
{
void_result offer_evaluator::do_evaluate( const offer_operation& op ) void_result offer_evaluator::do_evaluate(const offer_operation &op)
{ try { {
database& d = db(); try
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); database &d = db();
FC_ASSERT((*offer.bid_price).amount >= 0);
} else FC_ASSERT(op.offer_expiration_date > d.head_block_time());
{ FC_ASSERT(op.fee.amount >= 0);
FC_ASSERT(!offer.bidder); 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))
}
switch (op.result) { 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);
}
const auto &offer_obj = db().create<offer_object>([&](offer_object &obj) {
obj.issuer = o.issuer;
obj.item_ids = o.item_ids;
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.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(op.bidder, -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);
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::Expired:
case result_type::ExpiredNoBid: case result_type::ExpiredNoBid:
FC_ASSERT(offer.offer_expiration_date <= d.head_block_time()); FC_ASSERT(offer.offer_expiration_date <= d.head_block_time());
break; break;
default: default:
FC_THROW_EXCEPTION( fc::assert_exception, "finalize_offer_operation: unknown result type." ); FC_THROW_EXCEPTION(fc::assert_exception, "finalize_offer_operation: unknown result type.");
break; break;
}
return void_result();
} }
FC_CAPTURE_AND_RETHROW((op))
}
return void_result(); void_result finalize_offer_evaluator::do_apply(const finalize_offer_operation &op)
} FC_CAPTURE_AND_RETHROW( (op) ) } {
database &d = db();
void_result finalize_offer_evaluator::do_apply(const finalize_offer_operation& op) {
database& d = db();
offer_object offer = op.offer_id(d); offer_object offer = op.offer_id(d);
@ -133,41 +151,36 @@ void_result finalize_offer_evaluator::do_apply(const finalize_offer_operation& o
if (offer.buying_item) if (offer.buying_item)
{ {
d.adjust_balance(*offer.bidder, *offer.bid_price); 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) if (offer.bid_price < offer.maximum_price)
{ {
d.adjust_balance(offer.issuer, offer.maximum_price - *offer.bid_price); d.adjust_balance(offer.issuer, offer.maximum_price - *offer.bid_price);
} }
} else }
else
{ {
d.adjust_balance(offer.transfer_agent_id, -(*offer.bid_price));
d.adjust_balance(offer.issuer, *offer.bid_price); d.adjust_balance(offer.issuer, *offer.bid_price);
} }
} else }
else
{ {
if (offer.buying_item) if (offer.buying_item)
{ {
d.adjust_balance(offer.issuer, offer.maximum_price); 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 ) { d.create<offer_history_object>([&](offer_history_object &obj) {
obj.issuer = offer.issuer; obj.issuer = offer.issuer;
obj.item_ids = offer.item_ids;
obj.transfer_agent_id = offer.transfer_agent_id; obj.bidder = offer.bidder;
obj.item_id = offer.item_id; obj.bid_price = offer.bid_price;
obj.bidder = offer.bidder; obj.minimum_price = offer.minimum_price;
obj.bid_price = offer.bid_price; obj.maximum_price = offer.maximum_price;
obj.minimum_price = offer.minimum_price; obj.buying_item = offer.buying_item;
obj.maximum_price = offer.maximum_price; obj.offer_expiration_date = offer.offer_expiration_date;
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)); d.remove(op.offer_id(d));
return void_result(); return void_result();
} }
} } // namespace chain
} } // namespace graphene

View file

@ -1,46 +1,49 @@
#include <graphene/chain/protocol/offer.hpp> #include <graphene/chain/protocol/offer.hpp>
namespace graphene { namespace chain { namespace graphene
share_type offer_operation::calculate_fee( const fee_parameters_type& schedule )const
{ {
share_type core_fee_required = schedule.fee; namespace chain
return core_fee_required;
}
void offer_operation::validate()const
{ {
FC_ASSERT( item_id > 0 ); share_type offer_operation::calculate_fee(const fee_parameters_type &schedule) const
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; share_type core_fee_required = schedule.fee;
return core_fee_required; return core_fee_required;
} }
void offer_operation::validate() const
void bid_operation::validate()const
{ {
FC_ASSERT( fee.amount.value >= 0 ); for (const auto &item_id : item_ids)
FC_ASSERT( bid_price.amount.value >= 0 ); {
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);
} }
void finalize_offer_operation::validate() const { share_type bid_operation::calculate_fee(const fee_parameters_type &schedule) const
FC_ASSERT ( offer_id != offer_id_type() ); {
FC_ASSERT( fee.amount.value >= 0 ); share_type core_fee_required = schedule.fee;
return core_fee_required;
} }
share_type finalize_offer_operation::calculate_fee( const fee_parameters_type& k) const { void bid_operation::validate() const
share_type core_fee_required = k.fee; {
return core_fee_required; FC_ASSERT(fee.amount.value >= 0);
FC_ASSERT(bid_price.amount.value >= 0);
} }
void finalize_offer_operation::validate() const
{
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;
}
} // namespace chain
} // namespace graphene

View file

@ -43,6 +43,7 @@
#include <graphene/chain/event_group_object.hpp> #include <graphene/chain/event_group_object.hpp>
#include <graphene/chain/event_object.hpp> #include <graphene/chain/event_object.hpp>
#include <graphene/chain/tournament_object.hpp> #include <graphene/chain/tournament_object.hpp>
#include <graphene/chain/offer_object.hpp>
#include <graphene/utilities/tempdir.hpp> #include <graphene/utilities/tempdir.hpp>
@ -307,7 +308,21 @@ void database_fixture::verify_asset_supplies( const database& db )
total_balances[betting_market_group.asset_id] += o.fees_collected; total_balances[betting_market_group.asset_id] += o.fees_collected;
} }
for (const offer_object &o : db.get_index_type<offer_index>().indices())
{
if (o.buying_item)
{
total_balances[o.maximum_price.asset_id] += o.maximum_price.amount;
}
else
{
if (o.bid_price)
{
total_balances[o.bid_price->asset_id] += o.bid_price->amount;
}
}
}
uint64_t sweeps_vestings = 0; uint64_t sweeps_vestings = 0;
for( const sweeps_vesting_balance_object& svbo: db.get_index_type< sweeps_vesting_balance_index >().indices() ) for( const sweeps_vesting_balance_object& svbo: db.get_index_type< sweeps_vesting_balance_index >().indices() )
sweeps_vestings += svbo.balance; sweeps_vestings += svbo.balance;

View file

@ -1845,12 +1845,12 @@ BOOST_AUTO_TEST_CASE(create_offer_test)
std::for_each(params, params + 1, [&](bool is_buying_offer) { std::for_each(params, params + 1, [&](bool is_buying_offer) {
offer_operation offer_op; offer_operation offer_op;
offer_op.item_id = 13; offer_op.item_ids.emplace(13);
offer_op.item_ids.emplace(14);
offer_op.issuer = issuer.id; offer_op.issuer = issuer.id;
offer_op.buying_item = is_buying_offer; offer_op.buying_item = is_buying_offer;
offer_op.maximum_price = asset(100); offer_op.maximum_price = asset(100);
offer_op.minimum_price = asset(10); offer_op.minimum_price = asset(10);
offer_op.transfer_agent_id = agent.id;
// +1 second // +1 second
offer_op.offer_expiration_date = db.head_block_time() + fc::microseconds(3000000); offer_op.offer_expiration_date = db.head_block_time() + fc::microseconds(3000000);
@ -1888,7 +1888,6 @@ BOOST_AUTO_TEST_CASE(create_offer_test)
BOOST_CHECK(d.issuer == issuer.id); BOOST_CHECK(d.issuer == issuer.id);
BOOST_CHECK(d.maximum_price == asset(100)); BOOST_CHECK(d.maximum_price == asset(100));
BOOST_CHECK(d.minimum_price == asset(10)); BOOST_CHECK(d.minimum_price == asset(10));
BOOST_CHECK(d.transfer_agent_id == agent.id);
BOOST_CHECK(d.buying_item == is_buying_offer); BOOST_CHECK(d.buying_item == is_buying_offer);
if (is_buying_offer) if (is_buying_offer)
@ -1930,9 +1929,6 @@ BOOST_AUTO_TEST_CASE(bid_test)
bid_op.bidder = bidder.id; bid_op.bidder = bidder.id;
trx.operations.push_back(bid_op); trx.operations.push_back(bid_op);
// exception due to empty whitelist
GRAPHENE_REQUIRE_THROW(PUSH_TX(db, trx, ~0), fc::exception);
trx.operations.clear(); trx.operations.clear();
//adding whitelist //adding whitelist
@ -1952,7 +1948,6 @@ BOOST_AUTO_TEST_CASE(bid_test)
asset exp_delta_agent; asset exp_delta_agent;
asset exp_delta_bidder; 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 issuer_balance = get_balance(issuer_id(db), asset_id_type()(db));
int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db)); int64_t bidder_balance = get_balance(bidder_id(db), asset_id_type()(db));
@ -1985,8 +1980,6 @@ BOOST_AUTO_TEST_CASE(bid_test)
PUSH_TX(db, trx, ~0); 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)), BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
(bidder_balance + exp_delta_bidder.amount).value); (bidder_balance + exp_delta_bidder.amount).value);
@ -1997,7 +1990,6 @@ BOOST_AUTO_TEST_CASE(bid_test)
// data integrity // data integrity
BOOST_CHECK(offer_obj.bidder == bidder.id); BOOST_CHECK(offer_obj.bidder == bidder.id);
BOOST_CHECK(offer_obj.issuer == issuer.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.maximum_price == asset(100));
BOOST_CHECK(offer_obj.minimum_price == asset(10)); BOOST_CHECK(offer_obj.minimum_price == asset(10));
BOOST_CHECK(offer_obj.bid_price == bid); BOOST_CHECK(offer_obj.bid_price == bid);
@ -2072,8 +2064,6 @@ BOOST_AUTO_TEST_CASE(second_bid_test)
PUSH_TX(db, trx, ~0); 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)), BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
(bidder_balance + exp_delta_bidder.amount).value); (bidder_balance + exp_delta_bidder.amount).value);
BOOST_CHECK_EQUAL(get_balance(bidder2_id(db), asset_id_type()(db)), BOOST_CHECK_EQUAL(get_balance(bidder2_id(db), asset_id_type()(db)),
@ -2085,7 +2075,6 @@ BOOST_AUTO_TEST_CASE(second_bid_test)
// data integrity // data integrity
BOOST_CHECK(offer_obj.bidder == bidder2.id); 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.maximum_price == asset(100));
BOOST_CHECK(offer_obj.minimum_price == asset(10)); BOOST_CHECK(offer_obj.minimum_price == asset(10));
BOOST_CHECK(offer_obj.bid_price == bid); BOOST_CHECK(offer_obj.bid_price == bid);
@ -2168,8 +2157,6 @@ BOOST_AUTO_TEST_CASE(buyout_offer_test)
generate_block(); 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)), BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
(bidder_balance + exp_delta_bidder.amount).value); (bidder_balance + exp_delta_bidder.amount).value);
BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)), BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
@ -2189,8 +2176,7 @@ BOOST_AUTO_TEST_CASE(buyout_offer_test)
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price); 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.minimum_price == history_obj.minimum_price);
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date); 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_ids == history_obj.item_ids);
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
}); });
} }
catch (fc::exception &e) catch (fc::exception &e)
@ -2243,8 +2229,6 @@ BOOST_AUTO_TEST_CASE(expire_with_bid_offer_test)
generate_blocks(5); 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)), BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
(issuer_balance + exp_delta_issuer.amount).value); (issuer_balance + exp_delta_issuer.amount).value);
BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)), BOOST_CHECK_EQUAL(get_balance(bidder_id(db), asset_id_type()(db)),
@ -2264,8 +2248,7 @@ BOOST_AUTO_TEST_CASE(expire_with_bid_offer_test)
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price); 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.minimum_price == history_obj.minimum_price);
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date); 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_ids == history_obj.item_ids);
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
}); });
} }
@ -2306,8 +2289,6 @@ BOOST_AUTO_TEST_CASE(expire_no_bid_offer_test)
generate_blocks(5); 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)), BOOST_CHECK_EQUAL(get_balance(issuer_id(db), asset_id_type()(db)),
(issuer_balance + exp_delta_issuer.amount).value); (issuer_balance + exp_delta_issuer.amount).value);
@ -2325,8 +2306,7 @@ BOOST_AUTO_TEST_CASE(expire_no_bid_offer_test)
BOOST_CHECK(cached_offer_obj.maximum_price == history_obj.maximum_price); 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.minimum_price == history_obj.minimum_price);
BOOST_CHECK(cached_offer_obj.offer_expiration_date == history_obj.offer_expiration_date); 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_ids == history_obj.item_ids);
BOOST_CHECK(cached_offer_obj.item_id == history_obj.item_id);
}); });
} }
// TODO: Write linear VBO tests // TODO: Write linear VBO tests