merge from master, clean up test output

This commit is contained in:
Daniel Larimer 2015-06-18 15:40:38 -04:00
commit a14500a364
41 changed files with 603 additions and 1948 deletions

View file

@ -215,22 +215,6 @@ namespace graphene { namespace app {
return result;
}
vector<short_order_object> database_api::get_short_orders(asset_id_type a, uint32_t limit)const
{
const auto& short_order_idx = _db.get_index_type<short_order_index>();
const auto& sell_price_idx = short_order_idx.indices().get<by_price>();
const asset_object& mia = _db.get(a);
FC_ASSERT( mia.is_market_issued(), "must be a market issued asset" );
price index_price = price::min(mia.get_id(), mia.bitasset_data(_db).options.short_backing_asset);
auto short_itr = sell_price_idx.lower_bound(index_price.max());
auto short_end = sell_price_idx.upper_bound(index_price.min());
return vector<short_order_object>(short_itr, short_end);
}
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
{
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
@ -358,15 +342,11 @@ namespace graphene { namespace app {
case operation::tag<limit_order_create_operation>::value:
market = op.op.get<limit_order_create_operation>().get_market();
break;
case operation::tag<short_order_create_operation>::value:
market = op.op.get<limit_order_create_operation>().get_market();
break;
case operation::tag<fill_order_operation>::value:
market = op.op.get<fill_order_operation>().get_market();
break;
/*
case operation::tag<limit_order_cancel_operation>::value:
case operation::tag<short_order_cancel_operation>::value:
*/
default: break;
}

View file

@ -400,13 +400,13 @@ application::~application()
{
if( my->_p2p_network )
{
ilog("Closing p2p node");
//ilog("Closing p2p node");
my->_p2p_network->close();
my->_p2p_network.reset();
}
if( my->_chain_db )
{
ilog("Closing chain database");
//ilog("Closing chain database");
my->_chain_db->close();
}
}

View file

@ -22,7 +22,7 @@
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/key_object.hpp>
#include <graphene/net/node.hpp>
#include <fc/api.hpp>
@ -142,13 +142,6 @@ namespace graphene { namespace app {
* @return The limit orders, ordered from least price to greatest
*/
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
/**
* @brief Get short orders in a given asset
* @param a ID of asset being sold
* @param limit Maximum number of orders to retrieve
* @return The short orders, ordered from least price to greatest
*/
vector<short_order_object> get_short_orders(asset_id_type a, uint32_t limit)const;
/**
* @brief Get call orders in a given asset
* @param a ID of asset being called
@ -342,7 +335,6 @@ FC_API(graphene::app::database_api,
(get_named_account_balances)
(lookup_asset_symbols)
(get_limit_orders)
(get_short_orders)
(get_call_orders)
(get_settle_orders)
(list_assets)

View file

@ -16,7 +16,7 @@ add_library( graphene_chain
asset_evaluator.cpp
transfer_evaluator.cpp
proposal_evaluator.cpp
short_order_evaluator.cpp
call_order_evaluator.cpp
limit_order_evaluator.cpp
vesting_balance_evaluator.cpp
withdraw_permission_evaluator.cpp

View file

@ -101,13 +101,13 @@ namespace graphene { namespace chain {
price price::min( asset_id_type base, asset_id_type quote ) { return asset( 1, base ) / asset( GRAPHENE_MAX_SHARE_SUPPLY, quote); }
price price::call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio)
{
{ try {
fc::uint128 tmp( collateral.amount.value );
tmp *= collateral_ratio - 1000;
tmp /= 1000;
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
return asset( tmp.to_uint64(), collateral.asset_id) / debt;
}
} FC_CAPTURE_AND_RETHROW( (debt)(collateral)(collateral_ratio) ) }
bool price::is_null() const { return *this == price(); }
@ -120,20 +120,10 @@ namespace graphene { namespace chain {
void price_feed::validate() const
{ try {
if( !call_limit.is_null() )
call_limit.validate();
if( !short_limit.is_null() )
short_limit.validate();
if( !settlement_price.is_null() )
settlement_price.validate();
FC_ASSERT( call_limit.is_null() == short_limit.is_null() );
FC_ASSERT( call_limit.base.asset_id == short_limit.quote.asset_id );
FC_ASSERT( call_limit.quote.asset_id == short_limit.base.asset_id );
FC_ASSERT( max_margin_period_sec > 0 );
FC_ASSERT( required_maintenance_collateral < required_initial_collateral );
FC_ASSERT( required_maintenance_collateral >= 1000 );
FC_ASSERT( call_limit.is_null() || call_limit < ~short_limit );
} FC_CAPTURE_AND_RETHROW( (call_limit.is_null())(short_limit.is_null())(call_limit)(short_limit)
(max_margin_period_sec)(required_maintenance_collateral)(required_initial_collateral) ) }
FC_ASSERT( maximum_short_squeeze_ratio >= 1000 );
FC_ASSERT( maintenance_collateral_ratio >= maximum_short_squeeze_ratio );
} FC_CAPTURE_AND_RETHROW( (*this) ) }
} } // graphene::chain

View file

@ -18,7 +18,7 @@
#include <graphene/chain/asset_evaluator.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/database.hpp>
#include <functional>
@ -365,16 +365,17 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
{ try {
database& d = db();
const asset_object& quote = o.asset_id(d);
const asset_object& base = o.asset_id(d);
//Verify that this feed is for a market-issued asset and that asset is backed by the base
FC_ASSERT(quote.is_market_issued());
FC_ASSERT(base.is_market_issued());
const asset_bitasset_data_object& bitasset = quote.bitasset_data(d);
FC_ASSERT(bitasset.options.short_backing_asset == o.feed.call_limit.base.asset_id);
const asset_bitasset_data_object& bitasset = base.bitasset_data(d);
FC_ASSERT(bitasset.options.short_backing_asset == o.feed.settlement_price.quote.asset_id);
//Verify that the publisher is authoritative to publish a feed
if( quote.issuer == account_id_type() )
if( base.issuer == account_id_type() )
{
//It's a delegate-fed asset. Verify that publisher is an active delegate or witness.
// TODO: replace account_id_type with global variable for delegates account id
FC_ASSERT(d.get(account_id_type()).active.auths.count(o.publisher) ||
d.get_global_properties().witness_accounts.count(o.publisher));
} else {
@ -388,9 +389,9 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope
{ try {
database& d = db();
const asset_object& quote = o.asset_id(d);
const asset_object& base = o.asset_id(d);
// Store medians for this asset
d.modify(quote.bitasset_data(d), [&o,&d](asset_bitasset_data_object& a) {
d.modify(base.bitasset_data(d), [&o,&d](asset_bitasset_data_object& a) {
a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed);
a.update_median_feeds(d.head_block_time());
});

View file

@ -32,7 +32,6 @@ namespace graphene { namespace chain {
void block_database::open( const fc::path& dbdir )
{ try {
idump((sizeof(index_entry)) );
fc::create_directories(dbdir);
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/database.hpp>
#include <graphene/chain/call_order_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
void_result call_order_update_evaluator::do_evaluate(const call_order_update_operation& o)
{ try {
database& d = db();
_paying_account = &o.funding_account(d);
_debt_asset = &o.delta_debt.asset_id(d);
FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.",
("sym", _debt_asset->symbol) );
_bitasset_data = &_debt_asset->bitasset_data(d);
FC_ASSERT( o.delta_collateral.asset_id == _bitasset_data->options.short_backing_asset );
if( _bitasset_data->is_prediction_market )
FC_ASSERT( o.delta_collateral.amount == o.delta_debt.amount );
else
FC_ASSERT( !_bitasset_data->current_feed.settlement_price.is_null() );
if( o.delta_debt.amount < 0 )
{
FC_ASSERT( d.get_balance(*_paying_account, *_debt_asset) >= o.delta_debt,
"Cannot cover by ${c} when payer only has ${b}",
("c", o.delta_debt.amount)("b", d.get_balance(*_paying_account, *_debt_asset).amount) );
}
if( o.delta_collateral.amount > 0 )
{
FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= o.delta_collateral,
"Cannot increase collateral by ${c} when payer only has ${b}", ("c", o.delta_collateral.amount)
("b", d.get_balance(*_paying_account, o.delta_collateral.asset_id(d)).amount) );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result call_order_update_evaluator::do_apply(const call_order_update_operation& o)
{
database& d = db();
//wdump( (_bitasset_data->current_feed) );
if( o.delta_debt.amount != 0 )
{
d.adjust_balance( o.funding_account, o.delta_debt );
// Deduct the debt paid from the total supply of the debt asset.
d.modify(_debt_asset->dynamic_asset_data_id(d), [&](asset_dynamic_data_object& dynamic_asset) {
dynamic_asset.current_supply += o.delta_debt.amount;
assert(dynamic_asset.current_supply >= 0);
});
}
if( o.delta_collateral.amount != 0 )
{
d.adjust_balance( o.funding_account, -o.delta_collateral );
// Adjust the total core in orders accodingly
if( o.delta_collateral.asset_id == asset_id_type() )
{
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
stats.total_core_in_orders += o.delta_collateral.amount;
});
}
}
auto& call_idx = d.get_index_type<call_order_index>().indices().get<by_account>();
auto itr = call_idx.find( boost::make_tuple(o.funding_account, o.delta_debt.asset_id) );
const call_order_object* call_obj = nullptr;
if( itr == call_idx.end() )
{
FC_ASSERT( o.delta_collateral.amount > 0 );
FC_ASSERT( o.delta_debt.amount > 0 );
call_obj = &d.create<call_order_object>( [&](call_order_object& call ){
call.borrower = o.funding_account;
call.collateral = o.delta_collateral.amount;
call.debt = o.delta_debt.amount;
call.call_price = ~o.call_price;
});
}
else
{
call_obj = &*itr;
d.modify( *call_obj, [&]( call_order_object& call ){
call.collateral += o.delta_collateral.amount;
call.debt += o.delta_debt.amount;
call.call_price = ~o.call_price;
});
}
auto debt = call_obj->get_debt();
if( debt.amount == 0 )
{
FC_ASSERT( call_obj->collateral == 0 );
d.remove( *call_obj );
return void_result();
}
auto collateral = call_obj->get_collateral();
auto mp = _bitasset_data->current_feed.maintenance_price();
// edump((debt)(collateral)((debt/collateral).to_real())(mp.to_real()) );
// edump((debt*mp));
/// paying off the debt at the user specified call price should require
/// less collateral than paying off the debt at the maitenance price
auto col_at_call_price = debt * o.call_price;
auto col_at_min_callprice = debt * mp;
FC_ASSERT( col_at_call_price <= col_at_min_callprice, "", ("debt*o.callprice",debt*o.call_price)("debt*mp",debt*mp) );
FC_ASSERT( col_at_call_price <= collateral );
//wdump( (o.call_price)(mp)(call_obj->call_price.to_real())(mp.to_real()) );
//FC_ASSERT( call_obj->call_price <= mp );
auto call_order_id = call_obj->id;
//ilog( "checking call orders" );
// check to see if the order needs to be margin called now, but don't allow black swans and require there to be
// limit orders available that could be used to fill the order.
if( d.check_call_orders( *_debt_asset, false ) )
{
FC_ASSERT( !d.find_object( call_order_id ), "If updating the call order triggers a margin call, then it must completely cover the order" );
}
return void_result();
}
} } // graphene::chain

View file

@ -99,7 +99,7 @@ bool database::_push_block( const signed_block& new_block )
//If the head block from the longest chain does not build off of the current head, we need to switch forks.
if( new_head->data.previous != head_block_id() )
{
edump((new_head->data.previous));
//edump((new_head->data.previous));
//If the newly pushed block is the same height as head, we get head back in new_head
//Only switch forks if new_head is actually higher than head
if( new_head->data.block_num() > head_block_num() )
@ -107,11 +107,11 @@ bool database::_push_block( const signed_block& new_block )
auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous );
for( auto item : branches.first )
{
wdump( ("new")(item->id)(item->data.previous) );
// wdump( ("new")(item->id)(item->data.previous) );
}
for( auto item : branches.second )
{
wdump( ("old")(item->id)(item->data.previous) );
// wdump( ("old")(item->id)(item->data.previous) );
}
// pop blocks until we hit the forked block
@ -131,9 +131,9 @@ bool database::_push_block( const signed_block& new_block )
catch ( const fc::exception& e ) { except = e; }
if( except )
{
wdump((except->to_detail_string()));
elog( "Encountered error when switching to a longer fork at id ${id}. Going back.",
("id", (*ritr)->id) );
//wdump((except->to_detail_string()));
// elog( "Encountered error when switching to a longer fork at id ${id}. Going back.",
// ("id", (*ritr)->id) );
// remove the rest of branches.first from the fork_db, those blocks are invalid
while( ritr != branches.first.rend() )
{
@ -239,8 +239,8 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
return std::make_pair(id, authority::owner);
});
ilog("Attempting to push proposal ${prop}", ("prop", proposal));
idump((eval_state.approved_by));
//ilog("Attempting to push proposal ${prop}", ("prop", proposal));
//idump((eval_state.approved_by));
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
processed_transaction ptrx(proposal.proposed_transaction);

View file

@ -21,7 +21,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/witness_object.hpp>
@ -60,13 +60,6 @@ void database::debug_dump()
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
total_balances[for_sale.asset_id] += for_sale.amount;
}
for( const short_order_object& o : db.get_index_type<short_order_index>().indices() )
{
idump(("short_order")(o));
auto col = o.get_collateral();
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
total_balances[col.asset_id] += col.amount;
}
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
{
idump(("call_order")(o));

View file

@ -26,7 +26,7 @@
#include <graphene/chain/key_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
@ -42,7 +42,7 @@
#include <graphene/chain/key_evaluator.hpp>
#include <graphene/chain/limit_order_evaluator.hpp>
#include <graphene/chain/proposal_evaluator.hpp>
#include <graphene/chain/short_order_evaluator.hpp>
#include <graphene/chain/call_order_evaluator.hpp>
#include <graphene/chain/transfer_evaluator.hpp>
#include <graphene/chain/vesting_balance_evaluator.hpp>
#include <graphene/chain/withdraw_permission_evaluator.hpp>
@ -75,8 +75,6 @@ void database::initialize_evaluators()
register_evaluator<asset_global_settle_evaluator>();
register_evaluator<limit_order_create_evaluator>();
register_evaluator<limit_order_cancel_evaluator>();
register_evaluator<short_order_create_evaluator>();
register_evaluator<short_order_cancel_evaluator>();
register_evaluator<call_order_update_evaluator>();
register_evaluator<transfer_evaluator>();
register_evaluator<asset_fund_fee_pool_evaluator>();
@ -108,7 +106,6 @@ void database::initialize_indexes()
add_index< primary_index<simple_index<delegate_object>> >();
add_index< primary_index<simple_index<witness_object>> >();
add_index< primary_index<limit_order_index > >();
add_index< primary_index<short_order_index > >();
add_index< primary_index<call_order_index > >();
add_index< primary_index<proposal_index > >();
add_index< primary_index<withdraw_permission_index > >();
@ -295,9 +292,9 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}
}
fc::microseconds duration = fc::time_point::now() - start_time;
ilog("Finished allocating to ${n} accounts in ${t} milliseconds.",
("n", genesis_state.allocation_targets.size())("t", duration.count() / 1000));
// fc::microseconds duration = fc::time_point::now() - start_time;
// ilog("Finished allocating to ${n} accounts in ${t} milliseconds.",
// ("n", genesis_state.allocation_targets.size())("t", duration.count() / 1000));
}
flat_set<delegate_id_type> init_delegates;

View file

@ -52,7 +52,7 @@ vector<std::reference_wrapper<const ObjectType>> database::sort_votable_objects(
void database::pay_workers( share_type& budget )
{
ilog("Processing payroll! Available budget is ${b}", ("b", budget));
// ilog("Processing payroll! Available budget is ${b}", ("b", budget));
vector<std::reference_wrapper<const worker_object>> active_workers;
get_index_type<worker_index>().inspect_all_objects([this, &active_workers](const object& o) {
const worker_object& w = static_cast<const worker_object&>(o);
@ -78,7 +78,7 @@ void database::pay_workers( share_type& budget )
}
share_type actual_pay = std::min(budget, requested_pay);
ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
//ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
modify(active_worker, [&](worker_object& w) {
w.worker.visit(worker_pay_visitor(actual_pay, *this));
});

View file

@ -35,14 +35,13 @@ database::~database(){
void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation )
{ try {
ilog("Open database in ${d}", ("d", data_dir));
object_database::open(data_dir);
object_database::open( data_dir );
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
if( !find(global_property_id_type()) )
{
ilog( "Init Genesis State" );
// ilog( "Init Genesis State" );
init_genesis(initial_allocation);
}

View file

@ -21,7 +21,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <fc/uint128.hpp>
@ -69,9 +69,10 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett
const limit_order_index& limit_index = get_index_type<limit_order_index>();
const auto& limit_price_index = limit_index.indices().get<by_price>();
auto max_short_squeeze = bitasset.current_feed.max_short_squeeze_price();
// cancel all orders selling the market issued asset
auto limit_itr = limit_price_index.lower_bound(price::max(mia.id, bitasset.options.short_backing_asset));
auto limit_end = limit_price_index.upper_bound(~bitasset.current_feed.call_limit);
auto limit_end = limit_price_index.upper_bound(~max_short_squeeze);
while( limit_itr != limit_end )
{
const auto& order = *limit_itr;
@ -225,10 +226,6 @@ int database::match( const limit_order_object& bid, const limit_order_object& as
return match<limit_order_object>( bid, ask, match_price );
}
int database::match( const limit_order_object& bid, const short_order_object& ask, const price& match_price )
{
return match<short_order_object>( bid, ask, match_price );
}
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price,
asset max_settlement )
@ -290,107 +287,6 @@ bool database::fill_order( const limit_order_object& order, const asset& pays, c
}
}
bool database::fill_order( const short_order_object& order, const asset& pays, const asset& receives )
{ try {
assert( order.amount_for_sale().asset_id == pays.asset_id );
assert( pays.asset_id != receives.asset_id );
const call_order_index& call_index = get_index_type<call_order_index>();
const account_object& seller = order.seller(*this);
const asset_object& recv_asset = receives.asset_id(*this);
const asset_object& pays_asset = pays.asset_id(*this);
assert( pays_asset.is_market_issued() );
auto issuer_fees = pay_market_fees( recv_asset, receives );
bool filled = pays == order.amount_for_sale();
asset seller_to_collateral;
if( (*pays_asset.bitasset_data_id)(*this).is_prediction_market )
{
assert( pays.amount >= receives.amount );
seller_to_collateral = pays.amount - receives.amount;
}
else
{
seller_to_collateral = filled ? order.get_collateral() : pays * order.sell_price;
}
auto buyer_to_collateral = receives - issuer_fees;
if( receives.asset_id == asset_id_type() )
{
const auto& statistics = seller.statistics(*this);
modify( statistics, [&]( account_statistics_object& b ){
b.total_core_in_orders += buyer_to_collateral.amount;
});
}
modify( pays_asset.dynamic_asset_data_id(*this), [&]( asset_dynamic_data_object& obj ){
obj.current_supply += pays.amount;
});
const auto& call_account_index = call_index.indices().get<by_account>();
auto call_itr = call_account_index.find( boost::make_tuple(order.seller, pays.asset_id) );
if( call_itr == call_account_index.end() )
{
create<call_order_object>( [&]( call_order_object& c ){
c.borrower = seller.id;
c.collateral = seller_to_collateral.amount + buyer_to_collateral.amount;
c.debt = pays.amount;
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
c.call_price = price::max(seller_to_collateral.asset_id, pays.asset_id);
c.update_call_price();
});
}
else
{
modify( *call_itr, [&]( call_order_object& c ){
c.debt += pays.amount;
c.collateral += seller_to_collateral.amount + buyer_to_collateral.amount;
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
c.update_call_price();
});
}
if( filled )
{
remove( order );
}
else
{
modify( order, [&]( short_order_object& b ) {
b.for_sale -= pays.amount;
b.available_collateral -= seller_to_collateral.amount;
assert( b.available_collateral > 0 );
assert( b.for_sale > 0 );
});
/**
* There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we
* have hit the limit where the seller is asking for nothing in return. When this
* happens we must refund any balance back to the seller, it is too small to be
* sold at the sale price.
*/
if( order.amount_to_receive().amount == 0 )
{
adjust_balance(seller.get_id(), order.get_collateral());
if( order.get_collateral().asset_id == asset_id_type() )
{
const auto& statistics = seller.statistics(*this);
modify( statistics, [&]( account_statistics_object& b ){
b.total_core_in_orders -= order.available_collateral;
});
}
remove( order );
filled = true;
}
}
push_applied_operation( fill_order_operation{ order.id, order.seller, pays, receives, issuer_fees } );
return filled;
} FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives )
{ try {
@ -468,13 +364,22 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa
} FC_CAPTURE_AND_RETHROW( (settle)(pays)(receives) ) }
/**
* Starting with the least collateralized orders, fill them if their
* call price is above the max(lowest bid,call_limit).
*
* This method will return true if it filled a short or limit
*
* @param mia - the market issued asset that should be called.
* @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw
* if enable_black_swan is not set to true.
*
* @return true if a margin call was executed.
*/
bool database::check_call_orders( const asset_object& mia )
bool database::check_call_orders( const asset_object& mia, bool enable_black_swan )
{ try {
if( !mia.is_market_issued() ) return false;
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
if( bitasset.current_feed.call_limit.is_null() ) return false;
if( bitasset.current_feed.settlement_price.is_null() ) return false;
if( bitasset.is_prediction_market ) return false;
const call_order_index& call_index = get_index_type<call_order_index>();
@ -483,14 +388,42 @@ bool database::check_call_orders( const asset_object& mia )
const limit_order_index& limit_index = get_index_type<limit_order_index>();
const auto& limit_price_index = limit_index.indices().get<by_price>();
const short_order_index& short_index = get_index_type<short_order_index>();
const auto& short_price_index = short_index.indices().get<by_price>();
auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
auto min_price = bitasset.current_feed.max_short_squeeze_price();
/*
if( require_orders )
{
for( const auto& order : limit_price_index )
wdump((order)(order.sell_price.to_real()));
auto short_itr = short_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
auto short_end = short_price_index.upper_bound( ~bitasset.current_feed.call_limit );
for( const auto& call : call_price_index )
idump((call)(call.call_price.to_real()));
auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
auto limit_end = limit_price_index.upper_bound( ~bitasset.current_feed.call_limit );
// limit pirce index is sorted from highest price to lowest price.
//auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
wdump((max_price)(max_price.to_real()));
wdump((min_price)(min_price.to_real()));
}
*/
FC_ASSERT( max_price.base.asset_id == min_price.base.asset_id );
// wlog( "from ${a} Debt/Col to ${b} Debt/Col ", ("a", max_price.to_real())("b",min_price.to_real()) );
// NOTE limit_price_index is sorted from greatest to least
auto limit_itr = limit_price_index.lower_bound( max_price );
auto limit_end = limit_price_index.upper_bound( min_price );
/*
if( limit_itr != limit_price_index.end() )
wdump((*limit_itr)(limit_itr->sell_price.to_real()));
if( limit_end != limit_price_index.end() )
wdump((*limit_end)(limit_end->sell_price.to_real()));
*/
if( limit_itr == limit_end )
{
//wlog( "no orders available to fill margin calls" );
return false;
}
auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );
@ -499,33 +432,14 @@ bool database::check_call_orders( const asset_object& mia )
while( call_itr != call_end )
{
bool current_is_limit = true;
bool filled_call = false;
price match_price;
asset usd_for_sale;
if( limit_itr != limit_end )
{
assert( limit_itr != limit_price_index.end() );
if( short_itr != short_end && limit_itr->sell_price < short_itr->sell_price )
{
assert( short_itr != short_price_index.end() );
current_is_limit = false;
match_price = short_itr->sell_price;
usd_for_sale = short_itr->amount_for_sale();
}
else
{
current_is_limit = true;
match_price = limit_itr->sell_price;
usd_for_sale = limit_itr->amount_for_sale();
}
}
else if( short_itr != short_end )
{
assert( short_itr != short_price_index.end() );
current_is_limit = false;
match_price = short_itr->sell_price;
usd_for_sale = short_itr->amount_for_sale();
match_price = limit_itr->sell_price;
usd_for_sale = limit_itr->amount_for_sale();
}
else return filled_short_or_limit;
@ -540,6 +454,7 @@ bool database::check_call_orders( const asset_object& mia )
if( usd_to_buy * match_price > call_itr->get_collateral() )
{
FC_ASSERT( enable_black_swan );
elog( "black swan, we do not have enough collateral to cover at this price" );
globally_settle_asset( mia, call_itr->get_debt() / call_itr->get_collateral() );
return true;
@ -569,16 +484,9 @@ bool database::check_call_orders( const asset_object& mia )
auto old_call_itr = call_itr;
if( filled_call ) ++call_itr;
fill_order( *old_call_itr, call_pays, call_receives );
if( current_is_limit )
{
auto old_limit_itr = !filled_call ? limit_itr++ : limit_itr;
fill_order( *old_limit_itr, order_pays, order_receives );
}
else
{
auto old_short_itr = !filled_call ? short_itr++ : short_itr;
fill_order( *old_short_itr, order_pays, order_receives );
}
auto old_limit_itr = !filled_call ? limit_itr++ : limit_itr;
fill_order( *old_limit_itr, order_pays, order_receives );
} // whlie call_itr != call_end
return filled_short_or_limit;
@ -636,7 +544,7 @@ asset database::pay_market_fees( const asset_object& recv_asset, const asset& re
{
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
modify( recv_dyn_data, [&]( asset_dynamic_data_object& obj ){
idump((issuer_fees));
//idump((issuer_fees));
obj.accumulated_fees += issuer_fees.amount;
});
}

View file

@ -22,7 +22,7 @@
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/witness_object.hpp>
@ -119,32 +119,21 @@ void database::clear_expired_proposals()
void database::clear_expired_orders()
{
with_skip_flags(
get_node_properties().skip_flags | skip_authority_check, [&]()
{
transaction_evaluation_state cancel_context(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<limit_order_index>().indices().get<by_expiration>();
while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() )
{
limit_order_cancel_operation canceler;
const limit_order_object& order = *limit_index.begin();
canceler.fee_paying_account = order.seller;
canceler.order = order.id;
apply_operation(cancel_context, canceler);
}
//Cancel expired limit orders
auto& limit_index = get_index_type<limit_order_index>().indices().get<by_expiration>();
while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() )
{
limit_order_cancel_operation canceler;
const limit_order_object& order = *limit_index.begin();
canceler.fee_paying_account = order.seller;
canceler.order = order.id;
apply_operation(cancel_context, canceler);
}
});
//Cancel expired short orders
auto& short_index = get_index_type<short_order_index>().indices().get<by_expiration>();
while( !short_index.empty() && short_index.begin()->expiration <= head_block_time() )
{
const short_order_object& order = *short_index.begin();
short_order_cancel_operation canceler;
canceler.fee_paying_account = order.seller;
canceler.order = order.id;
apply_operation(cancel_context, canceler);
}
} );
//Process expired force settlement orders
auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();

View file

@ -23,7 +23,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <fc/uint128.hpp>

View file

@ -121,43 +121,10 @@ namespace graphene { namespace chain {
/**
* @class price_feed
* @brief defines market parameters for shorts and margin positions
* @brief defines market parameters for margin positions
*/
struct price_feed
{
/**
* This is the lowest price at which margin positions will be forced to sell their collateral. This does not
* directly affect the price at which margin positions will be called; it is only a safety to prevent calls at
* unreasonable prices.
*/
price call_limit;
/**
* Short orders will only be matched against bids above this price.
*/
price short_limit;
/**
* Forced settlements will evaluate using this price.
*/
price settlement_price;
/**
* Maximum number of seconds margin positions should be able to remain open.
*/
uint32_t max_margin_period_sec = GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC;
/**
* Required maintenance collateral is defined
* as a fixed point number with a maximum value of 10.000
* and a minimum value of 1.000.
*
* This value must be greater than required_maintenance_collateral or
* a margin call would be triggered immediately.
*
* Default requirement is $2 of collateral per $1 of debt based
* upon the premise that both parties to every trade should bring
* equal value to the table.
*/
uint16_t required_initial_collateral = GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO;
/**
* Required maintenance collateral is defined
* as a fixed point number with a maximum value of 10.000
@ -169,19 +136,49 @@ namespace graphene { namespace chain {
* equals value_of_collateral using rate.
*
* Default requirement is $1.75 of collateral per $1 of debt
*
* BlackSwan ---> SQR ---> MCR ----> SP
*/
uint16_t required_maintenance_collateral = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
///@{
/**
* Forced settlements will evaluate using this price, defined as BITASSET / COLLATERAL
*/
price settlement_price;
friend bool operator < ( const price_feed& a, const price_feed& b )
/** Fixed point between 1.000 and 10.000 */
uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
/** Fixed point between 1.000 and 10.000 */
uint16_t maximum_short_squeeze_ratio = GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO;
/**
* When updating a call order the following condition must be maintained:
*
* debt * maintenance_price() < collateral
* debt * settlement_price < debt * maintenance
* debt * maintenance_price() < debt * max_short_squeeze_price()
*/
price maintenance_price()const
{
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) <
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
return ~price::call_price( settlement_price.base, settlement_price.quote, maintenance_collateral_ratio );
}
/** When selling collateral to pay off debt, the least amount of debt to receive should be
* min_usd = max_short_squeeze_price() * collateral
*
* This is provided to ensure that a black swan cannot be trigged due to poor liquidity alone, it
* must be confirmed by having the max_short_squeeze_price() move below the black swan price.
*/
price max_short_squeeze_price()const
{
return ~price::call_price( settlement_price.base, settlement_price.quote, maximum_short_squeeze_ratio );
}
///@}
friend bool operator == ( const price_feed& a, const price_feed& b )
{
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) ==
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
return std::tie( a.settlement_price, a.maintenance_collateral_ratio, a.maximum_short_squeeze_ratio ) ==
std::tie( b.settlement_price, b.maintenance_collateral_ratio, b.maximum_short_squeeze_ratio );
}
void validate() const;
@ -191,6 +188,8 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::asset, (amount)(asset_id) )
FC_REFLECT( graphene::chain::price, (base)(quote) )
#define GRAPHENE_PRICE_FEED_FIELDS (call_limit)(short_limit)(settlement_price)(max_margin_period_sec)\
(required_initial_collateral)(required_maintenance_collateral)
#define GRAPHENE_PRICE_FEED_FIELDS (settlement_price)(maintenance_collateral_ratio)(maximum_short_squeeze_ratio)
FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )

View file

@ -22,44 +22,19 @@
namespace graphene { namespace chain {
class short_order_create_evaluator : public evaluator<short_order_create_evaluator>
{
public:
typedef short_order_create_operation operation_type;
object_id_type do_evaluate( const short_order_create_operation& o );
object_id_type do_apply( const short_order_create_operation& o );
const short_order_create_operation* _op = nullptr;
const account_object* _seller = nullptr;
const asset_object* _sell_asset = nullptr;
const asset_object* _receive_asset = nullptr;
share_type _priority_fee = 0;
};
class short_order_cancel_evaluator : public evaluator<short_order_cancel_evaluator>
{
public:
typedef short_order_cancel_operation operation_type;
asset do_evaluate( const short_order_cancel_operation& o );
asset do_apply( const short_order_cancel_operation& o );
const short_order_object* _order;
};
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
{
public:
typedef call_order_update_operation operation_type;
asset do_evaluate( const call_order_update_operation& o );
asset do_apply( const call_order_update_operation& o );
void_result do_evaluate( const call_order_update_operation& o );
void_result do_apply( const call_order_update_operation& o );
bool _closing_order = false;
const asset_object* _debt_asset = nullptr;
const account_object* _paying_account = nullptr;
const call_order_object* _order = nullptr;
const asset_bitasset_data_object* _bitasset_data = nullptr;
};
} } // graphene::chain

View file

@ -26,47 +26,6 @@
namespace graphene { namespace chain {
using namespace graphene::db;
/**
* @class short_order_object
* @brief maintains state about requests to short an asset
*
* Short orders are only valid if their sell price is above the
* fair market value of the asset at the feed price. Users can
* place shorts at any price but their order will be ignored
* beyond the feed.
*
* All shorts have a minimial initial collateral ratio requirement that is
* defined by the network, but individuals may choose to have a higher
* initial collateral to avoid the risk of being margin called.
*
* All shorts have a maintenance collateral ratio that must be kept or
* the network will automatically cover the short order. Users can
* specify a higher maintenance collateral ratio as a form of "stop loss"
* and to potentially get ahead of a short squeeze.
*/
class short_order_object : public abstract_object<short_order_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = short_order_object_type;
time_point_sec expiration;
account_id_type seller;
share_type for_sale;
share_type available_collateral; ///< asset_id == sell_price.quote.asset_id
price sell_price; ///< the price the short is currently at = min(limit_price,feed)
price call_price; ///< the price that will be used to trigger margin calls after match, must be 1:1 if prediction market
uint16_t initial_collateral_ratio = 0; ///< may be higher than the network requires
uint16_t maintenance_collateral_ratio = 0; ///< may optionally be higher than the network requires
asset get_collateral()const { return asset( available_collateral, sell_price.quote.asset_id ); }
/** if the initial_collateral_ratio is 0, then this is a prediction market order which means the
* amount for sale depends upon price and available collateral.
*/
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
};
/**
* @class call_order_object
* @brief tracks debt and call price information
@ -86,13 +45,10 @@ namespace graphene { namespace chain {
asset_id_type debt_type()const { return call_price.quote.asset_id; }
price collateralization()const { return get_collateral() / get_debt(); }
void update_call_price() { call_price = price::call_price(get_debt(), get_collateral(), maintenance_collateral_ratio); }
account_id_type borrower;
share_type collateral; ///< call_price.base.asset_id, access via get_collateral
share_type debt; ///< call_price.quote.asset_id, access via get_collateral
price call_price;
uint16_t maintenance_collateral_ratio;
};
/**
@ -115,27 +71,9 @@ namespace graphene { namespace chain {
{ return balance.asset_id; }
};
struct by_id;
struct by_price;
struct by_account;
struct by_expiration;
struct by_collateral;
typedef multi_index_container<
short_order_object,
indexed_by<
hashed_unique< tag<by_id>,
member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_expiration>, member< short_order_object, time_point_sec, &short_order_object::expiration> >,
ordered_unique< tag<by_price>,
composite_key< short_order_object,
member< short_order_object, price, &short_order_object::sell_price>,
member< object, object_id_type, &object::id>
>,
composite_key_compare< std::greater<price>, std::less<object_id_type> >
>
>
> short_order_multi_index_type;
struct by_collateral;
struct by_account;
struct by_price;
typedef multi_index_container<
call_order_object,
indexed_by<
@ -163,7 +101,6 @@ namespace graphene { namespace chain {
>
> call_order_multi_index_type;
struct by_account;
struct by_expiration;
typedef multi_index_container<
force_settlement_object,
@ -182,17 +119,12 @@ namespace graphene { namespace chain {
> force_settlement_object_multi_index_type;
typedef generic_index<short_order_object, short_order_multi_index_type> short_order_index;
typedef generic_index<call_order_object, call_order_multi_index_type> call_order_index;
typedef generic_index<force_settlement_object, force_settlement_object_multi_index_type> force_settlement_index;
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::short_order_object, (graphene::db::object),
(expiration)(seller)(for_sale)(available_collateral)(sell_price)
(call_price)(initial_collateral_ratio)(maintenance_collateral_ratio)
)
FC_REFLECT_DERIVED( graphene::chain::call_order_object, (graphene::db::object),
(borrower)(collateral)(debt)(call_price)(maintenance_collateral_ratio) )
(borrower)(collateral)(debt)(call_price) )
FC_REFLECT( graphene::chain::force_settlement_object, (owner)(balance)(settlement_date) )

View file

@ -65,6 +65,7 @@
#define GRAPHENE_MAX_COLLATERAL_RATIO 32000 // higher than this is unnecessary and may exceed int16 storage
#define GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO 2000
#define GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO 1750
#define GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO 1500
#define GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC (30*60*60*24)
#define GRAPHENE_DEFAULT_NUM_WITNESSES (101)

View file

@ -361,7 +361,6 @@ namespace graphene { namespace chain {
template<typename OrderType>
int match( const limit_order_object& bid, const OrderType& ask, const price& match_price );
int match( const limit_order_object& bid, const limit_order_object& ask, const price& trade_price );
int match( const limit_order_object& bid, const short_order_object& ask, const price& trade_price );
/// @return the amount of asset settled
asset match(const call_order_object& call,
const force_settlement_object& settle,
@ -373,11 +372,10 @@ namespace graphene { namespace chain {
* @return true if the order was completely filled and thus freed.
*/
bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives );
bool fill_order( const short_order_object& order, const asset& pays, const asset& receives );
bool fill_order( const call_order_object& order, const asset& pays, const asset& receives );
bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );
bool check_call_orders( const asset_object& mia );
bool check_call_orders( const asset_object& mia, bool enable_black_swan = true );
// helpers to fill_order
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );

