Example #1
0
Taker::Taker (CrossType cross_type, ApplyView& view,
    AccountID const& account, Amounts const& offer,
        std::uint32_t flags,
            beast::Journal journal)
    : BasicTaker (cross_type, account, offer, Quality(offer), flags,
        calculateRate(view, offer.in.getIssuer(), account),
        calculateRate(view, offer.out.getIssuer(), account), journal)
    , view_ (view)
    , xrp_flow_ (0)
    , direct_crossings_ (0)
    , bridge_crossings_ (0)
{
    assert (issue_in () == offer.in.issue ());
    assert (issue_out () == offer.out.issue ());

    if (journal_.debug)
    {
        journal_.debug << "Crossing as: " << to_string (account);

        if (isXRP (issue_in ()))
            journal_.debug << "   Offer in: " << format_amount (offer.in);
        else
            journal_.debug << "   Offer in: " << format_amount (offer.in) <<
                " (issuer: " << issue_in ().account << ")";

        if (isXRP (issue_out ()))
            journal_.debug << "  Offer out: " << format_amount (offer.out);
        else
            journal_.debug << "  Offer out: " << format_amount (offer.out) <<
                " (issuer: " << issue_out ().account << ")";

        journal_.debug <<
            "    Balance: " << format_amount (get_funds (account, offer.in));
    }
}
Example #2
0
    void
    attempt (
        bool sell,
        std::string name,
        Quality taker_quality,
        cross_attempt_offer const offer,
        std::string const funds,
        Quality cross_quality,
        cross_attempt_offer const cross,
        std::string const cross_funds,
        cross_attempt_offer const flow,
        Issue const& issue_in,
        Issue const& issue_out,
        Rate rate_in = parityRate,
        Rate rate_out = parityRate)
    {
        Amounts taker_offer (parse_amounts (
            offer.in, issue_in,
            offer.out, issue_out));

        Amounts cross_offer (parse_amounts (
            cross.in, issue_in,
            cross.out, issue_out));

        CrossType cross_type;

        if (isXRP (issue_out))
            cross_type = CrossType::IouToXrp;
        else if (isXRP (issue_in))
            cross_type = CrossType::XrpToIou;
        else
            cross_type = CrossType::IouToIou;

        // FIXME: We are always invoking the IOU-to-IOU taker. We should select
        // the correct type dynamically.
        TestTaker taker (cross_type, taker_offer, taker_quality,
            parse_amount (funds, issue_in), sell ? tfSell : 0,
            rate_in, rate_out);

        taker.set_funds (parse_amount (cross_funds, issue_out));

        auto result = taker.cross (cross_offer, cross_quality);

        Amounts const expected (parse_amounts (
            flow.in, issue_in,
            flow.out, issue_out));

        BEAST_EXPECT(expected == result);

        if (expected != result)
        {
            log <<
                "Expected: " << format_amount (expected.in) <<
                " : " << format_amount (expected.out) << '\n' <<
                "  Actual: " << format_amount (result.in) <<
                " : " << format_amount (result.out) << std::endl;
        }
    }
