Esempio n. 1
0
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);
}
Esempio n. 2
0
/** 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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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);
}