Fixed to follow QUOTE:BASE semantics. Cleanup and added in wallet calls that were missed in last merge. #592

This commit is contained in:
Michael Vandeberg 2016-02-25 11:37:25 -05:00
parent a675023b9f
commit 4b346579a8
4 changed files with 286 additions and 126 deletions

View file

@ -31,6 +31,8 @@
#include <fc/crypto/hex.hpp> #include <fc/crypto/hex.hpp>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <cctype> #include <cctype>
@ -1025,56 +1027,37 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q
try { try {
if( base_id > quote_id ) std::swap(base_id, quote_id); if( base_id > quote_id ) std::swap(base_id, quote_id);
const auto& bidx = _db.get_index_type<bucket_index>(); uint32_t day = 86400;
const auto& by_key_idx = bidx.indices().get<by_key>();
uint32_t bucket_size = 86400;
auto now = fc::time_point_sec( fc::time_point::now() ); auto now = fc::time_point_sec( fc::time_point::now() );
auto itr = by_key_idx.lower_bound( bucket_key( base_id, quote_id, bucket_size,
now - bucket_size ) );
auto orders = get_order_book( base, quote, 1 ); auto orders = get_order_book( base, quote, 1 );
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
if( itr != by_key_idx.end() && itr->key.base == base_id && itr->key.quote == quote_id && itr->key.seconds == bucket_size ) result.latest = trades[0].price;
for ( market_trade t: trades )
{ {
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 ); result.base_volume += t.value;
result.quote_volume += t.amount;
}
if (assets[0]->id == base_id) while (trades.size() == 100)
{ {
result.latest = trades[0].price; trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
result.percent_change = ( result.latest / ( price_to_real( itr->open_quote, assets[1]->precision ) / price_to_real( itr->open_base, assets[0]->precision ) ) - 1 ) * 100;
//result.lowest_ask = price_to_real( itr->low_quote, assets[1]->precision ) / price_to_real( itr->low_base, assets[0]->precision );
//result.highest_bid = price_to_real( itr->high_quote, assets[1]->precision ) / price_to_real( itr->high_base, assets[0]->precision );
result.lowest_ask = orders.asks[0].first;
result.highest_bid = orders.bids[0].first;
}
else
{
result.latest = trades[0].price;
result.percent_change = ( result.latest / ( price_to_real( itr->open_base, assets[1]->precision ) / price_to_real( itr->open_quote, assets[0]->precision ) ) - 1) * 100;
//result.lowest_ask = price_to_real( itr->low_base, assets[1]->precision ) / price_to_real( itr->low_quote, assets[0]->precision );
//result.highest_bid = price_to_real( itr->high_base, assets[1]->precision ) / price_to_real( itr->high_quote, assets[0]->precision );
result.lowest_ask = orders.bids[0].first;
result.highest_bid = orders.asks[0].first;
}
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
}
while (trades.size() == 100) trades = get_trade_history( base, quote, trades.back().date, fc::time_point_sec(), 1 );
{ result.percent_change = trades.size() > 0 ? ( ( result.latest / trades.back().price ) - 1 ) * 100 : 0;
for ( market_trade t: trades )
{
result.base_volume += t.amount;
result.quote_volume += t.value;
}
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
}
//if (assets[0]->id == base_id)
{
result.lowest_ask = orders.asks[0].price;
result.highest_bid = orders.bids[0].price;
} }
return result; return result;
@ -1111,19 +1094,19 @@ market_volume database_api_impl::get_24_volume( const string& base, const string
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
while (trades.size() == 100) while (trades.size() == 100)
{ {
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
} }
return result; return result;
@ -1137,6 +1120,7 @@ order_book database_api::get_order_book( const string& base, const string& quote
order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const
{ {
using boost::multiprecision::uint128_t;
FC_ASSERT( limit <= 50 ); FC_ASSERT( limit <= 50 );
order_book result; order_book result;
@ -1156,21 +1140,28 @@ order_book database_api_impl::get_order_book( const string& base, const string&
auto price_to_real = [&]( const price& p ) auto price_to_real = [&]( const price& p )
{ {
if( p.base.asset_id == base_id ) if( p.base.asset_id == base_id )
return asset_to_real( p.quote, assets[1]->precision ) / asset_to_real( p.base, assets[0]->precision ); return asset_to_real( p.base, assets[0]->precision ) / asset_to_real( p.quote, assets[1]->precision );
else else
return asset_to_real( p.base, assets[1]->precision ) / asset_to_real( p.quote, assets[0]->precision ); return asset_to_real( p.quote, assets[0]->precision ) / asset_to_real( p.base, assets[1]->precision );
}; };
for( const auto& o : orders ) { for( const auto& o : orders )
{
if( o.sell_price.base.asset_id == base_id ) if( o.sell_price.base.asset_id == base_id )
{ {
result.asks.push_back( std::make_pair( price_to_real(o.sell_price), order ord;
asset_to_real(o.sell_price.base, assets[0]->precision)) ); ord.price = price_to_real( o.sell_price );
ord.quote = asset_to_real( share_type( ( uint128_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[1]->precision );
ord.base = asset_to_real( o.for_sale, assets[0]->precision );
result.bids.push_back( ord );
} }
else else
{ {
result.bids.push_back( std::make_pair( price_to_real(o.sell_price), order ord;
asset_to_real(o.sell_price.quote, assets[0]->precision ) ) ); ord.price = price_to_real( o.sell_price );
ord.quote = asset_to_real( o.for_sale, assets[1]->precision );
ord.base = asset_to_real( share_type( ( uint64_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[0]->precision );
result.asks.push_back( ord );
} }
} }
@ -1225,13 +1216,13 @@ vector<market_trade> database_api_impl::get_trade_history( const string& base,
if( assets[0]->id == itr->op.receives.asset_id ) if( assets[0]->id == itr->op.receives.asset_id )
{ {
trade.amount = price_to_real( itr->op.receives.amount, assets[0]->precision ); trade.amount = price_to_real( itr->op.pays.amount, assets[1]->precision );
trade.value = price_to_real( itr->op.pays.amount, assets[1]->precision ); trade.value = price_to_real( itr->op.receives.amount, assets[0]->precision );
} }
else else
{ {
trade.amount = price_to_real( itr->op.pays.amount, assets[0]->precision ); trade.amount = price_to_real( itr->op.receives.amount, assets[1]->precision );
trade.value = price_to_real( itr->op.receives.amount, assets[1]->precision ); trade.value = price_to_real( itr->op.pays.amount, assets[0]->precision );
} }
trade.date = itr->time; trade.date = itr->time;

View file

@ -64,40 +64,47 @@ using namespace std;
class database_api_impl; class database_api_impl;
struct order
{
double price;
double quote;
double base;
};
struct order_book struct order_book
{ {
string base; string base;
string quote; string quote;
vector< pair<double,double> > bids; vector< order > bids;
vector< pair<double,double> > asks; vector< order > asks;
}; };
struct market_ticker struct market_ticker
{ {
string base; string base;
string quote; string quote;
double latest; double latest;
double lowest_ask; double lowest_ask;
double highest_bid; double highest_bid;
double percent_change; double percent_change;
double base_volume; double base_volume;
double quote_volume; double quote_volume;
}; };
struct market_volume struct market_volume
{ {
string base; string base;
string quote; string quote;
double base_volume; double base_volume;
double quote_volume; double quote_volume;
}; };
struct market_trade struct market_trade
{ {
fc::time_point_sec date; fc::time_point_sec date;
double price; double price;
double amount; double amount;
double value; double value;
}; };
/** /**
@ -116,7 +123,7 @@ class database_api
///////////// /////////////
// Objects // // Objects //
///////////// /////////////
/** /**
* @brief Get the objects corresponding to the provided IDs * @brief Get the objects corresponding to the provided IDs
* @param ids IDs of the objects to retrieve * @param ids IDs of the objects to retrieve
@ -202,7 +209,7 @@ class database_api
////////// //////////
// Keys // // Keys //
////////// //////////
vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const; vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const;
////////////// //////////////
@ -465,9 +472,9 @@ class database_api
*/ */
map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const;
/// WORKERS /// WORKERS
/** /**
* Return the worker objects associated with this account. * Return the worker objects associated with this account.
*/ */
@ -515,7 +522,7 @@ class database_api
bool verify_authority( const signed_transaction& trx )const; bool verify_authority( const signed_transaction& trx )const;
/** /**
* @return true if the signers have enough authority to authorize an account * @return true if the signers have enough authority to authorize an account
*/ */
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const; bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
@ -553,6 +560,8 @@ class database_api
}; };
} } } }
FC_REFLECT( graphene::app::order, (price)(quote)(base) );
FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) ); FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) );
FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) );
FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) );

