コード例 #1
0
ファイル: Taker27.cpp プロジェクト: Joke-Dk/rippled
/** 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;
}
コード例 #2
0
ファイル: Taker.cpp プロジェクト: reecer/rippled
std::uint32_t
Taker::calculateRate (
    LedgerView& view, AccountID const& issuer, AccountID const& account)
{
    return isXRP (issuer) || (account == issuer)
        ? QUALITY_ONE
        : rippleTransferRate (view, issuer);
}
コード例 #3
0
ファイル: ReverseLiquidity.cpp プロジェクト: referjs/rippled
TER PathCursor::reverseLiquidity () const
{
    // Every account has a transfer rate for its issuances.

    // TOMOVE: The account charges
    // a fee when third parties transfer that account's own issuances.

    // node.transferRate_ caches the output transfer rate for this node.
    node().transferRate_ = amountFromRate (
        rippleTransferRate (view(), node().issue_.account));

    if (node().isAccount ())
        return reverseLiquidityForAccount ();

    // Otherwise the node is an Offer.
    if (isXRP (nextNode().account_))
    {
        WriteLog (lsTRACE, RippleCalc)
            << "reverseLiquidityForOffer: "
            << "OFFER --> offer: nodeIndex_=" << nodeIndex_;
        return tesSUCCESS;

        // This control structure ensures deliverNodeReverse is only called for the
        // rightmost offer in a chain of offers - which means that
        // deliverNodeReverse has to take all of those offers into consideration.
    }

    // Next is an account node, resolve current offer node's deliver.
    STAmount saDeliverAct;

    WriteLog (lsTRACE, RippleCalc)
        << "reverseLiquidityForOffer: OFFER --> account:"
        << " nodeIndex_=" << nodeIndex_
        << " saRevDeliver=" << node().saRevDeliver;

    // The next node wants the current node to deliver this much:
    return deliverNodeReverse (
        nextNode().account_,
        node().saRevDeliver,
        saDeliverAct);
}
コード例 #4
0
// The reverse pass has been narrowing by credit available and inflating by fees
// as it worked backwards.  Now, for the current account node, take the actual
// amount from previous and adjust forward balances.
//
// Perform balance adjustments between previous and current node.
// - The previous node: specifies what to push through to current.
// - All of previous output is consumed.
//
// Then, compute current node's output for next node.
// - Current node: specify what to push through to next.
// - Output to next node is computed as input minus quality or transfer fee.
// - If next node is an offer and output is non-XRP then we are the issuer and
//   do not need to push funds.
// - If next node is an offer and output is XRP then we need to deliver funds to
//   limbo.
TER PathCursor::forwardLiquidityForAccount () const
{
    TER resultCode   = tesSUCCESS;
    auto const lastNodeIndex       = pathState_.nodes().size () - 1;
    auto viewJ = rippleCalc_.logs_.journal ("View");

    std::uint64_t uRateMax = 0;

    AccountID const& previousAccountID =
            previousNode().isAccount() ? previousNode().account_ :
            node().account_;
    // Offers are always issue.
    AccountID const& nextAccountID =
            nextNode().isAccount() ? nextNode().account_ : node().account_;

    std::uint32_t uQualityIn = nodeIndex_
        ? quality_in (view(),
            node().account_,
            previousAccountID,
            node().issue_.currency)
        : QUALITY_ONE;
    std::uint32_t  uQualityOut = (nodeIndex_ == lastNodeIndex)
        ? quality_out (view(),
            node().account_,
            nextAccountID,
            node().issue_.currency)
        : QUALITY_ONE;

    // When looking backward (prv) for req we care about what we just
    // calculated: use fwd.
    // When looking forward (cur) for req we care about what was desired: use
    // rev.

    // For nextNode().isAccount()
    auto saPrvRedeemAct = previousNode().saFwdRedeem.zeroed();
    auto saPrvIssueAct = previousNode().saFwdIssue.zeroed();

    // For !previousNode().isAccount()
    auto saPrvDeliverAct = previousNode().saFwdDeliver.zeroed ();

    JLOG (j_.trace)
        << "forwardLiquidityForAccount> "
        << "nodeIndex_=" << nodeIndex_ << "/" << lastNodeIndex
        << " previousNode.saFwdRedeem:" << previousNode().saFwdRedeem
        << " saPrvIssueReq:" << previousNode().saFwdIssue
        << " previousNode.saFwdDeliver:" << previousNode().saFwdDeliver
        << " node.saRevRedeem:" << node().saRevRedeem
        << " node.saRevIssue:" << node().saRevIssue
        << " node.saRevDeliver:" << node().saRevDeliver;

    // Ripple through account.

    if (previousNode().isAccount() && nextNode().isAccount())
    {
        // Next is an account, must be rippling.

        if (!nodeIndex_)
        {
            // ^ --> ACCOUNT --> account

            // For the first node, calculate amount to ripple based on what is
            // available.
            node().saFwdRedeem = node().saRevRedeem;

            if (pathState_.inReq() >= zero)
            {
                // Limit by send max.
                node().saFwdRedeem = std::min (
                    node().saFwdRedeem, pathState_.inReq() - pathState_.inAct());
            }

            pathState_.setInPass (node().saFwdRedeem);

            node().saFwdIssue = node().saFwdRedeem == node().saRevRedeem
                // Fully redeemed.
                ? node().saRevIssue : STAmount (node().saRevIssue);

            if (node().saFwdIssue && pathState_.inReq() >= zero)
            {
                // Limit by send max.
                node().saFwdIssue = std::min (
                    node().saFwdIssue,
                    pathState_.inReq() - pathState_.inAct() - node().saFwdRedeem);
            }

            pathState_.setInPass (pathState_.inPass() + node().saFwdIssue);

            JLOG (j_.trace)
                << "forwardLiquidityForAccount: ^ --> "
                << "ACCOUNT --> account :"
                << " saInReq=" << pathState_.inReq()
                << " saInAct=" << pathState_.inAct()
                << " node.saFwdRedeem:" << node().saFwdRedeem
                << " node.saRevIssue:" << node().saRevIssue
                << " node.saFwdIssue:" << node().saFwdIssue
                << " pathState_.saInPass:"******"forwardLiquidityForAccount: account --> "
                << "ACCOUNT --> $ :"
                << " previousAccountID="
                << to_string (previousAccountID)
                << " node.account_="
                << to_string (node().account_)
                << " previousNode.saFwdRedeem:" << previousNode().saFwdRedeem
                << " previousNode.saFwdIssue:" << previousNode().saFwdIssue;

            // Last node. Accept all funds. Calculate amount actually to credit.

            auto& saCurReceive = pathState_.outPass();
            STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
                    ? previousNode().saFwdIssue  // No fee.
                    : mulRound (
                          previousNode().saFwdIssue,
                          amountFromRate (uQualityIn),
                          previousNode().saFwdIssue.issue (),
                          true); // Amount to credit.

            // Amount to credit. Credit for less than received as a surcharge.
            pathState_.setOutPass (previousNode().saFwdRedeem + saIssueCrd);

            if (saCurReceive)
            {
                // Actually receive.
                resultCode = rippleCredit(view(),
                    previousAccountID,
                    node().account_,
                    previousNode().saFwdRedeem + previousNode().saFwdIssue,
                    false, viewJ);
            }
            else
            {
                // After applying quality, total payment was microscopic.
                resultCode   = tecPATH_DRY;
            }
        }
        else
        {
            // account --> ACCOUNT --> account
            JLOG (j_.trace)
                << "forwardLiquidityForAccount: account --> "
                << "ACCOUNT --> account";

            node().saFwdRedeem.clear (node().saRevRedeem);
            node().saFwdIssue.clear (node().saRevIssue);

            // Previous redeem part 1: redeem -> redeem
            if (previousNode().saFwdRedeem && node().saRevRedeem)
                // Previous wants to redeem.
            {
                // Rate : 1.0 : quality out
                rippleLiquidity (
                    rippleCalc_,
                    QUALITY_ONE,
                    uQualityOut,
                    previousNode().saFwdRedeem,
                    node().saRevRedeem,
                    saPrvRedeemAct,
                    node().saFwdRedeem,
                    uRateMax);
            }

            // Previous issue part 1: issue -> redeem
            if (previousNode().saFwdIssue != saPrvIssueAct
                // Previous wants to issue.
                && node().saRevRedeem != node().saFwdRedeem)
                // Current has more to redeem to next.
            {
                // Rate: quality in : quality out
                rippleLiquidity (
                    rippleCalc_,
                    uQualityIn,
                    uQualityOut,
                    previousNode().saFwdIssue,
                    node().saRevRedeem,
                    saPrvIssueAct,
                    node().saFwdRedeem,
                    uRateMax);
            }

            // Previous redeem part 2: redeem -> issue.
            if (previousNode().saFwdRedeem != saPrvRedeemAct
                // Previous still wants to redeem.
                && node().saRevRedeem == node().saFwdRedeem
                // Current redeeming is done can issue.
                && node().saRevIssue)
                // Current wants to issue.
            {
                // Rate : 1.0 : transfer_rate
                rippleLiquidity (
                    rippleCalc_,
                    QUALITY_ONE,
                    rippleTransferRate (view(), node().account_),
                    previousNode().saFwdRedeem,
                    node().saRevIssue,
                    saPrvRedeemAct,
                    node().saFwdIssue,
                    uRateMax);
            }

            // Previous issue part 2 : issue -> issue
            if (previousNode().saFwdIssue != saPrvIssueAct
                // Previous wants to issue.
                && node().saRevRedeem == node().saFwdRedeem
                // Current redeeming is done can issue.
                && node().saRevIssue)
                // Current wants to issue.
            {
                // Rate: quality in : 1.0
                rippleLiquidity (
                    rippleCalc_,
                    uQualityIn,
                    QUALITY_ONE,
                    previousNode().saFwdIssue,
                    node().saRevIssue,
                    saPrvIssueAct,
                    node().saFwdIssue,
                    uRateMax);
            }

            STAmount saProvide = node().saFwdRedeem + node().saFwdIssue;

            // Adjust prv --> cur balance : take all inbound
            resultCode = saProvide
                ? rippleCredit(view(),
                    previousAccountID,
                    node().account_,
                    previousNode().saFwdRedeem + previousNode().saFwdIssue,
                    false, viewJ)
                : tecPATH_DRY;
        }
    }
    else if (previousNode().isAccount() && !nextNode().isAccount())
    {
        // Current account is issuer to next offer.
        // Determine deliver to offer amount.
        // Don't adjust outbound balances- keep funds with issuer as limbo.
        // If issuer hold's an offer owners inbound IOUs, there is no fee and
        // redeem/issue will transparently happen.

        if (nodeIndex_)
        {
            // Non-XRP, current node is the issuer.
            JLOG (j_.trace)
                << "forwardLiquidityForAccount: account --> "
                << "ACCOUNT --> offer";

            node().saFwdDeliver.clear (node().saRevDeliver);

            // redeem -> issue/deliver.
            // Previous wants to redeem.
            // Current is issuing to an offer so leave funds in account as
            // "limbo".
            if (previousNode().saFwdRedeem)
                // Previous wants to redeem.
            {
                // Rate : 1.0 : transfer_rate
                // XXX Is having the transfer rate here correct?
                rippleLiquidity (
                    rippleCalc_,
                    QUALITY_ONE,
                    rippleTransferRate (view(), node().account_),
                    previousNode().saFwdRedeem,
                    node().saRevDeliver,
                    saPrvRedeemAct,
                    node().saFwdDeliver,
                    uRateMax);
            }

            // issue -> issue/deliver
            if (previousNode().saFwdRedeem == saPrvRedeemAct
                // Previous done redeeming: Previous has no IOUs.
                && previousNode().saFwdIssue)
                // Previous wants to issue. To next must be ok.
            {
                // Rate: quality in : 1.0
                rippleLiquidity (
                    rippleCalc_,
                    uQualityIn,
                    QUALITY_ONE,
                    previousNode().saFwdIssue,
                    node().saRevDeliver,
                    saPrvIssueAct,
                    node().saFwdDeliver,
                    uRateMax);
            }

            // Adjust prv --> cur balance : take all inbound
            resultCode   = node().saFwdDeliver
                ? rippleCredit(view(),
                    previousAccountID, node().account_,
                    previousNode().saFwdRedeem + previousNode().saFwdIssue,
                    false, viewJ)
                : tecPATH_DRY;  // Didn't actually deliver anything.
        }
        else
        {
            // Delivering amount requested from downstream.
            node().saFwdDeliver = node().saRevDeliver;

            // If limited, then limit by send max and available.
            if (pathState_.inReq() >= zero)
            {
                // Limit by send max.
                node().saFwdDeliver = std::min (
                    node().saFwdDeliver, pathState_.inReq() - pathState_.inAct());

                // Limit XRP by available. No limit for non-XRP as issuer.
                if (isXRP (node().issue_))
                    node().saFwdDeliver = std::min (
                        node().saFwdDeliver,
                        accountHolds(view(),
                            node().account_,
                            xrpCurrency(),
                            xrpAccount(),
                            fhIGNORE_FREEZE, viewJ)); // XRP can't be frozen

            }

            // Record amount sent for pass.
            pathState_.setInPass (node().saFwdDeliver);

            if (!node().saFwdDeliver)
            {
                resultCode   = tecPATH_DRY;
            }
            else if (!isXRP (node().issue_))
            {
                // Non-XRP, current node is the issuer.
                // We could be delivering to multiple accounts, so we don't know
                // which ripple balance will be adjusted.  Assume just issuing.

                JLOG (j_.trace)
                    << "forwardLiquidityForAccount: ^ --> "
                    << "ACCOUNT -- !XRP --> offer";

                // As the issuer, would only issue.
                // Don't need to actually deliver. As from delivering leave in
                // the issuer as limbo.
            }
            else
            {
                JLOG (j_.trace)
                    << "forwardLiquidityForAccount: ^ --> "
                    << "ACCOUNT -- XRP --> offer";

                // Deliver XRP to limbo.
                resultCode = accountSend(view(),
                    node().account_, xrpAccount(), node().saFwdDeliver, viewJ);
            }
        }
    }
    else if (!previousNode().isAccount() && nextNode().isAccount())
    {
        if (nodeIndex_ == lastNodeIndex)
        {
            // offer --> ACCOUNT --> $
            JLOG (j_.trace)
                << "forwardLiquidityForAccount: offer --> "
                << "ACCOUNT --> $ : "
                << previousNode().saFwdDeliver;

            // Amount to credit.
            pathState_.setOutPass (previousNode().saFwdDeliver);

            // No income balance adjustments necessary.  The paying side inside
            // the offer paid to this account.
        }
        else
        {
            // offer --> ACCOUNT --> account
            JLOG (j_.trace)
                << "forwardLiquidityForAccount: offer --> "
                << "ACCOUNT --> account";

            node().saFwdRedeem.clear (node().saRevRedeem);
            node().saFwdIssue.clear (node().saRevIssue);

            // deliver -> redeem
            if (previousNode().saFwdDeliver && node().saRevRedeem)
                // Previous wants to deliver and can current redeem.
            {
                // Rate : 1.0 : quality out
                rippleLiquidity (
                    rippleCalc_,
                    QUALITY_ONE,
                    uQualityOut,
                    previousNode().saFwdDeliver,
                    node().saRevRedeem,
                    saPrvDeliverAct,
                    node().saFwdRedeem,
                    uRateMax);
            }

            // deliver -> issue
            // Wants to redeem and current would and can issue.
            if (previousNode().saFwdDeliver != saPrvDeliverAct
                // Previous still wants to deliver.
                && node().saRevRedeem == node().saFwdRedeem
                // Current has more to redeem to next.
                && node().saRevIssue)
                // Current wants issue.
            {
                // Rate : 1.0 : transfer_rate
                rippleLiquidity (
                    rippleCalc_,
                    QUALITY_ONE,
                    rippleTransferRate (view(), node().account_),
                    previousNode().saFwdDeliver,
                    node().saRevIssue,
                    saPrvDeliverAct,
                    node().saFwdIssue,
                    uRateMax);
            }

            // No income balance adjustments necessary.  The paying side inside
            // the offer paid and the next link will receive.
            STAmount saProvide = node().saFwdRedeem + node().saFwdIssue;

            if (!saProvide)
                resultCode = tecPATH_DRY;
        }
    }
    else
    {
        // offer --> ACCOUNT --> offer
        // deliver/redeem -> deliver/issue.
        JLOG (j_.trace)
            << "forwardLiquidityForAccount: offer --> ACCOUNT --> offer";

        node().saFwdDeliver.clear (node().saRevDeliver);

        if (previousNode().saFwdDeliver && node().saRevDeliver)
        {
            // Rate : 1.0 : transfer_rate
            rippleLiquidity (
                rippleCalc_,
                QUALITY_ONE,
                rippleTransferRate (view(), node().account_),
                previousNode().saFwdDeliver,
                node().saRevDeliver,
                saPrvDeliverAct,
                node().saFwdDeliver,
                uRateMax);
        }

        // No income balance adjustments necessary.  The paying side inside the
        // offer paid and the next link will receive.
        if (!node().saFwdDeliver)
            resultCode   = tecPATH_DRY;
    }

    return resultCode;
}