View file

@ -809,10 +809,10 @@ namespace graphene { namespace chain {
*/
struct limit_order_cancel_operation
{
asset fee;
limit_order_id_type order;
/** must be order->seller */
account_id_type fee_paying_account;
asset fee;
account_id_type fee_payer()const { return fee_paying_account; }
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
@ -826,111 +826,26 @@ namespace graphene { namespace chain {
}
};
/**
* @ingroup operations
*
* Define a new short order, if it is filled it will
* be merged with existing call orders for the same
* account. If maintenance_collateral_ratio is set
* it will update any existing open call orders to
* use the new maintenance level.
*
* When shorting you specify the total amount to sell
* and the amount of collateral along with the initial
* ratio. The price it will sell at is (amount_to_sell/(collateral*initial_collateral_ratio/2000))
*/
struct short_order_create_operation
{
/// The account placing a short order (this account must sign the transaction)
account_id_type seller;
/// The amount of market-issued asset to short sell
asset amount_to_sell;
/// The fee paid by seller
asset fee;
/// The amount of collateral to withdraw from the seller
asset collateral;
/// Fixed point representation of initial collateral ratio, with three digits of precision
/// Must be greater than or equal to the minimum specified by price feed
uint16_t initial_collateral_ratio = GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO;
/// Fixed point representation of maintenance collateral ratio, with three digits of precision
/// Must be greater than or equal to the minimum specified by price feed
uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
/// Expiration time for this order. Any unfilled portion of this order which is on the books at or past this time
/// will automatically be canceled.
time_point_sec expiration = time_point_sec::maximum();
account_id_type fee_payer()const { return seller; }
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
void validate()const;
share_type calculate_fee( const fee_schedule_type& k )const;
pair<asset_id_type,asset_id_type> get_market()const
{
return amount_to_sell.asset_id < collateral.asset_id ?
std::make_pair( amount_to_sell.asset_id, collateral.asset_id ) :
std::make_pair( collateral.asset_id, amount_to_sell.asset_id );
}
/** convention: amount_to_sell / amount_to_receive */
price sell_price()const { return ~price::call_price(amount_to_sell, collateral, initial_collateral_ratio); }
/** convention: amount_to_sell / amount_to_receive means we are
* selling collateral to receive debt
**/
price call_price() const { return price::call_price(amount_to_sell, collateral, maintenance_collateral_ratio); }
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const
{
acc.adjust( fee_payer(), -fee );
acc.adjust( seller, -collateral );
}
};
/**
* @ingroup operations
* Cancel the short order and return the balance to the
* order->seller account.
*/
struct short_order_cancel_operation
{
short_order_id_type order;
account_id_type fee_paying_account; ///< Must be order->seller
asset fee; ///< paid by order->seller
account_id_type fee_payer()const { return fee_paying_account; }
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
void validate()const;
share_type calculate_fee( const fee_schedule_type& k )const;
void get_balance_delta( balance_accumulator& acc, const operation_result& result )const
{
acc.adjust( fee_payer(), -fee );
acc.adjust( fee_payer(), result.get<asset>() );
}
};
/**
* @ingroup operations
*
* This operation can be used to add collateral, cover, and adjust the margin call price with a new maintenance
* collateral ratio.
* This operation can be used to add collateral, cover, and adjust the margin call price for a particular user.
*
* The only way to "cancel" a call order is to pay off the balance due. The order is invalid if the payoff amount
* is greater than the amount due.
* For prediction markets the collateral and debt must always be equal.
*
* @note the call_order_id is implied by the funding_account and assets involved. This implies that the assets must
* have appropriate asset_ids, even if the amount is zero.
* This operation will fail if it would trigger a margin call that couldn't be filled. If the margin call hits
* the call price limit then it will fail if the call price is above the settlement price.
*
* @note this operation can be used to force a market order using the collateral without requiring outside funds.
*/
struct call_order_update_operation
{
account_id_type funding_account; ///< pays fee, collateral, and cover
asset fee; ///< paid by funding_account
asset collateral_to_add; ///< the amount of collateral to add to the margin position
asset amount_to_cover; ///< the amount of the debt to be paid off
uint16_t maintenance_collateral_ratio = 0; ///< 0 means don't change, 1000 means feed
account_id_type funding_account; ///< pays fee, collateral, and cover
asset delta_collateral; ///< the amount of collateral to add to the margin position
asset delta_debt; ///< the amount of the debt to be paid off, may be negative to issue new debt
price call_price; ///< the price at which the collateral will be sold to cover the debt
account_id_type fee_payer()const { return funding_account; }
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
@ -939,8 +854,8 @@ namespace graphene { namespace chain {
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const
{
acc.adjust( fee_payer(), -fee );
acc.adjust( funding_account, -collateral_to_add );
acc.adjust( funding_account, -amount_to_cover );
acc.adjust( funding_account, -delta_collateral );
acc.adjust( funding_account, delta_debt );
}
};
@ -1392,9 +1307,7 @@ namespace graphene { namespace chain {
typedef fc::static_variant<
transfer_operation,
limit_order_create_operation,
short_order_create_operation,
limit_order_cancel_operation,
short_order_cancel_operation,
call_order_update_operation,
key_create_operation,
account_create_operation,
@ -1591,10 +1504,7 @@ FC_REFLECT( graphene::chain::limit_order_create_operation,
)
FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) )
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order) )
FC_REFLECT( graphene::chain::short_order_cancel_operation,(fee)(fee_paying_account)(order) )
FC_REFLECT( graphene::chain::short_order_create_operation, (fee)(seller)(amount_to_sell)(collateral)
(initial_collateral_ratio)(maintenance_collateral_ratio)(expiration) )
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(collateral_to_add)(amount_to_cover)(maintenance_collateral_ratio) )
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt)(call_price) )
FC_REFLECT( graphene::chain::transfer_operation,
(fee)(from)(to)(amount)(memo) )