Example #3
0
void
Taker::consume_offer (Offer const& offer, Amounts const& order)
{
    if (order.in < zero)
        Throw<std::logic_error> ("flow with negative input.");

    if (order.out < zero)
        Throw<std::logic_error> ("flow with negative output.");

    if (journal_.debug) journal_.debug << "Consuming from offer " << offer;

    if (journal_.trace)
    {
        auto const& available = offer.amount ();

        journal_.trace << "   in:" << format_amount (available.in);
        journal_.trace << "  out:" << format_amount(available.out);
    }

    offer.consume (view_, order);
}
Example #4
0
void
BasicTaker::log_flow (char const* description, Flow const& flow)
{
    if (!journal_.debug)
        return;

    journal_.debug << description;

    if (isXRP (issue_in ()))
        journal_.debug << "   order in: " << format_amount (flow.order.in);
    else
        journal_.debug << "   order in: " << format_amount (flow.order.in) <<
            " (issuer: " << format_amount (flow.issuers.in) << ")";

    if (isXRP (issue_out ()))
        journal_.debug << "  order out: " << format_amount (flow.order.out);
    else
        journal_.debug << "  order out: " << format_amount (flow.order.out) <<
            " (issuer: " << format_amount (flow.issuers.out) << ")";
}
Example #5
0
// Calculates the bridged flow through the specified offers
std::pair<BasicTaker::Flow, BasicTaker::Flow>
BasicTaker::do_cross (
    Amounts offer1, Quality quality1, AccountID const& owner1,
    Amounts offer2, Quality quality2, AccountID const& owner2)
{
    assert (!done ());

    assert (!offer1.in.native ());
    assert (offer1.out.native ());
    assert (offer2.in.native ());
    assert (!offer2.out.native ());

    // If the taker owns the first leg of the offer, then the taker's available
    // funds aren't the limiting factor for the input - the offer itself is.
    auto leg1_in_funds = get_funds (account (), offer1.in);

    if (account () == owner1)
    {
        journal_.trace << "The taker owns the first leg of a bridge.";
        leg1_in_funds = std::max (leg1_in_funds, offer1.in);
    }

    // If the taker owns the second leg of the offer, then the taker's available
    // funds are not the limiting factor for the output - the offer itself is.
    auto leg2_out_funds = get_funds (owner2, offer2.out);

    if (account () == owner2)
    {
        journal_.trace << "The taker owns the second leg of a bridge.";
        leg2_out_funds = std::max (leg2_out_funds, offer2.out);
    }

    // The amount available to flow via XRP is the amount that the owner of the
    // first leg of the bridge has, up to the first leg's output.
    //
    // But, when both legs of a bridge are owned by the same person, the amount
    // of XRP that can flow between the two legs is, essentially, infinite
    // since all the owner is doing is taking out XRP of his left pocket
    // and putting it in his right pocket. In that case, we set the available
    // XRP to the largest of the two offers.
    auto xrp_funds = get_funds (owner1, offer1.out);

    if (owner1 == owner2)
    {
        journal_.trace << "The bridge endpoints are owneb by the same account.";
        xrp_funds = std::max (offer1.out, offer2.in);
    }

    if (journal_.debug)
    {
        journal_.debug << "Available bridge funds:";
        journal_.debug << "  leg1 in: " << format_amount (leg1_in_funds);
        journal_.debug << " leg2 out: " << format_amount (leg2_out_funds);
        journal_.debug << "      xrp: " << format_amount (xrp_funds);
    }

    auto const leg1_rate = in_rate (owner1, account ());
    auto const leg2_rate = out_rate (owner2, account ());

    // Attempt to determine the maximal flow that can be achieved across each
    // leg independent of the other.
    auto flow1 = flow_iou_to_xrp (offer1, quality1, xrp_funds, leg1_in_funds, leg1_rate);

    if (!flow1.sanity_check ())
        Throw<std::logic_error> ("Computed flow1 fails sanity check.");

    auto flow2 = flow_xrp_to_iou (offer2, quality2, leg2_out_funds, xrp_funds, leg2_rate);

    if (!flow2.sanity_check ())
        Throw<std::logic_error> ("Computed flow2 fails sanity check.");

    // We now have the maximal flows across each leg individually. We need to
    // equalize them, so that the amount of XRP that flows out of the first leg
    // is the same as the amount of XRP that flows into the second leg. We take
    // the side which is the limiting factor (if any) and adjust the other.
    if (flow1.order.out < flow2.order.in)
    {
        // Adjust the second leg of the offer down:
        flow2.order.in = flow1.order.out;
        flow2.order.out = qual_div (flow2.order.in, quality2, flow2.order.out);
        flow2.issuers.out = leg2_rate.multiply (flow2.order.out);
        log_flow ("Balancing: adjusted second leg down", flow2);
    }
    else if (flow1.order.out > flow2.order.in)
    {
        // Adjust the first leg of the offer down:
        flow1.order.out = flow2.order.in;
        flow1.order.in = qual_mul (flow1.order.out, quality1, flow1.order.in);
        flow1.issuers.in = leg1_rate.multiply (flow1.order.in);
        log_flow ("Balancing: adjusted first leg down", flow2);
    }

    if (flow1.order.out != flow2.order.in)
        Throw<std::logic_error> ("Bridged flow is out of balance.");

    remaining_.out -= flow2.order.out;
    remaining_.in -= flow1.order.in;

    return std::make_pair (flow1, flow2);
}