TER Taker::cross (Offer const& offer) { assert (!done ()); /* Before we call flow we must set the limit right; for buy semantics we need to clamp the output. And we always want to clamp the input. */ Amounts limit (offer.amount()); if (! m_options.sell) limit = offer.quality ().ceil_out (limit, m_remain.out); limit = offer.quality().ceil_in (limit, m_remain.in); assert (limit.in <= offer.amount().in); assert (limit.out <= offer.amount().out); assert (limit.in <= m_remain.in); Amounts const amount (flow (limit, offer, account ())); m_remain.out -= amount.out; m_remain.in -= amount.in; assert (m_remain.in >= zero); return fill (offer, amount); }
/** Calculate the amount particular user could get through an offer. @param amount the maximum flow that is available to the taker. @param offer the offer to flow through. @param taker the person taking the offer. @return the maximum amount that can flow through this offer. */ Amounts Taker::flow (Amounts amount, Offer const& offer, Account const& taker) { // Limit taker's input by available funds less fees Amount const taker_funds (view ().accountFunds ( taker, amount.in, fhZERO_IF_FROZEN)); // Get fee rate paid by taker std::uint32_t const taker_charge_rate (rippleTransferRate (view (), taker, offer.account (), amount.in.getIssuer())); // Skip some math when there's no fee if (taker_charge_rate == QUALITY_ONE) { amount = offer.quality ().ceil_in (amount, taker_funds); } else { Amount const taker_charge (amountFromRate (taker_charge_rate)); amount = offer.quality ().ceil_in (amount, divide (taker_funds, taker_charge, taker_funds.issue ())); } // Best flow the owner can get. // Start out assuming entire offer will flow. Amounts owner_amount (amount); // Limit owner's output by available funds less fees Amount const owner_funds (view ().accountFunds ( offer.account (), owner_amount.out, fhZERO_IF_FROZEN)); // Get fee rate paid by owner std::uint32_t const owner_charge_rate (rippleTransferRate (view (), offer.account (), taker, amount.out.getIssuer())); if (owner_charge_rate == QUALITY_ONE) { // Skip some math when there's no fee owner_amount = offer.quality ().ceil_out (owner_amount, owner_funds); } else { Amount const owner_charge (amountFromRate (owner_charge_rate)); owner_amount = offer.quality ().ceil_out (owner_amount, divide (owner_funds, owner_charge, owner_funds.issue ())); } // Calculate the amount that will flow through the offer // This does not include the fees. return (owner_amount.in < amount.in) ? owner_amount : amount; }
TER Taker::cross (Offer const& leg1, Offer const& leg2) { // In bridged crossings, XRP must can't be the input to the first leg // or the output of the second leg. if (isXRP (leg1.amount ().in) || isXRP (leg2.amount ().out)) return tefINTERNAL; auto ret = do_cross ( leg1.amount (), leg1.quality (), leg1.owner (), leg2.amount (), leg2.quality (), leg2.owner ()); return fill (ret.first, leg1, ret.second, leg2); }
TER Taker::cross (Offer const& offer) { assert (!done ()); Amounts limit (offer.amount()); if (m_options.sell) limit = offer.quality().ceil_in (limit, m_remain.in); else limit = offer.quality ().ceil_out (limit, m_remain.out); assert (limit.out <= offer.amount().out); assert (limit.in <= offer.amount().in); Amounts const amount (flow (limit, offer, account ())); m_remain.out -= amount.out; m_remain.in -= amount.in; assert (m_remain.in >= zero); return fill (offer, amount); }
TER Taker::cross (Offer const& offer) { // In direct crossings, at least one leg must not be XRP. if (isXRP (offer.amount ().in) && isXRP (offer.amount ().out)) return tefINTERNAL; auto const amount = do_cross ( offer.amount (), offer.quality (), offer.owner ()); return fill (amount, offer); }
TER Taker::cross (Offer const& leg1, Offer const& leg2) { assert (!done ()); assert (leg1.amount ().out.isNative ()); assert (leg2.amount ().in.isNative ()); Amounts amount1 (leg1.amount()); Amounts amount2 (leg2.amount()); if (m_options.sell) amount1 = leg1.quality().ceil_in (amount1, m_remain.in); else amount2 = leg2.quality().ceil_out (amount2, m_remain.out); if (amount1.out <= amount2.in) amount2 = leg2.quality().ceil_in (amount2, amount1.out); else amount1 = leg1.quality().ceil_out (amount1, amount2.in); assert (amount1.out == amount2.in); // As written, flow can't handle a 3-party transfer, but this works for // us because the output of leg1 and the input leg2 are XRP. Amounts flow1 (flow (amount1, leg1, m_account)); amount2 = leg2.quality().ceil_in (amount2, flow1.out); Amounts flow2 (flow (amount2, leg2, m_account)); m_remain.out -= amount2.out; m_remain.in -= amount1.in; return fill (leg1, flow1, leg2, flow2); }