merge from master, clean up test output
This commit is contained in:
commit
a14500a364
41 changed files with 603 additions and 1948 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
156
libraries/chain/call_order_evaluator.cpp
Normal file
156
libraries/chain/call_order_evaluator.cpp
Normal 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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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) )
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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) )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = "e_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
|
||||
|
|
@ -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 ) )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 { }
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
} }
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
Loading…
Reference in a new issue