View file

@ -849,6 +849,51 @@ class wallet_api
uint32_t timeout_sec = 0, uint32_t timeout_sec = 0,
bool fill_or_kill = false, bool fill_or_kill = false,
bool broadcast = false); bool broadcast = false);
/** Place a limit order attempting to sell one asset for another.
*
* This API call abstracts away some of the details of the sell_asset call to be more
* user friendly. All orders placed with sell never timeout and will not be killed if they
* cannot be filled immediately. If you wish for one of these parameters to be different,
* then sell_asset should be used instead.
*
* @param seller_account the account providing the asset being sold, and which will
* receive the processed of the sale.
* @param base The name or id of the asset to sell.
* @param quote The name or id of the asset to recieve.
* @param rate The rate in base:quote at which you want to sell.
* @param amount The amount of base you want to sell.
* @param broadcast true to broadcast the transaction on the network.
* @returns The signed transaction selling the funds.
*/
signed_transaction sell( string seller_account,
string base,
string quote,
double rate,
double amount,
bool broadcast );
/** Place a limit order attempting to buy one asset with another.
*
* This API call abstracts away some of the details of the sell_asset call to be more
* user friendly. All orders placed with buy never timeout and will not be killed if they
* cannot be filled immediately. If you wish for one of these parameters to be different,
* then sell_asset should be used instead.
*
* @param buyer_account The account buying the asset for another asset.
* @param base The name or id of the asset to buy.
* @param quote The name or id of the assest being offered as payment.
* @param rate The rate in base:quote at which you want to buy.
* @param amount the amount of base you want to buy.
* @param broadcast true to broadcast the transaction on the network.
* @param The signed transaction selling the funds.
*/
signed_transaction buy( string buyer_account,
string base,
string quote,
double rate,
double amount,
bool broadcast );
/** Borrow an asset or update the debt/collateral ratio for the loan. /** Borrow an asset or update the debt/collateral ratio for the loan.
* *
@ -1401,6 +1446,8 @@ class wallet_api
const approval_delta& delta, const approval_delta& delta,
bool broadcast /* = false */ bool broadcast /* = false */
); );
order_book get_order_book( const string& base, const string& quote, unsigned limit = 50);
void dbg_make_uia(string creator, string symbol); void dbg_make_uia(string creator, string symbol);
void dbg_make_mia(string creator, string symbol); void dbg_make_mia(string creator, string symbol);
@ -1517,6 +1564,8 @@ FC_API( graphene::wallet::wallet_api,
(upgrade_account) (upgrade_account)
(create_account_with_brain_key) (create_account_with_brain_key)
(sell_asset) (sell_asset)
(sell)
(buy)
(borrow_asset) (borrow_asset)
(cancel_order) (cancel_order)
(transfer) (transfer)
@ -1589,4 +1638,5 @@ FC_API( graphene::wallet::wallet_api,
(blind_transfer) (blind_transfer)
(blind_history) (blind_history)
(receive_blind_transfer) (receive_blind_transfer)
(get_order_book)
) )

