asset::operator std::string()const { try { auto rounded_amnt = get_rounded_amount(); std::string int_part = fc::to_string(uint64_t(rounded_amnt/BTS_BLOCKCHAIN_SHARE) ); uint64_t fract = uint64_t(rounded_amnt % BTS_BLOCKCHAIN_SHARE + BTS_BLOCKCHAIN_SHARE); return int_part + "." + fc::to_string(fract).substr(1) + " " + fc::to_string(unit); } FC_RETHROW_EXCEPTIONS( warn, "unable to convert asset to string" ) }
asset& asset::operator -= ( const asset& o ) { FC_ASSERT( unit == o.unit ); auto old = *this;; amount -= o.amount; if( amount > old.amount ) { if( get_rounded_amount() == 0 ) { amount = 0; return *this; } FC_THROW_EXCEPTION( exception, "asset addition underflow ${a} - ${b} = ${c}", ("a", old)("b",o)("c",*this) ); } return *this; }
void match_orders( std::vector<signed_transaction>& matched, asset::type quote, asset::type base ) { try { ilog( "match orders.." ); auto bids = _market_db.get_bids( quote, base ); auto asks = _market_db.get_asks( quote, base ); wlog( "asks: ${asks}", ("asks",asks) ); wlog( "bids: ${bids}", ("bids",bids) ); fc::optional<trx_output> ask_change; fc::optional<trx_output> bid_change; fc::optional<trx_output> cover_change; address bid_payout_address; fc::optional<asset> bid_payout; asset cover_collat; fc::optional<claim_by_cover_output> cover_payout; signed_transaction market_trx; market_trx.timestamp = fc::time_point::now(); /** asks are sorted from low to high, so we start * with the lowest ask, and check to see if there are * any bids that are greaterthan or equal to the ask, if * there are then either the full bid or full ask will be * filled. If the full bid is filled, then move on to the * next bid, and save the leftover ask. If the left over * ask is filled, then move to the next ask. * * When there are no more pairs that can be matched, exit * the loop and any partial payouts are made. */ auto ask_itr = asks.begin(); auto bid_itr = bids.rbegin(); while( ask_itr != asks.end() && bid_itr != bids.rend() ) { trx_output working_ask; trx_output working_bid; if( ask_change ) { working_ask = *ask_change; } else { working_ask = get_output( ask_itr->location ); } if( bid_change ) { working_bid = *bid_change; } else { working_bid = get_output( bid_itr->location); } claim_by_bid_output bid_claim = working_bid.as<claim_by_bid_output>(); if( working_ask.claim_func == claim_by_long ) { auto long_claim = working_ask.as<claim_by_long_output>(); if( long_claim.ask_price > bid_claim.ask_price ) { break; // exit the while loop, no more trades can occur } asset bid_amount = working_bid.get_amount() * bid_claim.ask_price; asset ask_amount = working_ask.get_amount() * long_claim.ask_price; FC_ASSERT( bid_amount.unit == ask_amount.unit ); auto trade_amount = std::min(bid_amount,ask_amount); ilog( "bid amount: ${b} @ ${bp} ask amount: ${a} @ ${ap}", ("b",bid_amount)("a",ask_amount)("bp",bid_claim.ask_price)("ap",long_claim.ask_price) ); asset bid_change_amount = working_bid.get_amount(); bid_change_amount -= trade_amount * bid_claim.ask_price; ilog( "bid change.. ${c}", ("c",bid_change_amount) ); asset ask_change_amount = working_ask.get_amount(); ask_change_amount -= trade_amount * long_claim.ask_price; ilog( "ask change.. ${c}", ("c",ask_change_amount) ); if( ask_change_amount != bid_change_amount && ask_change_amount != asset(0,working_bid.unit) ) { FC_ASSERT( !"At least one of the bid or ask should be completely filled", "", ("ask_change_amount",ask_change_amount)("bid_change_amount",bid_change_amount) ); } bid_payout_address = bid_claim.pay_address; auto bid_payout_amount = bid_amount - (bid_change_amount * bid_claim.ask_price); if( bid_payout ) { *bid_payout += bid_payout_amount; } else { bid_payout = bid_payout_amount; } if( cover_payout ) { cover_payout->payoff_amount += trade_amount.get_rounded_amount(); cover_collat += (trade_amount * long_claim.ask_price)*2; } else { cover_payout = claim_by_cover_output(); cover_payout->owner = long_claim.pay_address; cover_payout->payoff_unit = trade_amount.unit; cover_payout->payoff_amount = trade_amount.get_rounded_amount(); cover_collat = (trade_amount * long_claim.ask_price)*2; } if( bid_change_amount != asset(0, working_bid.unit) ) { // TODO: accumulate fractional parts, round at the end?.... working_bid.amount = bid_change_amount.get_rounded_amount(); bid_change = working_bid; elog( "we DID NOT fill the bid..." ); } else // we have filled the bid! { elog( "we filled the bid..." ); market_trx.inputs.push_back( bid_itr->location ); market_trx.outputs.push_back( trx_output( claim_by_signature_output( bid_claim.pay_address ), bid_payout->get_rounded_asset() ) ); bid_change.reset(); bid_payout.reset(); ++bid_itr; } if( ask_change_amount != asset( 0, working_bid.unit ) ) { working_ask.amount = ask_change_amount.get_rounded_amount(); ask_change = working_ask; } else // we have filled the ask! { market_trx.inputs.push_back( ask_itr->location ); market_trx.outputs.push_back( trx_output( *cover_payout, cover_collat ) ); ask_change.reset(); cover_payout.reset(); ++ask_itr; } } else if( working_ask.claim_func == claim_by_bid ) { FC_ASSERT( !"Not Implemented" ); claim_by_bid_output ask_claim = working_ask.as<claim_by_bid_output>(); if( ask_claim.ask_price > bid_claim.ask_price ) { break; } // TODO: implement straight trades.. } else { FC_ASSERT( !"Ask must either be a claim by bid or claim by long", "", ("ask", working_ask) ); } } // while( ... ) if( ask_change && ask_itr != asks.end() ) market_trx.inputs.push_back( ask_itr->location ); if( bid_change && bid_itr != bids.rend() ) market_trx.inputs.push_back( bid_itr->location ); if( ask_change ) { ilog( "ask_change: ${ask_change}", ("ask_change",ask_change) ); market_trx.outputs.push_back( *ask_change ); } if( bid_change ) { ilog( "bid_change: ${bid_change}", ("bid_change",bid_change) ); market_trx.outputs.push_back( *bid_change ); } if( bid_payout ) { ilog( "bid_payout ${payout}", ("payout",bid_payout) ); market_trx.outputs.push_back( trx_output( claim_by_signature_output( bid_payout_address ), *bid_payout ) ); } else { wlog ( "NO BID PAYOUT" ); } if( cover_payout ) { ilog( "cover_payout ${payout}", ("payout",cover_payout) ); market_trx.outputs.push_back( trx_output( *cover_payout, cover_collat ) ); } wlog( "Market Transaction: ${trx}", ("trx", market_trx) ); if( market_trx.inputs.size() ) { FC_ASSERT( market_trx.outputs.size() ); matched.push_back(market_trx); } //ilog( "done match orders.." ); } FC_RETHROW_EXCEPTIONS( warn, "", ("quote",quote)("base",base) ) }
asset get_rounded_asset()const { return asset( get_rounded_amount(),unit); }