View file

@ -108,7 +108,6 @@ namespace graphene { namespace chain {
delegate_object_type,
witness_object_type,
limit_order_object_type,
short_order_object_type,
call_order_object_type,
custom_object_type,
proposal_object_type,
@ -152,7 +151,6 @@ namespace graphene { namespace chain {
class force_settlement_object;
class key_object;
class limit_order_object;
class short_order_object;
class call_order_object;
class custom_object;
class proposal_object;
@ -169,7 +167,6 @@ namespace graphene { namespace chain {
typedef object_id< protocol_ids, delegate_object_type, delegate_object> delegate_id_type;
typedef object_id< protocol_ids, witness_object_type, witness_object> witness_id_type;
typedef object_id< protocol_ids, limit_order_object_type, limit_order_object> limit_order_id_type;
typedef object_id< protocol_ids, short_order_object_type, short_order_object> short_order_id_type;
typedef object_id< protocol_ids, call_order_object_type, call_order_object> call_order_id_type;
typedef object_id< protocol_ids, custom_object_type, custom_object> custom_id_type;
typedef object_id< protocol_ids, proposal_object_type, proposal_object> proposal_id_type;
@ -358,7 +355,7 @@ namespace graphene { namespace chain {
uint32_t witness_withdraw_pay_fee; ///< fee for withdrawing witness pay
uint32_t transfer_fee; ///< fee for transferring some asset
uint32_t limit_order_fee; ///< fee for placing a limit order in the markets
uint32_t short_order_fee; ///< fee for placing a short order in the markets
uint32_t call_order_fee; ///< fee for placing a call order in the markets
uint32_t publish_feed_fee; ///< fee for publishing a price feed
uint32_t asset_create_fee; ///< the cost to register the cheapest asset
uint32_t asset_update_fee; ///< the cost to modify a registered asset
@ -487,7 +484,6 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
(delegate_object_type)
(witness_object_type)
(limit_order_object_type)
(short_order_object_type)
(call_order_object_type)
(custom_object_type)
(proposal_object_type)
@ -532,7 +528,7 @@ FC_REFLECT( graphene::chain::fee_schedule_type,
(witness_withdraw_pay_fee)
(transfer_fee)
(limit_order_fee)
(short_order_fee)
(call_order_fee)
(publish_feed_fee)
(asset_create_fee)
(asset_update_fee)
@ -587,7 +583,6 @@ FC_REFLECT_TYPENAME( graphene::chain::force_settlement_id_type )
FC_REFLECT_TYPENAME( graphene::chain::delegate_id_type )
FC_REFLECT_TYPENAME( graphene::chain::witness_id_type )
FC_REFLECT_TYPENAME( graphene::chain::limit_order_id_type )
FC_REFLECT_TYPENAME( graphene::chain::short_order_id_type )
FC_REFLECT_TYPENAME( graphene::chain::call_order_id_type )
FC_REFLECT_TYPENAME( graphene::chain::custom_id_type )
FC_REFLECT_TYPENAME( graphene::chain::proposal_id_type )

View file

@ -18,7 +18,6 @@
#include <graphene/chain/limit_order_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
@ -104,44 +103,13 @@ object_id_type limit_order_create_evaluator::do_apply( const limit_order_create_
if( converted_some && !db().find(result) ) // then we were filled by call order
return result;
}
const auto& short_order_idx = db().get_index_type<short_order_index>();
const auto& sell_price_idx = short_order_idx.indices().get<by_price>();
FC_ASSERT( max_price.max() >= max_price );
auto short_itr = sell_price_idx.lower_bound( max_price.max() );
auto short_end = sell_price_idx.upper_bound( max_price );
while( !filled )
{
if( limit_itr != limit_end )
{
if( short_itr != short_end && limit_itr->sell_price < short_itr->sell_price )
{
auto old_short_itr = short_itr;
++short_itr;
filled = (db().match( new_order_object, *old_short_itr, old_short_itr->sell_price ) != 2 );
}
else
{
auto old_limit_itr = limit_itr;
++limit_itr;
filled = (db().match( new_order_object, *old_limit_itr, old_limit_itr->sell_price ) != 2 );
}
}
else if( short_itr != short_end )
{
auto old_short_itr = short_itr;
++short_itr;
filled = (db().match( new_order_object, *old_short_itr, old_short_itr->sell_price ) != 2 );
}
else break;
}
}
else while( !filled && limit_itr != limit_end )
while( !filled && limit_itr != limit_end )
{
auto old_itr = limit_itr;
++limit_itr;
filled = (db().match( new_order_object, *old_itr, old_itr->sell_price ) != 2);
auto old_limit_itr = limit_itr;
++limit_itr;
filled = (db().match( new_order_object, *old_limit_itr, old_limit_itr->sell_price ) != 2 );
}
//Possible optimization: only check calls if the new order completely filled some old order

View file

@ -391,37 +391,6 @@ share_type limit_order_cancel_operation::calculate_fee(const fee_schedule_type&
return k.limit_order_fee;
}
void short_order_create_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
{
active_auth_set.insert(seller);
}
void short_order_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( initial_collateral_ratio >= GRAPHENE_MIN_COLLATERAL_RATIO );
FC_ASSERT( initial_collateral_ratio > maintenance_collateral_ratio );
FC_ASSERT( initial_collateral_ratio <= GRAPHENE_MAX_COLLATERAL_RATIO );
}
share_type short_order_create_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.short_order_fee;
}
void short_order_cancel_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
{
active_auth_set.insert(fee_paying_account);
}
void short_order_cancel_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type short_order_cancel_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.short_order_fee;
}
void call_order_update_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
{
@ -429,20 +398,17 @@ void call_order_update_operation::get_required_auth(flat_set<account_id_type>& a
}
void call_order_update_operation::validate()const
{
{ try {
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( collateral_to_add.amount > 0 || amount_to_cover.amount > 0 || maintenance_collateral_ratio > 0 );
if( amount_to_cover.amount == 0 ) FC_ASSERT( collateral_to_add.amount >= 0 );
if( collateral_to_add.amount.value <= 0 ) FC_ASSERT( amount_to_cover.amount.value > 0 );
FC_ASSERT( amount_to_cover.amount >= 0 );
FC_ASSERT( amount_to_cover.asset_id != collateral_to_add.asset_id );
FC_ASSERT( maintenance_collateral_ratio == 0 || maintenance_collateral_ratio >= 1000 );
}
FC_ASSERT( delta_collateral.asset_id != delta_debt.asset_id );
FC_ASSERT( delta_debt.asset_id == call_price.base.asset_id );
FC_ASSERT( delta_collateral.asset_id == call_price.quote.asset_id );
call_price.validate();
} FC_CAPTURE_AND_RETHROW((*this)) }
share_type call_order_update_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.short_order_fee;
return k.call_order_fee;
}
proposal_create_operation proposal_create_operation::genesis_proposal(const database& db)

View file

@ -1,265 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/database.hpp>
#include <graphene/chain/short_order_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
object_id_type short_order_create_evaluator::do_evaluate( const short_order_create_operation& op )
{
database& d = db();
FC_ASSERT( op.expiration >= d.head_block_time() );
const asset_object& base_asset = op.amount_to_sell.asset_id(d);
const asset_object& quote_asset = op.collateral.asset_id(d);
FC_ASSERT( base_asset.is_market_issued() );
FC_ASSERT( quote_asset.id == base_asset.bitasset_data(d).options.short_backing_asset );
_seller = fee_paying_account;
_receive_asset = &quote_asset;
_sell_asset = &base_asset;
FC_ASSERT( !(base_asset.options.flags & white_list) || _seller->is_authorized_asset(base_asset) );
FC_ASSERT( !(quote_asset.options.flags & white_list) || _seller->is_authorized_asset(quote_asset) );
const asset_bitasset_data_object& bitasset_data = _sell_asset->bitasset_data(d);
if( bitasset_data.is_prediction_market )
{
FC_ASSERT( op.initial_collateral_ratio == 0 );
FC_ASSERT( op.maintenance_collateral_ratio == 0 );
auto p = op.sell_price();
// the maximum price is 1:1, it does not make sense to charge more than
// the collateral backing the position.
FC_ASSERT( p.base.amount < p.quote.amount );
}
else
{
FC_ASSERT( op.initial_collateral_ratio >= bitasset_data.current_feed.required_initial_collateral );
FC_ASSERT( op.maintenance_collateral_ratio >= bitasset_data.current_feed.required_maintenance_collateral );
FC_ASSERT( op.sell_price() >= bitasset_data.current_feed.short_limit );
}
return object_id_type();
}
object_id_type short_order_create_evaluator::do_apply( const short_order_create_operation& op )
{
db().adjust_balance(op.seller, -op.collateral);
const auto& new_order_object = db().create<short_order_object>( [&]( short_order_object& obj ){
obj.seller = _seller->id;
obj.for_sale = op.amount_to_sell.amount;
obj.available_collateral = op.collateral.amount;
obj.sell_price = op.sell_price();
obj.call_price = op.call_price();
obj.initial_collateral_ratio = op.initial_collateral_ratio;
obj.maintenance_collateral_ratio = op.maintenance_collateral_ratio;
obj.expiration = op.expiration;
});
short_order_id_type new_id = new_order_object.id;
if( op.collateral.asset_id == asset_id_type() )
{
auto& bal_obj = fee_paying_account->statistics(db());
db().modify( bal_obj, [&]( account_statistics_object& obj ){
obj.total_core_in_orders += op.collateral.amount;
});
}
// Possible optimization: We only need to check calls if both are true:
// - The new order is at the front of the book
// - The new order is below the call limit price
db().check_call_orders(*_sell_asset);
if( !db().find(new_id) ) // then we were filled by call order
return new_id;
const auto& limit_order_idx = db().get_index_type<limit_order_index>();
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
auto min_limit_price = ~op.sell_price();
auto itr = limit_price_idx.lower_bound( min_limit_price.max() );
auto end = limit_price_idx.upper_bound( min_limit_price );
while( itr != end )
{
auto old_itr = itr;
++itr;
if( db().match( *old_itr, new_order_object, old_itr->sell_price ) != 1 )
break; // 1 means ONLY old iter filled
}
//Possible optimization: only check calls if the new order completely filled some old order
//Do I need to check both assets?
db().check_call_orders(*_sell_asset);
db().check_call_orders(*_receive_asset);
return new_id;
} // short_order_evaluator::do_apply
asset short_order_cancel_evaluator::do_evaluate( const short_order_cancel_operation& o )
{
database& d = db();
_order = &o.order(d);
FC_ASSERT( _order->seller == o.fee_paying_account );
return _order->get_collateral();
}
asset short_order_cancel_evaluator::do_apply( const short_order_cancel_operation& o )
{
database& d = db();
auto refunded = _order->get_collateral();
d.adjust_balance(o.fee_paying_account, refunded);
auto base_asset = _order->sell_price.base.asset_id;
auto quote_asset = _order->sell_price.quote.asset_id;
d.remove( *_order );
if( refunded.asset_id == asset_id_type() )
{
auto& stats_obj = fee_paying_account->statistics(d);
d.modify( stats_obj, [&]( account_statistics_object& obj ){
obj.total_core_in_orders -= refunded.amount;
});
}
// Possible optimization: order can be called by canceling a short order iff the canceled order was at the top of the book.
// Do I need to check calls in both assets?
db().check_call_orders(base_asset(d));
db().check_call_orders(quote_asset(d));
return refunded;
}
asset call_order_update_evaluator::do_evaluate(const call_order_update_operation& o)
{ try {
database& d = db();
_paying_account = &o.funding_account(d);
_debt_asset = &o.amount_to_cover.asset_id(d);
const asset_bitasset_data_object& bitasset_data = _debt_asset->bitasset_data(d);
FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a market-issued asset.",
("sym", _debt_asset->symbol) );
FC_ASSERT( o.collateral_to_add.asset_id == bitasset_data.options.short_backing_asset );
if( bitasset_data.is_prediction_market )
{
FC_ASSERT( o.collateral_to_add.amount <= 0 );
FC_ASSERT( -o.collateral_to_add.amount == o.amount_to_cover.amount );
FC_ASSERT( o.maintenance_collateral_ratio == 0 );
}
else
{
FC_ASSERT( o.maintenance_collateral_ratio == 0 ||
o.maintenance_collateral_ratio > bitasset_data.current_feed.required_maintenance_collateral );
}
FC_ASSERT( d.get_balance(*_paying_account, *_debt_asset) >= o.amount_to_cover,
"Cannot cover by ${c} when payer has ${b}",
("c", o.amount_to_cover.amount)("b", d.get_balance(*_paying_account, *_debt_asset).amount) );
FC_ASSERT( d.get_balance(*_paying_account, bitasset_data.options.short_backing_asset(d)) >= o.collateral_to_add,
"Cannot increase collateral by ${c} when payer has ${b}", ("c", o.amount_to_cover.amount)
("b", d.get_balance(*_paying_account, bitasset_data.options.short_backing_asset(d)).amount) );
auto& call_idx = d.get_index_type<call_order_index>().indices().get<by_account>();
auto itr = call_idx.find( boost::make_tuple(o.funding_account, o.amount_to_cover.asset_id) );
FC_ASSERT( itr != call_idx.end(), "Could not find call order for ${sym} belonging to ${acct}.",
("sym", _debt_asset->symbol)("acct", _paying_account->name) );
_order = &*itr;
FC_ASSERT( o.amount_to_cover.asset_id == _order->debt_type() );
FC_ASSERT( o.amount_to_cover.amount <= _order->get_debt().amount );
if( o.amount_to_cover.amount < _order->get_debt().amount )
{
FC_ASSERT( (_order->get_debt() - o.amount_to_cover) *
price::call_price(_order->get_debt() - o.amount_to_cover,
_order->get_collateral() + o.collateral_to_add,
o.maintenance_collateral_ratio? o.maintenance_collateral_ratio
: _order->maintenance_collateral_ratio)
< _order->get_collateral(),
"Order would be called immediately following this update. Refusing to apply update." );
FC_ASSERT( o.amount_to_cover < _order->get_debt(), "Cover amount is greater than debt." );
} else {
_closing_order = true;
FC_ASSERT( o.collateral_to_add.amount == -_order->get_collateral().amount, "",
("collateral", _order->get_collateral()) );
return _order->get_collateral();
}
return asset();
} FC_CAPTURE_AND_RETHROW( (o) ) }
asset call_order_update_evaluator::do_apply(const call_order_update_operation& o)
{
database& d = db();
d.adjust_balance(_paying_account->get_id(), -o.amount_to_cover);
// Deduct the debt paid from the total supply of the debt asset.
d.modify(_debt_asset->dynamic_asset_data_id(d), [&](asset_dynamic_data_object& dynamic_asset) {
dynamic_asset.current_supply -= o.amount_to_cover.amount;
assert(dynamic_asset.current_supply >= 0);
});
asset collateral_returned;
if( _closing_order )
{
collateral_returned = _order->get_collateral();
// Credit the account's balances for his returned collateral.
d.adjust_balance(_paying_account->get_id(), collateral_returned);
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
if( _order->get_collateral().asset_id == asset_id_type() )
stats.total_core_in_orders -= collateral_returned.amount;
});
// Remove the call order.
d.remove(*_order);
} else {
// Update the call order.
d.modify(*_order, [&o](call_order_object& call) {
call.debt -= o.amount_to_cover.amount;
call.collateral += o.collateral_to_add.amount;
if( o.maintenance_collateral_ratio )
call.maintenance_collateral_ratio = o.maintenance_collateral_ratio;
call.update_call_price();
});
if( o.collateral_to_add.amount > 0 )
// Deduct the added collateral from the account.
d.adjust_balance(_paying_account->get_id(), -o.collateral_to_add);
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
if( o.collateral_to_add.asset_id == asset_id_type() )
stats.total_core_in_orders += o.collateral_to_add.amount;
});
}
return collateral_returned;
}
} } // graphene::chain