View file

@ -280,7 +280,7 @@ private:
auto iter = _wallet.pending_witness_registrations.find(witness_name); auto iter = _wallet.pending_witness_registrations.find(witness_name);
FC_ASSERT(iter != _wallet.pending_witness_registrations.end()); FC_ASSERT(iter != _wallet.pending_witness_registrations.end());
std::string wif_key = iter->second; std::string wif_key = iter->second;
// get the list key id this key is registered with in the chain // get the list key id this key is registered with in the chain
fc::optional<fc::ecc::private_key> witness_private_key = wif_to_key(wif_key); fc::optional<fc::ecc::private_key> witness_private_key = wif_to_key(wif_key);
FC_ASSERT(witness_private_key); FC_ASSERT(witness_private_key);
@ -316,12 +316,12 @@ private:
if( optional_account ) if( optional_account )
claim_registered_account(*optional_account); claim_registered_account(*optional_account);
} }
if (!_wallet.pending_witness_registrations.empty()) if (!_wallet.pending_witness_registrations.empty())
{ {
// make a vector of the owner accounts for witnesses pending registration // make a vector of the owner accounts for witnesses pending registration
std::vector<string> pending_witness_names = boost::copy_range<std::vector<string> >(boost::adaptors::keys(_wallet.pending_witness_registrations)); std::vector<string> pending_witness_names = boost::copy_range<std::vector<string> >(boost::adaptors::keys(_wallet.pending_witness_registrations));
// look up the owners on the blockchain // look up the owners on the blockchain
std::vector<fc::optional<graphene::chain::account_object>> owner_account_objects = _remote_db->lookup_account_names(pending_witness_names); std::vector<fc::optional<graphene::chain::account_object>> owner_account_objects = _remote_db->lookup_account_names(pending_witness_names);
@ -365,9 +365,9 @@ private:
// if the user executes the same command twice in quick succession, // if the user executes the same command twice in quick succession,
// we might generate the same transaction id, and cause the second // we might generate the same transaction id, and cause the second
// transaction to be rejected. This can be avoided by altering the // transaction to be rejected. This can be avoided by altering the
// second transaction slightly (bumping up the expiration time by // second transaction slightly (bumping up the expiration time by
// a second). Keep track of recent transaction ids we've generated // a second). Keep track of recent transaction ids we've generated
// so we can know if we need to do this // so we can know if we need to do this
struct recently_generated_transaction_record struct recently_generated_transaction_record
{ {
@ -377,7 +377,7 @@ private:
struct timestamp_index{}; struct timestamp_index{};
typedef boost::multi_index_container<recently_generated_transaction_record, typedef boost::multi_index_container<recently_generated_transaction_record,
boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::member<recently_generated_transaction_record, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::member<recently_generated_transaction_record,
graphene::chain::transaction_id_type, graphene::chain::transaction_id_type,
&recently_generated_transaction_record::transaction_id>, &recently_generated_transaction_record::transaction_id>,
std::hash<graphene::chain::transaction_id_type> >, std::hash<graphene::chain::transaction_id_type> >,
boost::multi_index::ordered_non_unique<boost::multi_index::tag<timestamp_index>, boost::multi_index::ordered_non_unique<boost::multi_index::tag<timestamp_index>,
@ -686,7 +686,7 @@ public:
if (!optional_private_key) if (!optional_private_key)
FC_THROW("Invalid private key"); FC_THROW("Invalid private key");
graphene::chain::public_key_type wif_pub_key = optional_private_key->get_public_key(); graphene::chain::public_key_type wif_pub_key = optional_private_key->get_public_key();
account_object account = get_account( account_name_or_id ); account_object account = get_account( account_name_or_id );
// make a list of all current public keys for the named account // make a list of all current public keys for the named account
@ -1042,7 +1042,7 @@ public:
{ try { { try {
int active_key_index = find_first_unused_derived_key_index(owner_privkey); int active_key_index = find_first_unused_derived_key_index(owner_privkey);
fc::ecc::private_key active_privkey = derive_private_key( key_to_wif(owner_privkey), active_key_index); fc::ecc::private_key active_privkey = derive_private_key( key_to_wif(owner_privkey), active_key_index);
int memo_key_index = find_first_unused_derived_key_index(active_privkey); int memo_key_index = find_first_unused_derived_key_index(active_privkey);
fc::ecc::private_key memo_privkey = derive_private_key( key_to_wif(active_privkey), memo_key_index); fc::ecc::private_key memo_privkey = derive_private_key( key_to_wif(active_privkey), memo_key_index);
@ -1350,7 +1350,7 @@ public:
return sign_transaction( tx, broadcast ); return sign_transaction( tx, broadcast );
} FC_CAPTURE_AND_RETHROW( (authorizing_account)(account_to_list)(new_listing_status)(broadcast) ) } } FC_CAPTURE_AND_RETHROW( (authorizing_account)(account_to_list)(new_listing_status)(broadcast) ) }
signed_transaction create_committee_member(string owner_account, string url, signed_transaction create_committee_member(string owner_account, string url,
bool broadcast /* = false */) bool broadcast /* = false */)
{ try { { try {
@ -1370,7 +1370,7 @@ public:
witness_object get_witness(string owner_account) witness_object get_witness(string owner_account)
{ {
try try
{ {
fc::optional<witness_id_type> witness_id = maybe_id<witness_id_type>(owner_account); fc::optional<witness_id_type> witness_id = maybe_id<witness_id_type>(owner_account);
if (witness_id) if (witness_id)
@ -1405,7 +1405,7 @@ public:
committee_member_object get_committee_member(string owner_account) committee_member_object get_committee_member(string owner_account)
{ {
try try
{ {
fc::optional<committee_member_id_type> committee_member_id = maybe_id<committee_member_id_type>(owner_account); fc::optional<committee_member_id_type> committee_member_id = maybe_id<committee_member_id_type>(owner_account);
if (committee_member_id) if (committee_member_id)
@ -1460,7 +1460,7 @@ public:
tx.operations.push_back( witness_create_op ); tx.operations.push_back( witness_create_op );
set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees);
tx.validate(); tx.validate();
_wallet.pending_witness_registrations[owner_account] = key_to_wif(witness_private_key); _wallet.pending_witness_registrations[owner_account] = key_to_wif(witness_private_key);
return sign_transaction( tx, broadcast ); return sign_transaction( tx, broadcast );
@ -1774,7 +1774,7 @@ public:
if (account_object_to_modify.options.num_witness == desired_number_of_witnesses && if (account_object_to_modify.options.num_witness == desired_number_of_witnesses &&
account_object_to_modify.options.num_committee == desired_number_of_committee_members) account_object_to_modify.options.num_committee == desired_number_of_committee_members)
FC_THROW("Account ${account} is already voting for ${witnesses} witnesses and ${committee_members} committee_members", FC_THROW("Account ${account} is already voting for ${witnesses} witnesses and ${committee_members} committee_members",
("account", account_to_modify)("witnesses", desired_number_of_witnesses)("committee_members",desired_number_of_witnesses)); ("account", account_to_modify)("witnesses", desired_number_of_witnesses)("committee_members",desired_number_of_witnesses));
account_object_to_modify.options.num_witness = desired_number_of_witnesses; account_object_to_modify.options.num_witness = desired_number_of_witnesses;
account_object_to_modify.options.num_committee = desired_number_of_committee_members; account_object_to_modify.options.num_committee = desired_number_of_committee_members;
@ -2161,11 +2161,94 @@ public:
for( auto& r : records ) for( auto& r : records )
{ {
asset_object as = get_asset( r.amount.asset_id ); asset_object as = get_asset( r.amount.asset_id );
ss << fc::get_approximate_relative_time_string( r.date ) ss << fc::get_approximate_relative_time_string( r.date )
<< " " << as.amount_to_pretty_string( r.amount ) << " " << r.from_label << " => " << r.to_label << " " << r.memo <<"\n"; << " " << as.amount_to_pretty_string( r.amount ) << " " << r.from_label << " => " << r.to_label << " " << r.memo <<"\n";
} }
return ss.str(); return ss.str();
}; };
m["get_order_book"] = [this](variant result, const fc::variants& a)
{
auto orders = result.as<order_book>();
auto bids = orders.bids;
auto asks = orders.asks;
std::stringstream ss;
std::stringstream sum_stream;
sum_stream << "Sum(" << orders.base << ')';
double bid_sum = 0;
double ask_sum = 0;
const int spacing = 20;
auto prettify_num = [&]( double n )
{
//ss << n;
if (abs( round( n ) - n ) < 0.00000000001 )
{
ss << setiosflags( !ios::fixed ) << (int) n;
}
else if (n - floor(n) < 0.000001)
{
ss << setiosflags( ios::fixed ) << setprecision(10) << n;
}
else
{
ss << setiosflags( ios::fixed ) << setprecision(6) << n;
}
};
ss << setprecision( 8 ) << setiosflags( ios::fixed ) << setiosflags( ios::left );
ss << ' ' << setw( (spacing * 4) + 6 ) << "BUY ORDERS" << "SELL ORDERS\n"
<< ' ' << setw( spacing + 1 ) << "Price" << setw( spacing ) << orders.quote << ' ' << setw( spacing )
<< orders.base << ' ' << setw( spacing ) << sum_stream.str()
<< " " << setw( spacing + 1 ) << "Price" << setw( spacing ) << orders.quote << ' ' << setw( spacing )
<< orders.base << ' ' << setw( spacing ) << sum_stream.str()
<< "\n====================================================================================="
<< "|=====================================================================================\n";
for (int i = 0; i < bids.size() || i < asks.size() ; i++)
{
if ( i < bids.size() )
{
bid_sum += bids[i].base;
ss << ' ' << setw( spacing );
prettify_num( bids[i].price );
ss << ' ' << setw( spacing );
prettify_num( bids[i].quote );
ss << ' ' << setw( spacing );
prettify_num( bids[i].base );
ss << ' ' << setw( spacing );
prettify_num( bid_sum );
ss << ' ';
}
else
{
ss << setw( (spacing * 4) + 5 ) << ' ';
}
ss << '|';
if ( i < asks.size() )
{
ask_sum += asks[i].base;
ss << ' ' << setw( spacing );
prettify_num( asks[i].price );
ss << ' ' << setw( spacing );
prettify_num( asks[i].quote );
ss << ' ' << setw( spacing );
prettify_num( asks[i].base );
ss << ' ' << setw( spacing );
prettify_num( ask_sum );
}
ss << '\n';
}
ss << endl
<< "Buy Total: " << bid_sum << ' ' << orders.base << endl
<< "Sell Total: " << ask_sum << ' ' << orders.base << endl;
return ss.str();
};
return m; return m;
} }
@ -2392,7 +2475,7 @@ public:
dbg_make_uia(master.name, "SHILL"); dbg_make_uia(master.name, "SHILL");
} catch(...) {/* Ignore; the asset probably already exists.*/} } catch(...) {/* Ignore; the asset probably already exists.*/}
fc::time_point start = fc::time_point::now(); fc::time_point start = fc::time_point::now();
for( int i = 0; i < number_of_accounts; ++i ) for( int i = 0; i < number_of_accounts; ++i )
{ {
std::ostringstream brain_key; std::ostringstream brain_key;
@ -2474,7 +2557,7 @@ std::string operation_printer::operator()(const T& op)const
//op.get_balance_delta( acc, result ); //op.get_balance_delta( acc, result );
auto a = wallet.get_asset( op.fee.asset_id ); auto a = wallet.get_asset( op.fee.asset_id );
auto payer = wallet.get_account( op.fee_payer() ); auto payer = wallet.get_account( op.fee_payer() );
string op_name = fc::get_typename<T>::name(); string op_name = fc::get_typename<T>::name();
if( op_name.find_last_of(':') != string::npos ) if( op_name.find_last_of(':') != string::npos )
op_name.erase(0, op_name.find_last_of(':')+1); op_name.erase(0, op_name.find_last_of(':')+1);
@ -2494,7 +2577,7 @@ std::string operation_printer::operator()(const transfer_from_blind_operation& o
auto a = wallet.get_asset( op.fee.asset_id ); auto a = wallet.get_asset( op.fee.asset_id );
auto receiver = wallet.get_account( op.to ); auto receiver = wallet.get_account( op.to );
out << receiver.name out << receiver.name
<< " received " << a.amount_to_pretty_string( op.amount ) << " from blinded balance"; << " received " << a.amount_to_pretty_string( op.amount ) << " from blinded balance";
return ""; return "";
} }
@ -2504,7 +2587,7 @@ std::string operation_printer::operator()(const transfer_to_blind_operation& op)
auto a = wallet.get_asset( op.amount.asset_id ); auto a = wallet.get_asset( op.amount.asset_id );
auto sender = wallet.get_account( op.from ); auto sender = wallet.get_account( op.from );
out << sender.name out << sender.name
<< " sent " << a.amount_to_pretty_string( op.amount ) << " to " << op.outputs.size() << " blinded balance" << (op.outputs.size()>1?"s":"") << " sent " << a.amount_to_pretty_string( op.amount ) << " to " << op.outputs.size() << " blinded balance" << (op.outputs.size()>1?"s":"")
<< " fee: " << fa.amount_to_pretty_string( op.fee ); << " fee: " << fa.amount_to_pretty_string( op.fee );
return ""; return "";
@ -2641,7 +2724,7 @@ vector<operation_detail> wallet_api::get_account_history(string name, int limit)
while( limit > 0 ) while( limit > 0 )
{ {
operation_history_id_type start; operation_history_id_type start;
if( result.size() ) if( result.size() )
{ {
start = result.back().op.id; start = result.back().op.id;
start = start + 1; start = start + 1;
@ -3077,7 +3160,7 @@ signed_transaction wallet_api::whitelist_account(string authorizing_account,
return my->whitelist_account(authorizing_account, account_to_list, new_listing_status, broadcast); return my->whitelist_account(authorizing_account, account_to_list, new_listing_status, broadcast);
} }
signed_transaction wallet_api::create_committee_member(string owner_account, string url, signed_transaction wallet_api::create_committee_member(string owner_account, string url,
bool broadcast /* = false */) bool broadcast /* = false */)
{ {
return my->create_committee_member(owner_account, url, broadcast); return my->create_committee_member(owner_account, url, broadcast);
@ -3183,7 +3266,7 @@ signed_transaction wallet_api::set_desired_witness_and_committee_member_count(st
uint16_t desired_number_of_committee_members, uint16_t desired_number_of_committee_members,
bool broadcast /* = false */) bool broadcast /* = false */)
{ {
return my->set_desired_witness_and_committee_member_count(account_to_modify, desired_number_of_witnesses, return my->set_desired_witness_and_committee_member_count(account_to_modify, desired_number_of_witnesses,
desired_number_of_committee_members, broadcast); desired_number_of_committee_members, broadcast);
} }
@ -3522,7 +3605,7 @@ vector< signed_transaction > wallet_api_impl::import_balance( string name_or_id,
if( broadcast ) if( broadcast )
_remote_net_broadcast->broadcast_transaction(signed_tx); _remote_net_broadcast->broadcast_transaction(signed_tx);
} }
return result; return result;
} FC_CAPTURE_AND_RETHROW( (name_or_id) ) } } FC_CAPTURE_AND_RETHROW( (name_or_id) ) }
@ -3552,6 +3635,28 @@ signed_transaction wallet_api::sell_asset(string seller_account,
symbol_to_receive, expiration, fill_or_kill, broadcast); symbol_to_receive, expiration, fill_or_kill, broadcast);
} }
signed_transaction wallet_api::sell( string seller_account,
string base,
string quote,
double rate,
double amount,
bool broadcast )
{
return my->sell_asset( seller_account, std::to_string( amount ), base,
std::to_string( rate * amount ), quote, 0, false, broadcast );
}
signed_transaction wallet_api::buy( string buyer_account,
string base,
string quote,
double rate,
double amount,
bool broadcast )
{
return my->sell_asset( buyer_account, std::to_string( rate * amount ), quote,
std::to_string( amount ), base, 0, false, broadcast );
}
signed_transaction wallet_api::borrow_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) string asset_symbol, string amount_of_collateral, bool broadcast)
{ {
@ -3675,7 +3780,7 @@ vector<asset> wallet_api::get_blind_balances( string key_or_label )
} }
blind_confirmation wallet_api::transfer_from_blind( string from_blind_account_key_or_label, blind_confirmation wallet_api::transfer_from_blind( string from_blind_account_key_or_label,
string to_account_id_or_name, string to_account_id_or_name,
string amount_in, string amount_in,
string symbol, string symbol,
bool broadcast ) bool broadcast )
@ -3694,7 +3799,7 @@ blind_confirmation wallet_api::transfer_from_blind( string from_blind_account_ke
auto conf = blind_transfer_help( from_blind_account_key_or_label, auto conf = blind_transfer_help( from_blind_account_key_or_label,
from_blind_account_key_or_label, from_blind_account_key_or_label,
blind_in, symbol, false, true/*to_temp*/ ); blind_in, symbol, false, true/*to_temp*/ );
FC_ASSERT( conf.outputs.size() > 0 ); FC_ASSERT( conf.outputs.size() > 0 );
@ -3709,24 +3814,24 @@ blind_confirmation wallet_api::transfer_from_blind( string from_blind_account_ke
conf.trx.operations.push_back(from_blind); conf.trx.operations.push_back(from_blind);
ilog( "about to validate" ); ilog( "about to validate" );
conf.trx.validate(); conf.trx.validate();
if( broadcast && conf.outputs.size() == 2 ) { if( broadcast && conf.outputs.size() == 2 ) {
// Save the change // Save the change
blind_confirmation::output conf_output; blind_confirmation::output conf_output;
blind_confirmation::output change_output = conf.outputs[0]; blind_confirmation::output change_output = conf.outputs[0];
// The wallet must have a private key for confirmation.to, this is used to decrypt the memo // The wallet must have a private key for confirmation.to, this is used to decrypt the memo
public_key_type from_key = get_public_key(from_blind_account_key_or_label); public_key_type from_key = get_public_key(from_blind_account_key_or_label);
conf_output.confirmation.to = from_key; conf_output.confirmation.to = from_key;
conf_output.confirmation.one_time_key = change_output.confirmation.one_time_key; conf_output.confirmation.one_time_key = change_output.confirmation.one_time_key;
conf_output.confirmation.encrypted_memo = change_output.confirmation.encrypted_memo; conf_output.confirmation.encrypted_memo = change_output.confirmation.encrypted_memo;
conf_output.confirmation_receipt = conf_output.confirmation; conf_output.confirmation_receipt = conf_output.confirmation;
//try { //try {
receive_blind_transfer( conf_output.confirmation_receipt, from_blind_account_key_or_label, "@"+to_account.name ); receive_blind_transfer( conf_output.confirmation_receipt, from_blind_account_key_or_label, "@"+to_account.name );
//} catch ( ... ){} //} catch ( ... ){}
} }
ilog( "about to broadcast" ); ilog( "about to broadcast" );
conf.trx = sign_transaction( conf.trx, broadcast ); conf.trx = sign_transaction( conf.trx, broadcast );
@ -3747,7 +3852,7 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
string symbol, string symbol,
bool broadcast, bool broadcast,
bool to_temp ) bool to_temp )
{ {
blind_confirmation confirm; blind_confirmation confirm;
try { try {
@ -3791,7 +3896,7 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
blinding_factors.push_back( start->data.blinding_factor ); blinding_factors.push_back( start->data.blinding_factor );
total_amount += start->amount; total_amount += start->amount;
if( total_amount >= amount + blind_tr.fee ) if( total_amount >= amount + blind_tr.fee )
break; break;
} }
++start; ++start;
@ -3859,7 +3964,7 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
conf_output.decrypted_memo.amount = change; conf_output.decrypted_memo.amount = change;
conf_output.decrypted_memo.blinding_factor = change_blind_factor; conf_output.decrypted_memo.blinding_factor = change_blind_factor;
conf_output.decrypted_memo.commitment = change_out.commitment; conf_output.decrypted_memo.commitment = change_out.commitment;
conf_output.decrypted_memo.check = from_secret._hash[0]; conf_output.decrypted_memo.check = from_secret._hash[0];
conf_output.confirmation.one_time_key = one_time_key.get_public_key(); conf_output.confirmation.one_time_key = one_time_key.get_public_key();
conf_output.confirmation.to = from_key; conf_output.confirmation.to = from_key;
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( from_secret, fc::raw::pack( conf_output.decrypted_memo ) ); conf_output.confirmation.encrypted_memo = fc::aes_encrypt( from_secret, fc::raw::pack( conf_output.decrypted_memo ) );
@ -3877,7 +3982,7 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
conf_output.decrypted_memo.amount = amount; conf_output.decrypted_memo.amount = amount;
conf_output.decrypted_memo.blinding_factor = blind_factor; conf_output.decrypted_memo.blinding_factor = blind_factor;
conf_output.decrypted_memo.commitment = to_out.commitment; conf_output.decrypted_memo.commitment = to_out.commitment;
conf_output.decrypted_memo.check = secret._hash[0]; conf_output.decrypted_memo.check = secret._hash[0];
conf_output.confirmation.one_time_key = one_time_key.get_public_key(); conf_output.confirmation.one_time_key = one_time_key.get_public_key();
conf_output.confirmation.to = to_key; conf_output.confirmation.to = to_key;
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) ); conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) );
@ -3887,9 +3992,9 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
confirm.outputs.push_back( conf_output ); confirm.outputs.push_back( conf_output );
/** commitments must be in sorted order */ /** commitments must be in sorted order */
std::sort( blind_tr.outputs.begin(), blind_tr.outputs.end(), std::sort( blind_tr.outputs.begin(), blind_tr.outputs.end(),
[&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } ); [&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } );
std::sort( blind_tr.inputs.begin(), blind_tr.inputs.end(), std::sort( blind_tr.inputs.begin(), blind_tr.inputs.end(),
[&]( const blind_input& a, const blind_input& b ){ return a.commitment < b.commitment; } ); [&]( const blind_input& a, const blind_input& b ){ return a.commitment < b.commitment; } );
confirm.trx.operations.emplace_back( std::move(blind_tr) ); confirm.trx.operations.emplace_back( std::move(blind_tr) );
@ -3914,10 +4019,10 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
* Transfers a public balance from @from to one or more blinded balances using a * Transfers a public balance from @from to one or more blinded balances using a
* stealth transfer. * stealth transfer.
*/ */
blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name, blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name,
string asset_symbol, string asset_symbol,
/** map from key or label to amount */ /** map from key or label to amount */
vector<pair<string, string>> to_amounts, vector<pair<string, string>> to_amounts,
bool broadcast ) bool broadcast )
{ try { { try {
FC_ASSERT( !is_locked() ); FC_ASSERT( !is_locked() );
@ -3948,7 +4053,7 @@ blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name
auto amount = asset_obj->amount_from_string(item.second); auto amount = asset_obj->amount_from_string(item.second);
total_amount += amount; total_amount += amount;
fc::ecc::public_key to_pub_key = to_key; fc::ecc::public_key to_pub_key = to_key;
blind_output out; blind_output out;
@ -3964,7 +4069,7 @@ blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name
conf_output.decrypted_memo.amount = amount; conf_output.decrypted_memo.amount = amount;
conf_output.decrypted_memo.blinding_factor = blind_factor; conf_output.decrypted_memo.blinding_factor = blind_factor;
conf_output.decrypted_memo.commitment = out.commitment; conf_output.decrypted_memo.commitment = out.commitment;
conf_output.decrypted_memo.check = secret._hash[0]; conf_output.decrypted_memo.check = secret._hash[0];
conf_output.confirmation.one_time_key = one_time_key.get_public_key(); conf_output.confirmation.one_time_key = one_time_key.get_public_key();
conf_output.confirmation.to = to_key; conf_output.confirmation.to = to_key;
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) ); conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) );
@ -3978,7 +4083,7 @@ blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name
bop.blinding_factor = fc::ecc::blind_sum( blinding_factors, blinding_factors.size() ); bop.blinding_factor = fc::ecc::blind_sum( blinding_factors, blinding_factors.size() );
/** commitments must be in sorted order */ /** commitments must be in sorted order */
std::sort( bop.outputs.begin(), bop.outputs.end(), std::sort( bop.outputs.begin(), bop.outputs.end(),
[&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } ); [&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } );
confirm.trx.operations.push_back( bop ); confirm.trx.operations.push_back( bop );
@ -4024,7 +4129,7 @@ blind_receipt wallet_api::receive_blind_transfer( string confirmation_receipt, s
result.to_key = *conf.to; result.to_key = *conf.to;
result.to_label = get_key_label( result.to_key ); result.to_label = get_key_label( result.to_key );
if( memo.from ) if( memo.from )
{ {
result.from_key = *memo.from; result.from_key = *memo.from;
result.from_label = get_key_label( result.from_key ); result.from_label = get_key_label( result.from_key );
@ -4044,7 +4149,7 @@ blind_receipt wallet_api::receive_blind_transfer( string confirmation_receipt, s
// confirm the amount matches the commitment (verify the blinding factor) // confirm the amount matches the commitment (verify the blinding factor)
auto commtiment_test = fc::ecc::blind( memo.blinding_factor, memo.amount.amount.value ); auto commtiment_test = fc::ecc::blind( memo.blinding_factor, memo.amount.amount.value );
FC_ASSERT( fc::ecc::verify_sum( {commtiment_test}, {memo.commitment}, 0 ) ); FC_ASSERT( fc::ecc::verify_sum( {commtiment_test}, {memo.commitment}, 0 ) );
blind_balance bal; blind_balance bal;
bal.amount = memo.amount; bal.amount = memo.amount;
bal.to = *conf.to; bal.to = *conf.to;
@ -4062,7 +4167,7 @@ blind_receipt wallet_api::receive_blind_transfer( string confirmation_receipt, s
auto child_key_itr = owner.key_auths.find( child_pubkey ); auto child_key_itr = owner.key_auths.find( child_pubkey );
if( child_key_itr != owner.key_auths.end() ) if( child_key_itr != owner.key_auths.end() )
my->_keys[child_key_itr->first] = key_to_wif( child_priv_key ); my->_keys[child_key_itr->first] = key_to_wif( child_priv_key );
// my->_wallet.blinded_balances[memo.amount.asset_id][bal.to].push_back( bal ); // my->_wallet.blinded_balances[memo.amount.asset_id][bal.to].push_back( bal );
result.date = fc::time_point::now(); result.date = fc::time_point::now();
@ -4079,7 +4184,7 @@ vector<blind_receipt> wallet_api::blind_history( string key_or_account )
vector<blind_receipt> result; vector<blind_receipt> result;
auto pub_key = get_public_key( key_or_account ); auto pub_key = get_public_key( key_or_account );
if( pub_key == public_key_type() ) if( pub_key == public_key_type() )
return vector<blind_receipt>(); return vector<blind_receipt>();
for( auto& r : my->_wallet.blind_receipts ) for( auto& r : my->_wallet.blind_receipts )
@ -4091,6 +4196,11 @@ vector<blind_receipt> wallet_api::blind_history( string key_or_account )
return result; return result;
} }
order_book wallet_api::get_order_book( const string& base, const string& quote, unsigned limit )
{
return( my->_remote_db->get_order_book( base, quote, limit ) );
}
signed_block_with_info::signed_block_with_info( const signed_block& block ) signed_block_with_info::signed_block_with_info( const signed_block& block )
: signed_block( block ) : signed_block( block )
{ {