View file

@ -60,7 +60,7 @@ namespace graphene { namespace chain {
{
if( depth == GRAPHENE_MAX_SIG_CHECK_DEPTH )
{
elog("Failing authority verification due to recursion depth.");
//elog("Failing authority verification due to recursion depth.");
return false;
}
if( check_authority( *dynamic_cast<const account_object*>( &auth_item ), auth_class, depth + 1 ) )

View file

@ -65,7 +65,7 @@ index& object_database::get_mutable_index(uint8_t space_id, uint8_t type_id)
void object_database::flush()
{
ilog("Save object_database in ${d}", ("d", _data_dir));
// ilog("Save object_database in ${d}", ("d", _data_dir));
for( uint32_t space = 0; space < _index.size(); ++space )
{
fc::create_directories( _data_dir / "object_database" / fc::to_string(space) );
@ -86,7 +86,7 @@ void object_database::wipe(const fc::path& data_dir)
void object_database::open(const fc::path& data_dir)
{ try {
ilog("Open object_database in ${d}", ("d", data_dir));
// ilog("Open object_database in ${d}", ("d", data_dir));
_data_dir = data_dir;
for( uint32_t space = 0; space < _index.size(); ++space )
for( uint32_t type = 0; type < _index[space].size(); ++type )

@ -1 +1 @@
Subproject commit dd1c77b327c6eba807168856c3c12e90173468c4
Subproject commit dde8ed9d7ab49807f2556488c0815f3741b11e00

View file

@ -141,9 +141,7 @@ struct operation_get_impacted_accounts
}
void operator()( const limit_order_create_operation& o )const { }
void operator()( const short_order_create_operation& o )const { }
void operator()( const limit_order_cancel_operation& o )const { }
void operator()( const short_order_cancel_operation& o )const { }
void operator()( const call_order_update_operation& o )const { }
void operator()( const key_create_operation& o )const { }
void operator()( const custom_operation& o )const { }

View file

@ -22,7 +22,7 @@
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
@ -72,8 +72,6 @@ object* create_object( const variant& v )
return create_object_of_type< witness_object >( v );
case limit_order_object_type:
return create_object_of_type< limit_order_object >( v );
case short_order_object_type:
return create_object_of_type< short_order_object >( v );
case call_order_object_type:
return create_object_of_type< call_order_object >( v );
/*

View file

@ -114,7 +114,6 @@ class wallet_api
vector<asset_object> list_assets(const string& lowerbound, uint32_t limit)const;
vector<operation_history_object> get_account_history(string name, int limit)const;
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
vector<short_order_object> get_short_orders(string a, uint32_t limit)const;
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
global_property_object get_global_properties() const;
@ -204,7 +203,11 @@ class wallet_api
bool fill_or_kill = false,
bool broadcast = false);
signed_transaction short_sell_asset(string seller_name, string amount_to_sell, string asset_symbol,
/**
* This method will create a transaction with two operations, the first one will borrow amount_to_sell
* given amount of collateral
*/
signed_transaction borrow_asset(string seller_name, string amount_to_sell, string asset_symbol,
string amount_of_collateral, bool broadcast = false);
signed_transaction create_asset(string issuer,
@ -272,7 +275,7 @@ FC_API( graphene::wallet::wallet_api,
(upgrade_account)
(create_account_with_brain_key)
(sell_asset)
(short_sell_asset)
(borrow_asset)
(transfer)
(create_asset)
(issue_asset)
@ -289,7 +292,6 @@ FC_API( graphene::wallet::wallet_api,
(load_wallet_file)
(normalize_brain_key)
(get_limit_orders)
(get_short_orders)
(get_call_orders)
(get_settle_orders)
(save_wallet_file)

View file

@ -1011,7 +1011,7 @@ public:
return sign_transaction( tx, broadcast );
}
signed_transaction short_sell_asset(string seller_name, string amount_to_sell, string asset_symbol,
signed_transaction borrow_asset(string seller_name, string amount_to_sell, string asset_symbol,
string amount_of_collateral, bool broadcast = false)
{
account_object seller = get_account(seller_name);
@ -1019,11 +1019,10 @@ public:
FC_ASSERT(mia.is_market_issued());
asset_object collateral = get_asset(get_object(*mia.bitasset_data_id).options.short_backing_asset);
short_order_create_operation op;
op.seller = seller.id;
op.expiration = fc::time_point::now() + fc::days(365*10);
op.amount_to_sell = mia.amount_from_string(amount_to_sell);
op.collateral = collateral.amount_from_string(amount_of_collateral);
call_order_update_operation op;
op.funding_account = seller.id;
op.delta_debt = mia.amount_from_string(amount_to_sell);
op.delta_collateral = collateral.amount_from_string(amount_of_collateral);
signed_transaction trx;
trx.operations = {op};
@ -1040,27 +1039,11 @@ public:
FC_ASSERT(order_id.space() == protocol_ids, "Invalid order ID ${id}", ("id", order_id));
signed_transaction trx;
switch( order_id.type() )
{
case short_order_object_type: {
short_order_cancel_operation op;
op.fee_paying_account = get_object<short_order_object>(order_id).seller;
op.order = order_id;
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
trx.operations = {op};
break;
}
case limit_order_object_type: {
limit_order_cancel_operation op;
op.fee_paying_account = get_object<limit_order_object>(order_id).seller;
op.order = order_id;
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
trx.operations = {op};
break;
}
default:
FC_THROW("Invalid order ID ${id}", ("id", order_id));
}
limit_order_cancel_operation op;
op.fee_paying_account = get_object<limit_order_object>(order_id).seller;
op.order = order_id;
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
trx.operations = {op};
trx.validate();
return sign_transaction(trx, broadcast);
@ -1384,11 +1367,6 @@ vector<limit_order_object> wallet_api::get_limit_orders(string a, string b, uint
return my->_remote_db->get_limit_orders(get_asset(a).id, get_asset(b).id, limit);
}
vector<short_order_object> wallet_api::get_short_orders(string a, uint32_t limit)const
{
return my->_remote_db->get_short_orders(get_asset(a).id, limit);
}
vector<call_order_object> wallet_api::get_call_orders(string a, uint32_t limit)const
{
return my->_remote_db->get_call_orders(get_asset(a).id, limit);
@ -1740,11 +1718,11 @@ signed_transaction wallet_api::sell_asset(string seller_account,
symbol_to_receive, expiration, fill_or_kill, broadcast);
}
signed_transaction wallet_api::short_sell_asset(string seller_name, string amount_to_sell,
signed_transaction wallet_api::borrow_asset(string seller_name, string amount_to_sell,
string asset_symbol, string amount_of_collateral, bool broadcast)
{
FC_ASSERT(!is_locked());
return my->short_sell_asset(seller_name, amount_to_sell, asset_symbol, amount_of_collateral, broadcast);
return my->borrow_asset(seller_name, amount_to_sell, asset_symbol, amount_of_collateral, broadcast);
}
} }

View file

@ -21,7 +21,7 @@
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/key_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/block.hpp>

View file

@ -26,7 +26,7 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/witness_object.hpp>
@ -107,7 +107,7 @@ string database_fixture::generate_anon_acct_name()
void database_fixture::verify_asset_supplies( )const
{
wlog("*** Begin asset supply verification ***");
//wlog("*** Begin asset supply verification ***");
const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db);
BOOST_CHECK(core_asset_data.fee_pool == 0);
@ -134,12 +134,6 @@ void database_fixture::verify_asset_supplies( )const
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
total_balances[for_sale.asset_id] += for_sale.amount;
}
for( const short_order_object& o : db.get_index_type<short_order_index>().indices() )
{
asset col = o.get_collateral();
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
total_balances[col.asset_id] += col.amount;
}
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
{
asset col = o.get_collateral();
@ -170,7 +164,7 @@ void database_fixture::verify_asset_supplies( )const
BOOST_CHECK_EQUAL( core_in_orders.value , reported_core_in_orders.value );
BOOST_CHECK_EQUAL( total_balances[asset_id_type()].value , core_asset_data.current_supply.value );
wlog("*** End asset supply verification ***");
// wlog("*** End asset supply verification ***");
}
void database_fixture::verify_account_history_plugin_index( )const
@ -424,32 +418,6 @@ void database_fixture::issue_uia( const account_object& recipient, asset amount
return;
}
const short_order_object*database_fixture::create_short(account_id_type seller, const asset& amount_to_sell, const asset& collateral_provided, uint16_t initial_collateral_ratio, uint16_t maintenance_collateral_ratio)
{
return create_short(seller(db), amount_to_sell, collateral_provided, initial_collateral_ratio, maintenance_collateral_ratio);
}
const short_order_object* database_fixture::create_short(
const account_object& seller,
const asset& amount_to_sell,
const asset& collateral_provided,
uint16_t initial_collateral_ratio /* = 2000 */,
uint16_t maintenance_collateral_ratio /* = 1750 */
)
{
short_order_create_operation op;
op.seller = seller.id;
op.amount_to_sell = amount_to_sell;
op.collateral = collateral_provided;
op.initial_collateral_ratio = initial_collateral_ratio;
op.maintenance_collateral_ratio = maintenance_collateral_ratio;
trx.operations.push_back(std::move(op));
trx.validate();
processed_transaction ptx = db.push_transaction(trx, ~0);
trx.operations.clear();
return db.find<short_order_object>(ptx.operation_results[0].get<object_id_type>());
}
const account_object& database_fixture::create_account(
const string& name,
const key_id_type& key /* = key_id_type() */
@ -514,7 +482,7 @@ const account_object& database_fixture::create_account(
trx.validate();
processed_transaction ptx = db.push_transaction(trx, ~0);
wdump( (ptx) );
//wdump( (ptx) );
const account_object& result = db.get<account_object>(ptx.operation_results[1].get<object_id_type>());
trx.operations.clear();
return result;
@ -593,6 +561,7 @@ const limit_order_object*database_fixture::create_sell_order(account_id_type use
const limit_order_object* database_fixture::create_sell_order( const account_object& user, const asset& amount, const asset& recv )
{
//wdump((amount)(recv));
limit_order_create_operation buy_order;
buy_order.seller = user.id;
buy_order.amount_to_sell = amount;
@ -602,6 +571,7 @@ const limit_order_object* database_fixture::create_sell_order( const account_obj
trx.validate();
auto processed = db.push_transaction(trx, ~0);
trx.operations.clear();
//wdump((processed));
return db.find<limit_order_object>( processed.operation_results[0].get<object_id_type>() );
}
@ -618,18 +588,6 @@ asset database_fixture::cancel_limit_order( const limit_order_object& order )
return processed.operation_results[0].get<asset>();
}
asset database_fixture::cancel_short_order( const short_order_object& order )
{
short_order_cancel_operation cancel_order;
cancel_order.fee_paying_account = order.seller;
cancel_order.order = order.id;
trx.operations.push_back(cancel_order);
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
trx.validate();
auto processed = db.push_transaction(trx, ~0);
trx.operations.clear();
return processed.operation_results[0].get<asset>();
}
void database_fixture::transfer(
account_id_type from,
@ -662,6 +620,63 @@ void database_fixture::transfer(
} FC_CAPTURE_AND_RETHROW( (from.id)(to.id)(amount)(fee) )
}
void database_fixture::update_feed_producers( const asset_object& mia, flat_set<account_id_type> producers )
{ try {
trx.set_expiration(db.head_block_time() + fc::minutes(1));
trx.operations.clear();
asset_update_feed_producers_operation op;
op.asset_to_update = mia.id;
op.issuer = mia.issuer;
op.new_feed_producers = std::move(producers);
trx.operations.emplace_back( std::move(op) );
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
trx.validate();
db.push_transaction(trx, ~0);
trx.operations.clear();
} FC_CAPTURE_AND_RETHROW( (mia)(producers) ) }
void database_fixture::publish_feed( const asset_object& mia, const account_object& by, const price_feed& f )
{
trx.set_expiration(db.head_block_time() + fc::minutes(1));
trx.operations.clear();
asset_publish_feed_operation op;
op.publisher = by.id;
op.asset_id = mia.id;
op.feed = f;
trx.operations.emplace_back( std::move(op) );
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
trx.validate();
db.push_transaction(trx, ~0);
trx.operations.clear();
}
void database_fixture::borrow( const account_object& who, asset what, asset collateral, price call_price )
{ try {
asset call_price_collateral((collateral.amount.value * 3)/4, collateral.asset_id );
trx.set_expiration(db.head_block_time() + fc::minutes(1));
trx.operations.clear();
trx.operations.push_back( call_order_update_operation({ asset(), who.id, collateral, what, call_price }));;
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
trx.validate();
db.push_transaction(trx, ~0);
trx.operations.clear();
} FC_CAPTURE_AND_RETHROW( (who.name)(what)(collateral) ) }
void database_fixture::cover( const account_object& who, asset what, asset collateral, price call_price )
{ try {
trx.set_expiration(db.head_block_time() + fc::minutes(1));
trx.operations.clear();
trx.operations.push_back( call_order_update_operation({ asset(), who.id, -collateral, -what, call_price }));
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
trx.validate();
db.push_transaction(trx, ~0);
trx.operations.clear();
} FC_CAPTURE_AND_RETHROW( (who.name)(what)(collateral) ) }
void database_fixture::fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount )
{
trx.operations.push_back( asset_fund_fee_pool_operation({asset(), from.id, asset_to_fund.id, amount}) );
@ -761,15 +776,6 @@ string database_fixture::pretty( const asset& a )const
return ss.str();
}
void database_fixture::print_short_order( const short_order_object& cur )const
{
std::cout << std::setw(10) << cur.seller(db).name << " ";
std::cout << std::setw(10) << "SHORT" << " ";
std::cout << std::setw(16) << pretty( cur.amount_for_sale() ) << " ";
std::cout << std::setw(16) << pretty( cur.amount_to_receive() ) << " ";
std::cout << std::setw(16) << (~cur.sell_price).to_real() << " ";
}
void database_fixture::print_limit_order( const limit_order_object& cur )const
{
std::cout << std::setw(10) << cur.seller(db).name << " ";
@ -817,68 +823,16 @@ void database_fixture::print_joint_market( const string& syma, const string& sym
const auto& limit_idx = db.get_index_type<limit_order_index>();
const auto& limit_price_idx = limit_idx.indices().get<by_price>();
const auto& short_idx = db.get_index_type<short_order_index>();
const auto& sell_price_idx = short_idx.indices().get<by_price>();
auto limit_itr = limit_price_idx.begin();
auto short_itr = sell_price_idx.rbegin();
while( true )
while( limit_itr != limit_price_idx.end() )
{
std::cout << std::endl;
if( limit_itr != limit_price_idx.end() )
{
if( short_itr != sell_price_idx.rend() && limit_itr->sell_price > ~short_itr->sell_price )
{
print_short_order( *short_itr );
++short_itr;
}
else // print the limit
{
print_limit_order( *limit_itr );
++limit_itr;
}
}
else if( short_itr != sell_price_idx.rend() )
{
print_short_order( *short_itr );
++short_itr;
}
else
break;
print_limit_order( *limit_itr );
++limit_itr;
}
}
void database_fixture::print_short_market( const string& syma, const string& symb )const
{
const auto& limit_idx = db.get_index_type<short_order_index>();
const auto& price_idx = limit_idx.indices().get<by_price>();
cout << std::fixed;
cout.precision(5);
cout << std::setw(10) << std::left << "NAME" << " ";
cout << std::setw(16) << std::right << "FOR SHORT" << " ";
cout << std::setw(16) << std::right << "COLLATERAL" << " ";
cout << std::setw(10) << std::right << "PRICE" << " ";
cout << std::setw(10) << std::right << "1/PRICE" << " ";
cout << std::setw(10) << std::right << "CALL PRICE" << " ";
cout << std::setw(10) << std::right << "I-Ratio" << " ";
cout << std::setw(10) << std::right << "M-Ratio" << "\n";
cout << string(100, '=') << std::endl;
auto cur = price_idx.begin();
while( cur != price_idx.end() )
{
cout << std::setw( 10 ) << std::left << cur->seller(db).name << " ";
cout << std::setw( 16 ) << std::right << pretty( cur->amount_for_sale() ) << " ";
cout << std::setw( 16 ) << std::right << pretty( cur->get_collateral() ) << " ";
cout << std::setw( 10 ) << std::right << cur->sell_price.to_real() << " ";
cout << std::setw( 10 ) << std::right << (~cur->sell_price).to_real() << " ";
cout << std::setw( 10 ) << std::right << (cur->call_price).to_real() << " ";
cout << std::setw( 10 ) << std::right << (cur->initial_collateral_ratio)/double(1000) << " ";
cout << std::setw( 10 ) << std::right << (cur->maintenance_collateral_ratio)/double(1000) << " ";
cout << "\n";
++cur;
}
}
int64_t database_fixture::get_balance( account_id_type account, asset_id_type a )const
{

View file

@ -76,10 +76,13 @@ using namespace graphene::db;
key_id_type name ## _key_id = register_key(name ## _private_key.get_public_key()).get_id();
#define ACTOR(name) \
PREP_ACTOR(name) \
account_id_type name ## _id = create_account(BOOST_PP_STRINGIZE(name), name ## _key_id).id;
const auto& name = create_account(BOOST_PP_STRINGIZE(name), name ## _key_id); \
account_id_type name ## _id = name.id; (void)name ## _id;
#define GET_ACTOR(name) \
fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \
account_id_type name ## _id = get_account(BOOST_PP_STRINGIZE(name)).id; \
const account_object& name = get_account(BOOST_PP_STRINGIZE(name)); \
account_id_type name ## _id = name.id; \
key_id_type name ## _key_id = name ## _id(db).active.auths.begin()->first;
#define ACTORS_IMPL(r, data, elem) ACTOR(elem)
@ -144,6 +147,11 @@ struct database_fixture {
key_id_type key = key_id_type()
);
void update_feed_producers( const asset_object& mia, flat_set<account_id_type> producers );
void publish_feed( const asset_object& mia, const account_object& by, const price_feed& f );
void borrow( const account_object& who, asset what, asset collateral, price call_price = price());
void cover( const account_object& who, asset what, asset collateral_freed, price call_price = price());
const asset_object& get_asset( const string& symbol )const;
const account_object& get_account( const string& name )const;
const asset_object& create_bitasset(const string& name,
@ -153,20 +161,6 @@ struct database_fixture {
const asset_object& create_user_issued_asset( const string& name );
void issue_uia( const account_object& recipient, asset amount );
const short_order_object* create_short(
account_id_type seller,
const asset& amount_to_sell,
const asset& collateral_provided,
uint16_t initial_collateral_ratio = 2000,
uint16_t maintenance_collateral_ratio = 1750
);
const short_order_object* create_short(
const account_object& seller,
const asset& amount_to_sell,
const asset& collateral_provided,
uint16_t initial_collateral_ratio = 2000,
uint16_t maintenance_collateral_ratio = 1750
);
const account_object& create_account(
const string& name,
@ -203,7 +197,6 @@ struct database_fixture {
const limit_order_object* create_sell_order( account_id_type user, const asset& amount, const asset& recv );
const limit_order_object* create_sell_order( const account_object& user, const asset& amount, const asset& recv );
asset cancel_limit_order( const limit_order_object& order );
asset cancel_short_order( const short_order_object& order );
void transfer( account_id_type from, account_id_type to, const asset& amount, const asset& fee = asset() );
void transfer( const account_object& from, const account_object& to, const asset& amount, const asset& fee = asset() );
void fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount );
@ -214,11 +207,9 @@ struct database_fixture {
void upgrade_to_annual_member( const account_object& account );
void print_market( const string& syma, const string& symb )const;
string pretty( const asset& a )const;
void print_short_order( const short_order_object& cur )const;
void print_limit_order( const limit_order_object& cur )const;
void print_call_orders( )const;
void print_joint_market( const string& syma, const string& symb )const;
void print_short_market( const string& syma, const string& symb )const;
int64_t get_balance( account_id_type account, asset_id_type a )const;
int64_t get_balance( const account_object& account, const asset_object& a )const;
};

View file

@ -966,14 +966,12 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
flat_set<account_id_type> active_set, owner_set;
xfer_op.get<transfer_operation>().get_required_auth(active_set, owner_set);
wdump( (active_set)(owner_set)(alice_key_id)
(alice_account_object) );
// wdump( (active_set)(owner_set)(alice_key_id) (alice_account_object) );
PUSH_TX( db, trx, skip );
trx.operations.push_back( xfer_op );
// Alice's signature is now invalid
edump((trx));
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
// Re-sign, now OK (sig is replaced)
trx.sign( alice_key_id, alice_key );
@ -1013,10 +1011,10 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
delegate_id_type nathan_delegate = create_delegate(nathan_id(db)).id;
delegate_id_type vikram_delegate = create_delegate(vikram_id(db)).id;
wdump((db.get_balance(account_id_type(), asset_id_type())));
//wdump((db.get_balance(account_id_type(), asset_id_type())));
generate_block();
wdump((db.get_balance(account_id_type(), asset_id_type())));
//wdump((db.get_balance(account_id_type(), asset_id_type())));
transfer(account_id_type(), nathan_id, asset(1000000));
transfer(account_id_type(), vikram_id, asset(100));

View file

@ -26,7 +26,7 @@
#include <graphene/chain/key_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <fc/crypto/digest.hpp>
@ -70,30 +70,29 @@ BOOST_AUTO_TEST_CASE( block_database_test )
for( uint32_t i = 0; i < 5; ++i )
{
if( i > 0 ) b.previous = b.id();
b.witness = witness_id_type(i+1);
edump((b));
b.witness = witness_id_type(i+1);
bdb.store( b.id(), b );
auto fetch = bdb.fetch_by_number( b.block_num() );
idump((fetch));
//idump((fetch));
FC_ASSERT( fetch.valid() );
FC_ASSERT( fetch->witness == b.witness );
fetch = bdb.fetch_by_number( i+1 );
idump((fetch));
//idump((fetch));
FC_ASSERT( fetch.valid() );
FC_ASSERT( fetch->witness == b.witness );
fetch = bdb.fetch_optional( b.id() );
idump((fetch));
//idump((fetch));
FC_ASSERT( fetch.valid() );
FC_ASSERT( fetch->witness == b.witness );
}
ilog("-----------" );
//ilog("-----------" );
for( uint32_t i = 1; i < 5; ++i )
{
auto blk = bdb.fetch_by_number( i );
FC_ASSERT( blk.valid() );
idump((blk)(i));
//idump((blk)(i));
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
}
@ -111,7 +110,7 @@ BOOST_AUTO_TEST_CASE( block_database_test )
{
auto blk = bdb.fetch_by_number( i+1 );
FC_ASSERT( blk.valid() );
idump((blk)(i));
//idump((blk)(i));
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
}
@ -150,7 +149,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
db.close();
}
{
wlog( "------------------------------------------------" );
//wlog( "------------------------------------------------" );
database db;
db.open(data_dir.path() );
BOOST_CHECK_EQUAL( db.head_block_num(), 200 );
@ -190,15 +189,15 @@ BOOST_AUTO_TEST_CASE( undo_block )
BOOST_CHECK( db.head_block_num() == 5 );
db.pop_block();
now -= db.block_interval();
wdump( (witness_schedule_id_type()(db)) );
//wdump( (witness_schedule_id_type()(db)) );
BOOST_CHECK( db.head_block_num() == 4 );
db.pop_block();
now -= db.block_interval();
wdump( (witness_schedule_id_type()(db)) );
//wdump( (witness_schedule_id_type()(db)) );
BOOST_CHECK( db.head_block_num() == 3 );
db.pop_block();
now -= db.block_interval();
wdump( (witness_schedule_id_type()(db)) );
//wdump( (witness_schedule_id_type()(db)) );
BOOST_CHECK( db.head_block_num() == 2 );
for( uint32_t i = 0; i < 5; ++i )
{
@ -540,53 +539,6 @@ BOOST_FIXTURE_TEST_CASE( maintenance_interval, database_fixture )
}
}
/**
* Orders should specify a valid expiration time and they will ba automatically canceled if not filled by that time.
* This feature allows people to safely submit orders that have a limited lifetime, which is essential to some
* traders.
*/
BOOST_FIXTURE_TEST_CASE( short_order_expiration, database_fixture )
{ try {
//Get a sane head block time
generate_block();
auto* test = &create_bitasset("TEST");
auto* core = &asset_id_type()(db);
auto* nathan = &create_account("nathan");
auto* genesis = &account_id_type()(db);
transfer(*genesis, *nathan, core->amount(50000));
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 50000 );
short_order_create_operation op;
op.seller = nathan->id;
op.amount_to_sell = test->amount(500);
op.collateral = core->amount(500);
op.expiration = db.head_block_time() + fc::seconds(10);
trx.operations.push_back(op);
auto ptrx = PUSH_TX( db, trx, ~0 );
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 49500 );
auto ptrx_id = ptrx.operation_results.back().get<object_id_type>();
auto short_index = db.get_index_type<short_order_index>().indices();
auto short_itr = short_index.begin();
BOOST_REQUIRE( short_itr != short_index.end() );
BOOST_REQUIRE( short_itr->id == ptrx_id );
BOOST_REQUIRE( db.find_object(short_itr->id) );
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 49500 );
auto id = short_itr->id;
generate_blocks(op.expiration, false);
test = &get_asset("TEST");
core = &asset_id_type()(db);
nathan = &get_account("nathan");
genesis = &account_id_type()(db);
BOOST_CHECK(db.find_object(id) == nullptr);
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 50000 );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE( limit_order_expiration, database_fixture )
{ try {
@ -690,7 +642,11 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture )
BOOST_FIXTURE_TEST_CASE( force_settlement, database_fixture )
{ try {
FC_ASSERT( !"TODO" );
/*
auto private_key = delegate_priv_key;
auto private_key = generate_private_key("genesis");
>>>>>>> short_refactor
account_id_type nathan_id = create_account("nathan").get_id();
account_id_type shorter1_id = create_account("shorter1").get_id();
account_id_type shorter2_id = create_account("shorter2").get_id();
@ -810,6 +766,7 @@ BOOST_FIXTURE_TEST_CASE( force_settlement, database_fixture )
BOOST_CHECK(db.find(settle_id));
BOOST_CHECK_EQUAL(get_balance(nathan_id, asset_id_type()), 5878);
BOOST_CHECK(!db.get_index_type<call_order_index>().indices().empty());
*/
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture )
@ -883,9 +840,7 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture )
});
near_schedule = db.get_near_witness_schedule();
idump((db.head_block_time()));
generate_block(0, delegate_priv_key, 2);
idump((db.head_block_time()));
BOOST_CHECK(db.get_dynamic_global_properties().current_witness == near_schedule[2]);
near_schedule.erase(near_schedule.begin(), near_schedule.begin() + 3);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/short_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_nominal_case )
while(true)
{
const withdraw_permission_object& permit_object = permit(db);
wdump( (permit_object) );
//wdump( (permit_object) );
withdraw_permission_claim_operation op;
op.withdraw_permission = permit;
op.withdraw_from_account = nathan_id;
@ -336,48 +336,32 @@ BOOST_AUTO_TEST_CASE( mia_feeds )
const asset_object& bit_usd = bit_usd_id(db);
asset_publish_feed_operation op({asset(), vikram_id});
op.asset_id = bit_usd_id;
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(30));
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(10));
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(30));
// We'll expire margins after a month
op.feed.max_margin_period_sec = fc::days(30).to_seconds();
// Accept defaults for required collateral
trx.operations.emplace_back(op);
PUSH_TX( db, trx, ~0 );
const asset_bitasset_data_object& bitasset = bit_usd.bitasset_data(db);
BOOST_CHECK(bitasset.current_feed.call_limit.to_real() == GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 10.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
BOOST_CHECK(bitasset.current_feed.settlement_price.to_real() == GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
op.publisher = ben_id;
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(25));
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(20));
op.feed.max_margin_period_sec = fc::days(10).to_seconds();
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(25));
trx.operations.back() = op;
PUSH_TX( db, trx, ~0 );
BOOST_CHECK_EQUAL(bitasset.current_feed.call_limit.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 25.0);
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 20.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
BOOST_CHECK_EQUAL(bitasset.current_feed.settlement_price.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 25.0);
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
op.publisher = dan_id;
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(40));
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(10));
op.feed.max_margin_period_sec = fc::days(100).to_seconds();
op.feed.required_initial_collateral = 1001;
op.feed.required_maintenance_collateral = 1000;
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(40));
op.feed.maintenance_collateral_ratio = 1000;
trx.operations.back() = op;
PUSH_TX( db, trx, ~0 );
BOOST_CHECK_EQUAL(bitasset.current_feed.call_limit.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 10.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
BOOST_CHECK_EQUAL(bitasset.current_feed.settlement_price.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
op.publisher = nathan_id;
trx.operations.back() = op;
@ -452,6 +436,8 @@ BOOST_AUTO_TEST_CASE( witness_create )
BOOST_AUTO_TEST_CASE( global_settle_test )
{ try {
ACTORS((nathan)(ben)(valentine)(dan));
FC_ASSERT( !"TODO - Reimplement this" );
/*
asset_id_type bit_usd_id = create_bitasset("BITUSD", nathan_id, 100, global_settle | charge_market_fee).get_id();
transfer(genesis_account, ben_id, asset(10000));
transfer(genesis_account, valentine_id, asset(10000));
@ -490,6 +476,7 @@ BOOST_AUTO_TEST_CASE( global_settle_test )
BOOST_CHECK_EQUAL(get_balance(ben_id, asset_id_type()), 10091);
BOOST_CHECK_EQUAL(get_balance(dan_id, bit_usd_id), 0);
BOOST_CHECK_EQUAL(get_balance(dan_id, asset_id_type()), 9850);
*/
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE( worker_create_test )
@ -684,7 +671,11 @@ BOOST_AUTO_TEST_CASE( refund_worker_test )
BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
{ try {
FC_ASSERT( !"TODO - Reimplement this" );
/*
auto private_key = delegate_priv_key;
auto private_key = generate_private_key("genesis");
>>>>>>> short_refactor
account_id_type nathan_id = create_account("nathan").get_id();
account_id_type shorter1_id = create_account("shorter1").get_id();
account_id_type shorter2_id = create_account("shorter2").get_id();
@ -739,7 +730,6 @@ BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
price_feed feed;
feed.settlement_price = price(asset(1),asset(1, bit_usd));
feed.call_limit = price::min(0, bit_usd);
feed.short_limit = price::min(bit_usd, 0);
pop.feed = feed;
trx.operations.push_back(pop);
}
@ -797,6 +787,7 @@ BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
BOOST_CHECK(db.get_index_type<force_settlement_index>().indices().empty());
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), bit_usd(db).dynamic_data(db).current_supply.value);
}
*/
} FC_LOG_AND_RETHROW() }
// TODO: Write linear VBO tests

View file

@ -63,9 +63,7 @@ BOOST_AUTO_TEST_CASE( json_tests )
{
try {
auto var = fc::json::variants_from_string( "10.6 " );
wdump((var));
var = fc::json::variants_from_string( "10.5" );
wdump((var));
} catch ( const fc::exception& e )
{
edump((e.to_detail_string()));