mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-01 16:05:52 +00:00
Use Rate to represent transfer rates (RIPD-201, RIPD-983):
The Ripple protocol represent transfer rates and trust line qualities as fractions of one billion. For example, a transfer rate of 1% is represented as 1010000000. Previously, such rates where represented either as std::uint32_t or std::uint64_t. Other, nominally related types, also used an integral representation and could be unintentionally substituted. The new Rate class addresses this by providing a simple, type safe alternative which also helps make the code self-documenting since arithmetic operations now can be clearly understood to involve the scaling of an amount by a rate.
This commit is contained in:
committed by
Miguel Portilla
parent
f060820f3b
commit
a698104c55
@@ -1001,6 +1001,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\paths\cursor\EffectiveRate.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\app\paths\cursor\EffectiveRate.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\app\paths\cursor\ForwardLiquidity.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
|
||||
@@ -1482,6 +1482,12 @@
|
||||
<ClCompile Include="..\..\src\ripple\app\paths\cursor\DeliverNodeReverse.cpp">
|
||||
<Filter>ripple\app\paths\cursor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\app\paths\cursor\EffectiveRate.cpp">
|
||||
<Filter>ripple\app\paths\cursor</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\app\paths\cursor\EffectiveRate.h">
|
||||
<Filter>ripple\app\paths\cursor</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\app\paths\cursor\ForwardLiquidity.cpp">
|
||||
<Filter>ripple\app\paths\cursor</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/HashPrefix.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/resource/Gossip.h>
|
||||
#include <ripple/resource/ResourceManager.h>
|
||||
@@ -2851,7 +2852,7 @@ void NetworkOPsImp::getBookPage (
|
||||
unsigned int uBookEntry;
|
||||
STAmount saDirRate;
|
||||
|
||||
auto uTransferRate = rippleTransferRate(view, book.out.account);
|
||||
auto const rate = transferRate(view, book.out.account);
|
||||
auto viewJ = app_.journal ("View");
|
||||
|
||||
unsigned int left (iLimit == 0 ? 300 : iLimit);
|
||||
@@ -2948,12 +2949,11 @@ void NetworkOPsImp::getBookPage (
|
||||
|
||||
Json::Value jvOffer = sleOffer->getJson (0);
|
||||
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit;
|
||||
std::uint32_t uOfferRate;
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit = saOwnerFunds;
|
||||
Rate offerRate = parityRate;
|
||||
|
||||
|
||||
if (uTransferRate != QUALITY_ONE
|
||||
if (rate != parityRate
|
||||
// Have a tranfer fee.
|
||||
&& uTakerID != book.out.account
|
||||
// Not taking offers of own IOUs.
|
||||
@@ -2961,16 +2961,9 @@ void NetworkOPsImp::getBookPage (
|
||||
// Offer owner not issuing ownfunds
|
||||
{
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = divide (
|
||||
saOwnerFunds,
|
||||
amountFromRate (uOfferRate),
|
||||
saOwnerFunds.issue ());
|
||||
}
|
||||
else
|
||||
{
|
||||
uOfferRate = QUALITY_ONE;
|
||||
saOwnerFundsLimit = saOwnerFunds;
|
||||
offerRate = rate;
|
||||
saOwnerFundsLimit = divide (
|
||||
saOwnerFunds, offerRate);
|
||||
}
|
||||
|
||||
if (saOwnerFundsLimit >= saTakerGets)
|
||||
@@ -2982,7 +2975,7 @@ void NetworkOPsImp::getBookPage (
|
||||
{
|
||||
// Only provide, if not fully funded.
|
||||
|
||||
saTakerGetsFunded = saOwnerFundsLimit;
|
||||
saTakerGetsFunded = saOwnerFundsLimit;
|
||||
|
||||
saTakerGetsFunded.setJson (jvOffer[jss::taker_gets_funded]);
|
||||
std::min (
|
||||
@@ -2991,14 +2984,11 @@ void NetworkOPsImp::getBookPage (
|
||||
(jvOffer[jss::taker_pays_funded]);
|
||||
}
|
||||
|
||||
STAmount saOwnerPays = (QUALITY_ONE == uOfferRate)
|
||||
STAmount saOwnerPays = (parityRate == offerRate)
|
||||
? saTakerGetsFunded
|
||||
: std::min (
|
||||
saOwnerFunds,
|
||||
multiply (
|
||||
saTakerGetsFunded,
|
||||
amountFromRate (uOfferRate),
|
||||
saTakerGetsFunded.issue ()));
|
||||
multiply (saTakerGetsFunded, offerRate));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
|
||||
@@ -3055,7 +3045,7 @@ void NetworkOPsImp::getBookPage (
|
||||
MetaView lesActive (lpLedger, tapNONE, true);
|
||||
OrderBookIterator obIterator (lesActive, book);
|
||||
|
||||
auto uTransferRate = rippleTransferRate (lesActive, book.out.account);
|
||||
auto const rate = transferRate(lesActive, book.out.account);
|
||||
|
||||
const bool bGlobalFreeze = lesActive.isGlobalFrozen (book.out.account) ||
|
||||
lesActive.isGlobalFrozen (book.in.account);
|
||||
@@ -3115,12 +3105,11 @@ void NetworkOPsImp::getBookPage (
|
||||
|
||||
Json::Value jvOffer = sleOffer->getJson (0);
|
||||
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit;
|
||||
std::uint32_t uOfferRate;
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit = saOwnerFunds;
|
||||
Rate offerRate = parityRate;
|
||||
|
||||
|
||||
if (uTransferRate != QUALITY_ONE
|
||||
if (rate != parityRate
|
||||
// Have a tranfer fee.
|
||||
&& uTakerID != book.out.account
|
||||
// Not taking offers of own IOUs.
|
||||
@@ -3128,14 +3117,8 @@ void NetworkOPsImp::getBookPage (
|
||||
// Offer owner not issuing ownfunds
|
||||
{
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = divide (saOwnerFunds,
|
||||
amountFromRate (uOfferRate));
|
||||
}
|
||||
else
|
||||
{
|
||||
uOfferRate = QUALITY_ONE;
|
||||
saOwnerFundsLimit = saOwnerFunds;
|
||||
offerRate = rate;
|
||||
saOwnerFundsLimit = divide (saOwnerFunds, offerRate);
|
||||
}
|
||||
|
||||
if (saOwnerFundsLimit >= saTakerGets)
|
||||
@@ -3157,11 +3140,11 @@ void NetworkOPsImp::getBookPage (
|
||||
jvOffer[jss::taker_pays_funded]);
|
||||
}
|
||||
|
||||
STAmount saOwnerPays = (uOfferRate == QUALITY_ONE)
|
||||
STAmount saOwnerPays = (parityRate == offerRate)
|
||||
? saTakerGetsFunded
|
||||
: std::min (
|
||||
saOwnerFunds,
|
||||
multiply (saTakerGetsFunded, amountFromRate (uOfferRate)));
|
||||
multiply (saTakerGetsFunded, offerRate));
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
#include <ripple/app/paths/NodeDirectory.h>
|
||||
#include <ripple/app/paths/Types.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace path {
|
||||
@@ -42,12 +44,12 @@ struct Node
|
||||
|
||||
std::uint16_t uFlags; // --> From path.
|
||||
|
||||
AccountID account_; // --> Accounts: Receiving/sending account.
|
||||
AccountID account_; // --> Accounts: Receiving/sending account.
|
||||
|
||||
Issue issue_; // --> Accounts: Receive and send, Offers: send.
|
||||
// --- For offer's next has currency out.
|
||||
|
||||
STAmount transferRate_; // Transfer rate for issuer.
|
||||
boost::optional<Rate> transferRate_; // Transfer rate for issuer.
|
||||
|
||||
// Computed by Reverse.
|
||||
STAmount saRevRedeem; // <-- Amount to redeem to next.
|
||||
@@ -65,8 +67,7 @@ struct Node
|
||||
// fee.
|
||||
|
||||
// For offers:
|
||||
|
||||
STAmount saRateMax;
|
||||
boost::optional<Rate> rateMax;
|
||||
|
||||
// The nodes are partitioned into a buckets called "directories".
|
||||
//
|
||||
|
||||
@@ -366,7 +366,6 @@ TER PathState::pushNode (
|
||||
else
|
||||
node.issue_.account = backNode.issue_.account;
|
||||
|
||||
node.saRateMax = STAmount::saZero;
|
||||
node.saRevDeliver = STAmount (node.issue_);
|
||||
node.saFwdDeliver = node.saRevDeliver;
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
<< "rippleCalc: AFTER:"
|
||||
<< " mIndex=" << pathState->index()
|
||||
<< " uQuality=" << pathState->quality()
|
||||
<< " rate=" << amountFromRate (pathState->quality());
|
||||
<< " rate=" << amountFromQuality (pathState->quality());
|
||||
|
||||
if (flowDebugInfo)
|
||||
flowDebugInfo->pushLiquiditySrc (
|
||||
@@ -399,7 +399,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
JLOG (j_.debug())
|
||||
<< "rippleCalc: better:"
|
||||
<< " uQuality="
|
||||
<< amountFromRate (pathState->quality())
|
||||
<< amountFromQuality (pathState->quality())
|
||||
<< " inPass()=" << pathState->inPass()
|
||||
<< " saOutPass=" << pathState->outPass();
|
||||
}
|
||||
@@ -427,7 +427,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
<< " mIndex=" << pathState->index()
|
||||
<< " uQuality=" << pathState->quality()
|
||||
<< " rate="
|
||||
<< amountFromRate (pathState->quality())
|
||||
<< amountFromQuality (pathState->quality())
|
||||
<< " inPass()=" << pathState->inPass()
|
||||
<< " saOutPass=" << pathState->outPass();
|
||||
|
||||
@@ -452,7 +452,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
<< "rippleCalc: "
|
||||
<< "Summary: " << pathState->index()
|
||||
<< " rate: "
|
||||
<< amountFromRate (pathState->quality())
|
||||
<< amountFromQuality (pathState->quality())
|
||||
<< " quality:" << pathState->quality()
|
||||
<< " best: " << (iBest == pathState->index ());
|
||||
}
|
||||
@@ -470,7 +470,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
|
||||
JLOG (j_.debug ())
|
||||
<< "rippleCalc: best:"
|
||||
<< " uQuality=" << amountFromRate (pathState->quality ())
|
||||
<< " uQuality=" << amountFromQuality (pathState->quality ())
|
||||
<< " inPass()=" << pathState->inPass ()
|
||||
<< " saOutPass=" << pathState->outPass () << " iBest=" << iBest;
|
||||
|
||||
@@ -490,7 +490,7 @@ TER RippleCalc::rippleCalculate (detail::FlowDebugInfo* flowDebugInfo)
|
||||
JLOG (j_.trace())
|
||||
<< "rippleCalc: best:"
|
||||
<< " uQuality="
|
||||
<< amountFromRate (pathState->quality())
|
||||
<< amountFromQuality (pathState->quality())
|
||||
<< " inPass()=" << pathState->inPass()
|
||||
<< " saOutPass=" << pathState->outPass()
|
||||
<< " actualIn=" << actualAmountIn_
|
||||
|
||||
@@ -41,21 +41,18 @@ RippleState::makeItem (
|
||||
RippleState::RippleState (
|
||||
std::shared_ptr<SLE const>&& sle,
|
||||
AccountID const& viewAccount)
|
||||
: mLedgerEntry (std::move(sle))
|
||||
, mLowLimit (mLedgerEntry->getFieldAmount (sfLowLimit))
|
||||
, mHighLimit (mLedgerEntry->getFieldAmount (sfHighLimit))
|
||||
: sle_ (std::move(sle))
|
||||
, mFlags (sle_->getFieldU32 (sfFlags))
|
||||
, mLowLimit (sle_->getFieldAmount (sfLowLimit))
|
||||
, mHighLimit (sle_->getFieldAmount (sfHighLimit))
|
||||
, mLowID (mLowLimit.getIssuer ())
|
||||
, mHighID (mHighLimit.getIssuer ())
|
||||
, mBalance (mLedgerEntry->getFieldAmount (sfBalance))
|
||||
, lowQualityIn_ (sle_->getFieldU32 (sfLowQualityIn))
|
||||
, lowQualityOut_ (sle_->getFieldU32 (sfLowQualityOut))
|
||||
, highQualityIn_ (sle_->getFieldU32 (sfHighQualityIn))
|
||||
, highQualityOut_ (sle_->getFieldU32 (sfHighQualityOut))
|
||||
, mBalance (sle_->getFieldAmount (sfBalance))
|
||||
{
|
||||
mFlags = mLedgerEntry->getFieldU32 (sfFlags);
|
||||
|
||||
mLowQualityIn = mLedgerEntry->getFieldU32 (sfLowQualityIn);
|
||||
mLowQualityOut = mLedgerEntry->getFieldU32 (sfLowQualityOut);
|
||||
|
||||
mHighQualityIn = mLedgerEntry->getFieldU32 (sfHighQualityIn);
|
||||
mHighQualityOut = mLedgerEntry->getFieldU32 (sfHighQualityOut);
|
||||
|
||||
mViewLowest = (mLowID == viewAccount);
|
||||
|
||||
if (!mViewLowest)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED
|
||||
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/STLedgerEntry.h>
|
||||
#include <cstdint>
|
||||
@@ -58,7 +59,7 @@ public:
|
||||
uint256
|
||||
key() const
|
||||
{
|
||||
return mLedgerEntry->getIndex();
|
||||
return sle_->getIndex();
|
||||
}
|
||||
|
||||
// VFALCO Take off the "get" from each function name
|
||||
@@ -121,20 +122,22 @@ public:
|
||||
return !mViewLowest ? mLowLimit : mHighLimit;
|
||||
}
|
||||
|
||||
std::uint32_t getQualityIn () const
|
||||
Rate const&
|
||||
getQualityIn () const
|
||||
{
|
||||
return ((std::uint32_t) (mViewLowest ? mLowQualityIn : mHighQualityIn));
|
||||
return mViewLowest ? lowQualityIn_ : highQualityIn_;
|
||||
}
|
||||
|
||||
std::uint32_t getQualityOut () const
|
||||
Rate const&
|
||||
getQualityOut () const
|
||||
{
|
||||
return ((std::uint32_t) (mViewLowest ? mLowQualityOut : mHighQualityOut));
|
||||
return mViewLowest ? lowQualityOut_ : highQualityOut_;
|
||||
}
|
||||
|
||||
Json::Value getJson (int);
|
||||
|
||||
private:
|
||||
std::shared_ptr<SLE const> mLedgerEntry;
|
||||
std::shared_ptr<SLE const> sle_;
|
||||
|
||||
bool mViewLowest;
|
||||
|
||||
@@ -146,10 +149,10 @@ private:
|
||||
AccountID const& mLowID;
|
||||
AccountID const& mHighID;
|
||||
|
||||
std::uint64_t mLowQualityIn;
|
||||
std::uint64_t mLowQualityOut;
|
||||
std::uint64_t mHighQualityIn;
|
||||
std::uint64_t mHighQualityOut;
|
||||
Rate lowQualityIn_;
|
||||
Rate lowQualityOut_;
|
||||
Rate highQualityIn_;
|
||||
Rate highQualityOut_;
|
||||
|
||||
STAmount mBalance;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/paths/cursor/EffectiveRate.h>
|
||||
#include <ripple/app/paths/cursor/RippleLiquidity.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
|
||||
@@ -82,14 +83,11 @@ TER PathCursor::deliverNodeForward (
|
||||
}
|
||||
else if (resultCode == tesSUCCESS)
|
||||
{
|
||||
// Doesn't charge input. Input funds are in limbo.
|
||||
// There's no fee if we're transferring XRP, if the sender is the
|
||||
// issuer, or if the receiver is the issuer.
|
||||
bool noFee = isXRP (previousNode().issue_)
|
||||
|| uInAccountID == previousNode().issue_.account
|
||||
|| node().offerOwnerAccount_ == previousNode().issue_.account;
|
||||
const STAmount saInFeeRate = noFee ? STAmount::saOne
|
||||
: previousNode().transferRate_; // Transfer rate of issuer.
|
||||
auto const xferRate = effectiveRate (
|
||||
previousNode().issue_,
|
||||
uInAccountID,
|
||||
node().offerOwnerAccount_,
|
||||
previousNode().transferRate_);
|
||||
|
||||
// First calculate assuming no output fees: saInPassAct,
|
||||
// saInPassFees, saOutPassAct.
|
||||
@@ -111,8 +109,8 @@ TER PathCursor::deliverNodeForward (
|
||||
true);
|
||||
|
||||
// Offer maximum in with fees.
|
||||
auto saInTotal = mulRound (saInFunded, saInFeeRate,
|
||||
saInFunded.issue (), true);
|
||||
auto saInTotal = multiplyRound (
|
||||
saInFunded, xferRate, true);
|
||||
auto saInRemaining = saInReq - saInAct - saInFees;
|
||||
|
||||
if (saInRemaining < zero)
|
||||
@@ -123,8 +121,8 @@ TER PathCursor::deliverNodeForward (
|
||||
|
||||
// In without fees.
|
||||
auto saInPassAct = std::min (
|
||||
node().saTakerPays, divRound (
|
||||
saInSum, saInFeeRate, saInSum.issue (), true));
|
||||
node().saTakerPays,
|
||||
divideRound (saInSum, xferRate, true));
|
||||
|
||||
// Out limited by in remaining.
|
||||
auto outPass = divRound (
|
||||
@@ -247,8 +245,8 @@ TER PathCursor::deliverNodeForward (
|
||||
auto inPassAct = mulRound (
|
||||
saOutPassAct, node().saOfrRate, saInReq.issue (), true);
|
||||
saInPassAct = std::min (node().saTakerPays, inPassAct);
|
||||
auto inPassFees = mulRound (
|
||||
saInPassAct, saInFeeRate, saInPassAct.issue (), true);
|
||||
auto inPassFees = multiplyRound (
|
||||
saInPassAct, xferRate, true);
|
||||
saInPassFees = std::min (saInPassFeesMax, inPassFees);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/paths/cursor/EffectiveRate.h>
|
||||
#include <ripple/app/paths/cursor/RippleLiquidity.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
|
||||
@@ -81,66 +82,58 @@ TER PathCursor::deliverNodeReverseImpl (
|
||||
// Error or out of offers.
|
||||
break;
|
||||
|
||||
auto const hasFee = node().offerOwnerAccount_ == node().issue_.account
|
||||
|| uOutAccountID == node().issue_.account;
|
||||
// Issuer sending or receiving.
|
||||
|
||||
const STAmount saOutFeeRate = hasFee
|
||||
? STAmount::saOne // No fee.
|
||||
: node().transferRate_; // Transfer rate of issuer.
|
||||
auto const xferRate = effectiveRate (
|
||||
node().issue_,
|
||||
uOutAccountID,
|
||||
node().offerOwnerAccount_,
|
||||
node().transferRate_);
|
||||
|
||||
JLOG (j_.trace())
|
||||
<< "deliverNodeReverse:"
|
||||
<< " offerOwnerAccount_="
|
||||
<< node().offerOwnerAccount_
|
||||
<< " uOutAccountID="
|
||||
<< uOutAccountID
|
||||
<< " node().issue_.account="
|
||||
<< node().issue_.account
|
||||
<< " node().transferRate_=" << node().transferRate_
|
||||
<< " saOutFeeRate=" << saOutFeeRate;
|
||||
<< " offerOwnerAccount_=" << node().offerOwnerAccount_
|
||||
<< " uOutAccountID=" << uOutAccountID
|
||||
<< " node().issue_.account=" << node().issue_.account
|
||||
<< " xferRate=" << xferRate;
|
||||
|
||||
if (multiQuality_)
|
||||
// Only use rate when not in multi-quality mode
|
||||
if (!multiQuality_)
|
||||
{
|
||||
// In multi-quality mode, ignore rate.
|
||||
}
|
||||
else if (!node().saRateMax)
|
||||
{
|
||||
// Set initial rate.
|
||||
node().saRateMax = saOutFeeRate;
|
||||
if (!node().rateMax)
|
||||
{
|
||||
// Set initial rate.
|
||||
JLOG (j_.trace())
|
||||
<< "Set initial rate";
|
||||
|
||||
JLOG (j_.trace())
|
||||
<< "deliverNodeReverse: Set initial rate:"
|
||||
<< " node().saRateMax=" << node().saRateMax
|
||||
<< " saOutFeeRate=" << saOutFeeRate;
|
||||
}
|
||||
else if (saOutFeeRate > node().saRateMax)
|
||||
{
|
||||
// Offer exceeds initial rate.
|
||||
JLOG (j_.trace())
|
||||
<< "deliverNodeReverse: Offer exceeds initial rate:"
|
||||
<< " node().saRateMax=" << node().saRateMax
|
||||
<< " saOutFeeRate=" << saOutFeeRate;
|
||||
node().rateMax = xferRate;
|
||||
}
|
||||
else if (xferRate > node().rateMax)
|
||||
{
|
||||
// Offer exceeds initial rate.
|
||||
JLOG (j_.trace())
|
||||
<< "Offer exceeds initial rate: " << *node().rateMax;
|
||||
|
||||
break; // Done. Don't bother looking for smaller transferRates.
|
||||
}
|
||||
else if (saOutFeeRate < node().saRateMax)
|
||||
{
|
||||
// Reducing rate. Additional offers will only considered for this
|
||||
// increment if they are at least this good.
|
||||
//
|
||||
// At this point, the overall rate is reducing, while the overall
|
||||
// rate is not saOutFeeRate, it would be wrong to add anything with
|
||||
// a rate above saOutFeeRate.
|
||||
//
|
||||
// The rate would be reduced if the current offer was from the
|
||||
// issuer and the previous offer wasn't.
|
||||
break; // Done. Don't bother looking for smaller transferRates.
|
||||
}
|
||||
else if (xferRate < node().rateMax)
|
||||
{
|
||||
// Reducing rate. Additional offers will only
|
||||
// be considered for this increment if they
|
||||
// are at least this good.
|
||||
//
|
||||
// At this point, the overall rate is reducing,
|
||||
// while the overall rate is not xferRate, it
|
||||
// would be wrong to add anything with a rate
|
||||
// above xferRate.
|
||||
//
|
||||
// The rate would be reduced if the current
|
||||
// offer was from the issuer and the previous
|
||||
// offer wasn't.
|
||||
|
||||
node().saRateMax = saOutFeeRate;
|
||||
JLOG (j_.trace())
|
||||
<< "Reducing rate: " << *node().rateMax;
|
||||
|
||||
JLOG (j_.trace())
|
||||
<< "deliverNodeReverse: Reducing rate:"
|
||||
<< " node().saRateMax=" << node().saRateMax;
|
||||
node().rateMax = xferRate;
|
||||
}
|
||||
}
|
||||
|
||||
// Amount that goes to the taker.
|
||||
@@ -157,8 +150,8 @@ TER PathCursor::deliverNodeReverseImpl (
|
||||
// as a cost to taker.
|
||||
//
|
||||
// Round down: prefer liquidity rather than microscopic fees.
|
||||
STAmount saOutPlusFees = mulRound (
|
||||
saOutPassAct, saOutFeeRate, saOutPassAct.issue (), false);
|
||||
STAmount saOutPlusFees = multiplyRound (
|
||||
saOutPassAct, xferRate, false);
|
||||
|
||||
|
||||
// Offer out with fees.
|
||||
@@ -180,8 +173,7 @@ TER PathCursor::deliverNodeReverseImpl (
|
||||
|
||||
// Round up: prefer liquidity rather than microscopic fees. But,
|
||||
// limit by requested.
|
||||
auto fee = divRound (saOutPlusFees, saOutFeeRate,
|
||||
saOutPlusFees.issue (), true);
|
||||
auto fee = divideRound (saOutPlusFees, xferRate, true);
|
||||
saOutPassAct = std::min (saOutPassReq, fee);
|
||||
|
||||
JLOG (j_.trace())
|
||||
@@ -280,8 +272,7 @@ TER PathCursor::deliverNodeReverseImpl (
|
||||
auto outputRequirements = divRound (saInPassAct, node ().saOfrRate,
|
||||
node ().saTakerGets.issue (), true);
|
||||
saOutPassAct = std::min (saOutPassReq, outputRequirements);
|
||||
auto outputFees = mulRound (saOutPassAct, saOutFeeRate,
|
||||
saOutPassAct.issue (), true);
|
||||
auto outputFees = multiplyRound (saOutPassAct, xferRate, true);
|
||||
saOutPlusFees = std::min (node().saOfferFunds, outputFees);
|
||||
|
||||
JLOG (j_.trace())
|
||||
|
||||
49
src/ripple/app/paths/cursor/EffectiveRate.cpp
Normal file
49
src/ripple/app/paths/cursor/EffectiveRate.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/paths/cursor/EffectiveRate.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace path {
|
||||
|
||||
Rate
|
||||
effectiveRate(
|
||||
Issue const& issue,
|
||||
AccountID const& account1,
|
||||
AccountID const& account2,
|
||||
boost::optional<Rate> const& rate)
|
||||
{
|
||||
// 1:1 transfer rate for XRP
|
||||
if (isXRP (issue))
|
||||
return parityRate;
|
||||
|
||||
if (!rate)
|
||||
LogicError ("No transfer rate set for node.");
|
||||
|
||||
// 1:1 transfer rate if either of the accounts is the issuer
|
||||
if (issue.account == account1 || issue.account == account2)
|
||||
return parityRate;
|
||||
|
||||
return rate.get();
|
||||
}
|
||||
|
||||
} // path
|
||||
} // ripple
|
||||
41
src/ripple/app/paths/cursor/EffectiveRate.h
Normal file
41
src/ripple/app/paths/cursor/EffectiveRate.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_APP_PATHS_CURSOR_EFFECTIVERATE_H_INCLUDED
|
||||
#define RIPPLE_APP_PATHS_CURSOR_EFFECTIVERATE_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
#include <ripple/protocol/Issue.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace path {
|
||||
|
||||
Rate
|
||||
effectiveRate(
|
||||
Issue const& issue,
|
||||
AccountID const& account1,
|
||||
AccountID const& account2,
|
||||
boost::optional<Rate> const& rate);
|
||||
|
||||
} // path
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -55,18 +55,19 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
AccountID const& nextAccountID =
|
||||
nextNode().isAccount() ? nextNode().account_ : node().account_;
|
||||
|
||||
std::uint32_t uQualityIn = nodeIndex_
|
||||
auto const qualityIn = nodeIndex_
|
||||
? quality_in (view(),
|
||||
node().account_,
|
||||
previousAccountID,
|
||||
node().issue_.currency)
|
||||
: QUALITY_ONE;
|
||||
std::uint32_t uQualityOut = (nodeIndex_ == lastNodeIndex)
|
||||
: parityRate;
|
||||
|
||||
auto const qualityOut = (nodeIndex_ == lastNodeIndex)
|
||||
? quality_out (view(),
|
||||
node().account_,
|
||||
nextAccountID,
|
||||
node().issue_.currency)
|
||||
: QUALITY_ONE;
|
||||
: parityRate;
|
||||
|
||||
// When looking backward (prv) for req we care about what we just
|
||||
// calculated: use fwd.
|
||||
@@ -153,12 +154,11 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Last node. Accept all funds. Calculate amount actually to credit.
|
||||
|
||||
auto& saCurReceive = pathState_.outPass();
|
||||
STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
|
||||
STAmount saIssueCrd = qualityIn >= parityRate
|
||||
? previousNode().saFwdIssue // No fee.
|
||||
: mulRound (
|
||||
: multiplyRound (
|
||||
previousNode().saFwdIssue,
|
||||
amountFromRate (uQualityIn),
|
||||
previousNode().saFwdIssue.issue (),
|
||||
qualityIn,
|
||||
true); // Amount to credit.
|
||||
|
||||
// Amount to credit. Credit for less than received as a surcharge.
|
||||
@@ -196,8 +196,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate : 1.0 : quality out
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
uQualityOut,
|
||||
parityRate,
|
||||
qualityOut,
|
||||
previousNode().saFwdRedeem,
|
||||
node().saRevRedeem,
|
||||
saPrvRedeemAct,
|
||||
@@ -214,8 +214,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate: quality in : quality out
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
uQualityOut,
|
||||
qualityIn,
|
||||
qualityOut,
|
||||
previousNode().saFwdIssue,
|
||||
node().saRevRedeem,
|
||||
saPrvIssueAct,
|
||||
@@ -234,8 +234,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
previousNode().saFwdRedeem,
|
||||
node().saRevIssue,
|
||||
saPrvRedeemAct,
|
||||
@@ -254,8 +254,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate: quality in : 1.0
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
previousNode().saFwdIssue,
|
||||
node().saRevIssue,
|
||||
saPrvIssueAct,
|
||||
@@ -303,8 +303,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// XXX Is having the transfer rate here correct?
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
previousNode().saFwdRedeem,
|
||||
node().saRevDeliver,
|
||||
saPrvRedeemAct,
|
||||
@@ -321,8 +321,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate: quality in : 1.0
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
previousNode().saFwdIssue,
|
||||
node().saRevDeliver,
|
||||
saPrvIssueAct,
|
||||
@@ -428,8 +428,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate : 1.0 : quality out
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
uQualityOut,
|
||||
parityRate,
|
||||
qualityOut,
|
||||
previousNode().saFwdDeliver,
|
||||
node().saRevRedeem,
|
||||
saPrvDeliverAct,
|
||||
@@ -449,8 +449,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
previousNode().saFwdDeliver,
|
||||
node().saRevIssue,
|
||||
saPrvDeliverAct,
|
||||
@@ -480,8 +480,8 @@ TER PathCursor::forwardLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
previousNode().saFwdDeliver,
|
||||
node().saRevDeliver,
|
||||
saPrvDeliverAct,
|
||||
|
||||
@@ -39,14 +39,17 @@ TER PathCursor::liquidity () const
|
||||
<< " nodeIndex=" << pc.nodeIndex_
|
||||
<< ".issue_.account=" << to_string (pc.node().issue_.account);
|
||||
|
||||
resultCode = pc.reverseLiquidity();
|
||||
resultCode = pc.reverseLiquidity();
|
||||
|
||||
if (!pc.node().transferRate_)
|
||||
return tefINTERNAL;
|
||||
|
||||
JLOG (j_.trace())
|
||||
<< "reverseLiquidity< "
|
||||
<< "nodeIndex=" << pc.nodeIndex_
|
||||
<< " resultCode=" << transToken (resultCode)
|
||||
<< " transferRate_=" << pc.node().transferRate_
|
||||
<< "/" << resultCode;
|
||||
<< " transferRate_=" << *pc.node().transferRate_
|
||||
<< ": " << resultCode;
|
||||
|
||||
if (resultCode != tesSUCCESS)
|
||||
break;
|
||||
|
||||
@@ -55,9 +55,8 @@ TER PathCursor::reverseLiquidity () const
|
||||
// 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));
|
||||
// Cache the output transfer rate for this node.
|
||||
node().transferRate_ = transferRate (view(), node().issue_.account);
|
||||
|
||||
if (node().isAccount ())
|
||||
return reverseLiquidityForAccount ();
|
||||
|
||||
@@ -49,8 +49,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
auto const isFinalNode = (nodeIndex_ == lastNodeIndex);
|
||||
|
||||
// 0 quality means none has yet been determined.
|
||||
std::uint64_t uRateMax = 0
|
||||
;
|
||||
std::uint64_t uRateMax = 0;
|
||||
|
||||
// Current is allowed to redeem to next.
|
||||
const bool previousNodeIsAccount = !nodeIndex_ ||
|
||||
previousNode().isAccount();
|
||||
@@ -63,22 +63,22 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
: node().account_; // Offers are always issue.
|
||||
|
||||
// This is the quality from from the previous node to this one.
|
||||
const std::uint32_t uQualityIn
|
||||
auto const qualityIn
|
||||
= (nodeIndex_ != 0)
|
||||
? quality_in (view(),
|
||||
node().account_,
|
||||
previousAccountID,
|
||||
node().issue_.currency)
|
||||
: QUALITY_ONE;
|
||||
: parityRate;
|
||||
|
||||
// And this is the quality from the next one to this one.
|
||||
const std::uint32_t uQualityOut
|
||||
auto const qualityOut
|
||||
= (nodeIndex_ != lastNodeIndex)
|
||||
? quality_out (view(),
|
||||
node().account_,
|
||||
nextAccountID,
|
||||
node().issue_.currency)
|
||||
: QUALITY_ONE;
|
||||
: parityRate;
|
||||
|
||||
// For previousNodeIsAccount:
|
||||
// Previous account is already owed.
|
||||
@@ -112,8 +112,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
<< " node.account_=" << node().account_
|
||||
<< " nextAccountID=" << nextAccountID
|
||||
<< " currency=" << node().issue_.currency
|
||||
<< " uQualityIn=" << uQualityIn
|
||||
<< " uQualityOut=" << uQualityOut
|
||||
<< " qualityIn=" << qualityIn
|
||||
<< " qualityOut=" << qualityOut
|
||||
<< " saPrvOwed=" << saPrvOwed
|
||||
<< " saPrvLimit=" << saPrvLimit;
|
||||
|
||||
@@ -208,7 +208,7 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
<< " (available) previousNode.saRevRedeem="
|
||||
<< previousNode().saRevRedeem
|
||||
<< " uRateMax="
|
||||
<< amountFromRate (uRateMax).getText ();
|
||||
<< amountFromQuality (uRateMax).getText ();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,8 +227,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// won't be included the current increment.
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
saPrvIssueReq,
|
||||
saCurWantedReq,
|
||||
previousNode().saRevIssue,
|
||||
@@ -266,8 +266,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// as 1:1.
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
uQualityOut,
|
||||
parityRate,
|
||||
qualityOut,
|
||||
saPrvRedeemReq,
|
||||
node().saRevRedeem,
|
||||
previousNode().saRevRedeem,
|
||||
@@ -290,8 +290,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate: quality in : quality out
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
uQualityOut,
|
||||
qualityIn,
|
||||
qualityOut,
|
||||
saPrvIssueReq,
|
||||
node().saRevRedeem,
|
||||
previousNode().saRevIssue,
|
||||
@@ -316,8 +316,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
saPrvRedeemReq,
|
||||
node().saRevIssue,
|
||||
previousNode().saRevRedeem,
|
||||
@@ -344,8 +344,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate: quality in : 1.0
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
saPrvIssueReq,
|
||||
node().saRevIssue,
|
||||
previousNode().saRevIssue,
|
||||
@@ -402,8 +402,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
saPrvRedeemReq,
|
||||
node().saRevDeliver,
|
||||
previousNode().saRevRedeem,
|
||||
@@ -419,8 +419,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate: quality in : 1.0
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
saPrvIssueReq,
|
||||
node().saRevDeliver,
|
||||
previousNode().saRevIssue,
|
||||
@@ -483,8 +483,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate: quality in : 1.0
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
uQualityIn,
|
||||
QUALITY_ONE,
|
||||
qualityIn,
|
||||
parityRate,
|
||||
saPrvDeliverReq,
|
||||
saCurWantedReq,
|
||||
previousNode().saRevDeliver,
|
||||
@@ -527,8 +527,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate : 1.0 : quality out
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
uQualityOut,
|
||||
parityRate,
|
||||
qualityOut,
|
||||
saPrvDeliverReq,
|
||||
node().saRevRedeem,
|
||||
previousNode().saRevDeliver,
|
||||
@@ -545,8 +545,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
saPrvDeliverReq,
|
||||
node().saRevIssue,
|
||||
previousNode().saRevDeliver,
|
||||
@@ -578,8 +578,8 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
// Rate : 1.0 : transfer_rate
|
||||
rippleLiquidity (
|
||||
rippleCalc_,
|
||||
QUALITY_ONE,
|
||||
rippleTransferRate (view(), node().account_),
|
||||
parityRate,
|
||||
transferRate (view(), node().account_),
|
||||
saPrvDeliverReq,
|
||||
node().saRevDeliver,
|
||||
previousNode().saRevDeliver,
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace path {
|
||||
|
||||
void rippleLiquidity (
|
||||
RippleCalc& rippleCalc,
|
||||
std::uint32_t const uQualityIn,
|
||||
std::uint32_t const uQualityOut,
|
||||
Rate const& qualityIn,
|
||||
Rate const& qualityOut,
|
||||
STAmount const& saPrvReq, // --> in limit including fees, <0 = unlimited
|
||||
STAmount const& saCurReq, // --> out limit
|
||||
STAmount& saPrvAct, // <-> in limit including achieved so far: <-- <= -->
|
||||
@@ -59,8 +59,8 @@ void rippleLiquidity (
|
||||
{
|
||||
JLOG (rippleCalc.j_.trace())
|
||||
<< "rippleLiquidity>"
|
||||
<< " uQualityIn=" << uQualityIn
|
||||
<< " uQualityOut=" << uQualityOut
|
||||
<< " qualityIn=" << qualityIn
|
||||
<< " qualityOut=" << qualityOut
|
||||
<< " saPrvReq=" << saPrvReq
|
||||
<< " saCurReq=" << saCurReq
|
||||
<< " saPrvAct=" << saPrvAct
|
||||
@@ -94,7 +94,7 @@ void rippleLiquidity (
|
||||
if (saPrv == zero || saCur == zero)
|
||||
return;
|
||||
|
||||
if (uQualityIn >= uQualityOut)
|
||||
if (qualityIn >= qualityOut)
|
||||
{
|
||||
// You're getting better quality than you asked for, so no fee.
|
||||
JLOG (rippleCalc.j_.trace()) << "rippleLiquidity: No fees";
|
||||
@@ -129,22 +129,18 @@ void rippleLiquidity (
|
||||
// If the quality is worse than the previous
|
||||
JLOG (rippleCalc.j_.trace()) << "rippleLiquidity: Fee";
|
||||
|
||||
std::uint64_t uRate = getRate (
|
||||
STAmount (uQualityOut), STAmount (uQualityIn));
|
||||
std::uint64_t const uRate = getRate (
|
||||
STAmount (qualityOut.value),
|
||||
STAmount (qualityIn.value));
|
||||
|
||||
// If the next rate is at least as good as the current rate, process.
|
||||
if (!uRateMax || uRate <= uRateMax)
|
||||
{
|
||||
auto currency = saCur.getCurrency ();
|
||||
auto uCurIssuerID = saCur.getIssuer ();
|
||||
|
||||
// current actual = current request * (quality out / quality in).
|
||||
auto numerator = mulRound (
|
||||
saCur, uQualityOut, {currency, uCurIssuerID}, true);
|
||||
auto numerator = multiplyRound (saCur, qualityOut, true);
|
||||
// True means "round up" to get best flow.
|
||||
|
||||
STAmount saCurIn = divRound (
|
||||
numerator, uQualityIn, {currency, uCurIssuerID}, true);
|
||||
STAmount saCurIn = divideRound (numerator, qualityIn, true);
|
||||
|
||||
JLOG (rippleCalc.j_.trace())
|
||||
<< "rippleLiquidity:"
|
||||
@@ -170,13 +166,12 @@ void rippleLiquidity (
|
||||
// * (quality in / quality out).
|
||||
// This is inverted compared to the code above because we're
|
||||
// going the other way
|
||||
|
||||
Issue issue{currency, uCurIssuerID};
|
||||
auto numerator = mulRound (saPrv, uQualityIn, issue, true);
|
||||
auto numerator = multiplyRound (saPrv,
|
||||
qualityIn, saCur.issue(), true);
|
||||
// A part of current. All of previous. (Cur is the driver
|
||||
// variable.)
|
||||
STAmount saCurOut = divRound (
|
||||
numerator, uQualityOut, issue, true);
|
||||
STAmount saCurOut = divideRound (numerator,
|
||||
qualityOut, saCur.issue(), true);
|
||||
|
||||
JLOG (rippleCalc.j_.trace())
|
||||
<< "rippleLiquidity:4: saCurReq=" << saCurReq;
|
||||
@@ -191,8 +186,8 @@ void rippleLiquidity (
|
||||
|
||||
JLOG (rippleCalc.j_.trace())
|
||||
<< "rippleLiquidity<"
|
||||
<< " uQualityIn=" << uQualityIn
|
||||
<< " uQualityOut=" << uQualityOut
|
||||
<< " qualityIn=" << qualityIn
|
||||
<< " qualityOut=" << qualityOut
|
||||
<< " saPrvReq=" << saPrvReq
|
||||
<< " saCurReq=" << saCurReq
|
||||
<< " saPrvAct=" << saPrvAct
|
||||
@@ -200,7 +195,7 @@ void rippleLiquidity (
|
||||
}
|
||||
|
||||
static
|
||||
std::uint32_t
|
||||
Rate
|
||||
rippleQuality (
|
||||
ReadView const& view,
|
||||
AccountID const& destination,
|
||||
@@ -209,32 +204,28 @@ rippleQuality (
|
||||
SField const& sfLow,
|
||||
SField const& sfHigh)
|
||||
{
|
||||
std::uint32_t uQuality (QUALITY_ONE);
|
||||
if (destination == source)
|
||||
return parityRate;
|
||||
|
||||
if (destination != source)
|
||||
{
|
||||
auto const sleRippleState = view.read(
|
||||
keylet::line(destination, source, currency));
|
||||
auto const& sfField = destination < source ? sfLow : sfHigh;
|
||||
|
||||
// we should be able to assert(sleRippleState) here
|
||||
auto const sle = view.read(
|
||||
keylet::line(destination, source, currency));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
auto const& sfField = destination < source ? sfLow : sfHigh;
|
||||
if (!sle || !sle->isFieldPresent (sfField))
|
||||
return parityRate;
|
||||
|
||||
uQuality = sleRippleState->isFieldPresent (sfField)
|
||||
? sleRippleState->getFieldU32 (sfField)
|
||||
: QUALITY_ONE;
|
||||
auto quality = sle->getFieldU32 (sfField);
|
||||
|
||||
if (!uQuality)
|
||||
uQuality = 1; // Avoid divide by zero.
|
||||
}
|
||||
}
|
||||
// Avoid divide by zero. NIKB CHECKME: if we
|
||||
// allow zero qualities now, then we shouldn't.
|
||||
if (quality == 0)
|
||||
quality = 1;
|
||||
|
||||
return uQuality;
|
||||
return Rate{ quality };
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
Rate
|
||||
quality_in (
|
||||
ReadView const& view,
|
||||
AccountID const& uToAccountID,
|
||||
@@ -245,7 +236,7 @@ quality_in (
|
||||
sfLowQualityIn, sfHighQualityIn);
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
Rate
|
||||
quality_out (
|
||||
ReadView const& view,
|
||||
AccountID const& uToAccountID,
|
||||
|
||||
@@ -24,28 +24,29 @@
|
||||
#include <ripple/app/paths/RippleCalc.h>
|
||||
#include <ripple/app/paths/Tuning.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace path {
|
||||
|
||||
void rippleLiquidity (
|
||||
RippleCalc&,
|
||||
const std::uint32_t uQualityIn,
|
||||
const std::uint32_t uQualityOut,
|
||||
Rate const& qualityIn,
|
||||
Rate const& qualityOut,
|
||||
STAmount const& saPrvReq,
|
||||
STAmount const& saCurReq,
|
||||
STAmount& saPrvAct,
|
||||
STAmount& saCurAct,
|
||||
std::uint64_t& uRateMax);
|
||||
|
||||
std::uint32_t
|
||||
Rate
|
||||
quality_in (
|
||||
ReadView const& view,
|
||||
AccountID const& uToAccountID,
|
||||
AccountID const& uFromAccountID,
|
||||
Currency const& currency);
|
||||
|
||||
std::uint32_t
|
||||
Rate
|
||||
quality_out (
|
||||
ReadView const& view,
|
||||
AccountID const& uToAccountID,
|
||||
|
||||
@@ -256,18 +256,20 @@ forEachOffer (
|
||||
// Charge a fee even if the owner is the same as the issuer
|
||||
// (the old code does not charge a fee)
|
||||
// Calculate amount that goes to the taker and the amount charged the offer owner
|
||||
auto transferRate = [&](AccountID const& id)->std::uint32_t
|
||||
auto rate = [&](AccountID const& id)->std::uint32_t
|
||||
{
|
||||
if (isXRP (id) || id == dst)
|
||||
return QUALITY_ONE;
|
||||
return rippleTransferRate (sb, id);
|
||||
return transferRate (sb, id).value;
|
||||
};
|
||||
|
||||
std::uint32_t const trIn =
|
||||
prevStepRedeems ? transferRate (book.in.account) : QUALITY_ONE;
|
||||
std::uint32_t const trIn = prevStepRedeems
|
||||
? rate (book.in.account)
|
||||
: QUALITY_ONE;
|
||||
// Always charge the transfer fee, even if the owner is the issuer
|
||||
std::uint32_t const trOut =
|
||||
ownerPaysTransferFee ? transferRate (book.out.account) : QUALITY_ONE;
|
||||
std::uint32_t const trOut = ownerPaysTransferFee
|
||||
? rate (book.out.account)
|
||||
: QUALITY_ONE;
|
||||
|
||||
typename FlowOfferStream<TAmtIn, TAmtOut>::StepCounter counter (limit, j);
|
||||
FlowOfferStream<TAmtIn, TAmtOut> offers (
|
||||
|
||||
@@ -546,8 +546,9 @@ DirectStepI::qualities (
|
||||
{
|
||||
// Charge a transfer rate when issuing and previous step redeems
|
||||
auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, fwd);
|
||||
std::uint32_t const srcQOut =
|
||||
prevStepRedeems ? rippleTransferRate (sb, src_) : QUALITY_ONE;
|
||||
std::uint32_t const srcQOut = prevStepRedeems
|
||||
? transferRate (sb, src_).value
|
||||
: QUALITY_ONE;
|
||||
return std::make_pair(
|
||||
srcQOut,
|
||||
quality ( // dst quality in
|
||||
|
||||
@@ -37,10 +37,21 @@ class Taker_test : public beast::unit_test::suite
|
||||
|
||||
public:
|
||||
TestTaker (
|
||||
CrossType cross_type, Amounts const& amount, Quality const& quality,
|
||||
STAmount const& funds, std::uint32_t flags, std::uint32_t rate_in,
|
||||
std::uint32_t rate_out)
|
||||
: BasicTaker (cross_type, AccountID(0x4701), amount, quality, flags, rate_in, rate_out)
|
||||
CrossType cross_type,
|
||||
Amounts const& amount,
|
||||
Quality const& quality,
|
||||
STAmount const& funds,
|
||||
std::uint32_t flags,
|
||||
Rate const& rate_in,
|
||||
Rate const& rate_out)
|
||||
: BasicTaker (
|
||||
cross_type,
|
||||
AccountID(0x4701),
|
||||
amount,
|
||||
quality,
|
||||
flags,
|
||||
rate_in,
|
||||
rate_out)
|
||||
, funds_ (funds)
|
||||
{
|
||||
}
|
||||
@@ -178,8 +189,8 @@ private:
|
||||
cross_attempt_offer const flow,
|
||||
Issue const& issue_in,
|
||||
Issue const& issue_out,
|
||||
std::uint32_t rate_in = QUALITY_ONE,
|
||||
std::uint32_t rate_out = QUALITY_ONE)
|
||||
Rate rate_in = parityRate,
|
||||
Rate rate_out = parityRate)
|
||||
{
|
||||
Amounts taker_offer (parse_amounts (
|
||||
offer.in, issue_in,
|
||||
@@ -333,7 +344,7 @@ public:
|
||||
Quality q1 = get_quality ("1", "1");
|
||||
|
||||
// Highly exaggerated 50% transfer rate for the input and output:
|
||||
std::uint32_t rate = QUALITY_ONE + (QUALITY_ONE / 2);
|
||||
Rate const rate { parityRate.value + (parityRate.value / 2) };
|
||||
|
||||
// TAKER OWNER
|
||||
// QUAL OFFER FUNDS QUAL OFFER FUNDS EXPECTED
|
||||
|
||||
@@ -34,28 +34,10 @@ format_amount (STAmount const& amount)
|
||||
return txt;
|
||||
}
|
||||
|
||||
STAmount
|
||||
BasicTaker::Rate::divide (STAmount const& amount) const
|
||||
{
|
||||
if (quality_ == QUALITY_ONE)
|
||||
return amount;
|
||||
|
||||
return ripple::divide (amount, rate_, amount.issue ());
|
||||
}
|
||||
|
||||
STAmount
|
||||
BasicTaker::Rate::multiply (STAmount const& amount) const
|
||||
{
|
||||
if (quality_ == QUALITY_ONE)
|
||||
return amount;
|
||||
|
||||
return ripple::multiply (amount, rate_, amount.issue ());
|
||||
}
|
||||
|
||||
BasicTaker::BasicTaker (
|
||||
CrossType cross_type, AccountID const& account, Amounts const& amount,
|
||||
Quality const& quality, std::uint32_t flags, std::uint32_t rate_in,
|
||||
std::uint32_t rate_out, beast::Journal journal)
|
||||
Quality const& quality, std::uint32_t flags, Rate const& rate_in,
|
||||
Rate const& rate_out, beast::Journal journal)
|
||||
: account_ (account)
|
||||
, quality_ (quality)
|
||||
, threshold_ (quality_)
|
||||
@@ -72,8 +54,8 @@ BasicTaker::BasicTaker (
|
||||
assert (remaining_.in > zero);
|
||||
assert (remaining_.out > zero);
|
||||
|
||||
assert (m_rate_in != 0);
|
||||
assert (m_rate_out != 0);
|
||||
assert (m_rate_in.value != 0);
|
||||
assert (m_rate_out.value != 0);
|
||||
|
||||
// If we are dealing with a particular flavor, make sure that it's the
|
||||
// flavor we expect:
|
||||
@@ -92,24 +74,23 @@ BasicTaker::BasicTaker (
|
||||
++threshold_;
|
||||
}
|
||||
|
||||
BasicTaker::Rate
|
||||
Rate
|
||||
BasicTaker::effective_rate (
|
||||
std::uint32_t rate, Issue const &issue,
|
||||
Rate const& rate, Issue const &issue,
|
||||
AccountID const& from, AccountID const& to)
|
||||
{
|
||||
assert (rate != 0);
|
||||
|
||||
if (rate != QUALITY_ONE)
|
||||
// If there's a transfer rate, the issuer is not involved
|
||||
// and the sender isn't the same as the recipient, return
|
||||
// the actual transfer rate.
|
||||
if (rate != parityRate &&
|
||||
from != to &&
|
||||
from != issue.account &&
|
||||
to != issue.account)
|
||||
{
|
||||
// We ignore the transfer if the sender is also the recipient since no
|
||||
// actual transfer takes place in that case. We also ignore if either
|
||||
// the sender or the receiver is the issuer.
|
||||
|
||||
if (from != to && from != issue.account && to != issue.account)
|
||||
return Rate (rate);
|
||||
return rate;
|
||||
}
|
||||
|
||||
return Rate (QUALITY_ONE);
|
||||
return parityRate;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -232,7 +213,7 @@ BasicTaker::flow_xrp_to_iou (
|
||||
{
|
||||
Flow f;
|
||||
f.order = order;
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
|
||||
log_flow ("flow_xrp_to_iou", f);
|
||||
|
||||
@@ -240,7 +221,7 @@ BasicTaker::flow_xrp_to_iou (
|
||||
if (owner_funds < f.issuers.out)
|
||||
{
|
||||
f.issuers.out = owner_funds;
|
||||
f.order.out = rate_out.divide (f.issuers.out);
|
||||
f.order.out = divide (f.issuers.out, rate_out);
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
log_flow ("(clamped on owner balance)", f);
|
||||
}
|
||||
@@ -250,7 +231,7 @@ BasicTaker::flow_xrp_to_iou (
|
||||
{
|
||||
f.order.out = remaining_.out;
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
log_flow ("(clamped on taker output)", f);
|
||||
}
|
||||
|
||||
@@ -259,7 +240,7 @@ BasicTaker::flow_xrp_to_iou (
|
||||
{
|
||||
f.order.in = taker_funds;
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
log_flow ("(clamped on taker funds)", f);
|
||||
}
|
||||
|
||||
@@ -269,7 +250,7 @@ BasicTaker::flow_xrp_to_iou (
|
||||
{
|
||||
f.order.in = remaining_.in;
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
log_flow ("(clamped on taker input)", f);
|
||||
}
|
||||
|
||||
@@ -284,7 +265,7 @@ BasicTaker::flow_iou_to_xrp (
|
||||
{
|
||||
Flow f;
|
||||
f.order = order;
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
|
||||
log_flow ("flow_iou_to_xrp", f);
|
||||
|
||||
@@ -293,7 +274,7 @@ BasicTaker::flow_iou_to_xrp (
|
||||
{
|
||||
f.order.out = owner_funds;
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
log_flow ("(clamped on owner funds)", f);
|
||||
}
|
||||
|
||||
@@ -305,7 +286,7 @@ BasicTaker::flow_iou_to_xrp (
|
||||
{
|
||||
f.order.out = remaining_.out;
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
log_flow ("(clamped on taker output)", f);
|
||||
}
|
||||
}
|
||||
@@ -314,7 +295,7 @@ BasicTaker::flow_iou_to_xrp (
|
||||
if (remaining_.in < f.order.in)
|
||||
{
|
||||
f.order.in = remaining_.in;
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
log_flow ("(clamped on taker input)", f);
|
||||
}
|
||||
@@ -323,7 +304,7 @@ BasicTaker::flow_iou_to_xrp (
|
||||
if (taker_funds < f.issuers.in)
|
||||
{
|
||||
f.issuers.in = taker_funds;
|
||||
f.order.in = rate_in.divide (f.issuers.in);
|
||||
f.order.in = divide (f.issuers.in, rate_in);
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
log_flow ("(clamped on taker funds)", f);
|
||||
}
|
||||
@@ -339,8 +320,8 @@ BasicTaker::flow_iou_to_iou (
|
||||
{
|
||||
Flow f;
|
||||
f.order = order;
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
|
||||
log_flow ("flow_iou_to_iou", f);
|
||||
|
||||
@@ -348,9 +329,9 @@ BasicTaker::flow_iou_to_iou (
|
||||
if (owner_funds < f.issuers.out)
|
||||
{
|
||||
f.issuers.out = owner_funds;
|
||||
f.order.out = rate_out.divide (f.issuers.out);
|
||||
f.order.out = divide (f.issuers.out, rate_out);
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
log_flow ("(clamped on owner funds)", f);
|
||||
}
|
||||
|
||||
@@ -359,8 +340,8 @@ BasicTaker::flow_iou_to_iou (
|
||||
{
|
||||
f.order.out = remaining_.out;
|
||||
f.order.in = qual_mul (f.order.out, quality, f.order.in);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
log_flow ("(clamped on taker output)", f);
|
||||
}
|
||||
|
||||
@@ -368,9 +349,9 @@ BasicTaker::flow_iou_to_iou (
|
||||
if (remaining_.in < f.order.in)
|
||||
{
|
||||
f.order.in = remaining_.in;
|
||||
f.issuers.in = rate_in.multiply (f.order.in);
|
||||
f.issuers.in = multiply (f.order.in, rate_in);
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
log_flow ("(clamped on taker input)", f);
|
||||
}
|
||||
|
||||
@@ -378,9 +359,9 @@ BasicTaker::flow_iou_to_iou (
|
||||
if (taker_funds < f.issuers.in)
|
||||
{
|
||||
f.issuers.in = taker_funds;
|
||||
f.order.in = rate_in.divide (f.issuers.in);
|
||||
f.order.in = divide (f.issuers.in, rate_in);
|
||||
f.order.out = qual_div (f.order.in, quality, f.order.out);
|
||||
f.issuers.out = rate_out.multiply (f.order.out);
|
||||
f.issuers.out = multiply (f.order.out, rate_out);
|
||||
log_flow ("(clamped on taker funds)", f);
|
||||
}
|
||||
|
||||
@@ -503,7 +484,7 @@ BasicTaker::do_cross (
|
||||
// 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);
|
||||
flow2.issuers.out = multiply (flow2.order.out, leg2_rate);
|
||||
log_flow ("Balancing: adjusted second leg down", flow2);
|
||||
}
|
||||
else if (flow1.order.out > flow2.order.in)
|
||||
@@ -511,7 +492,7 @@ BasicTaker::do_cross (
|
||||
// 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);
|
||||
flow1.issuers.in = multiply (flow1.order.in, leg1_rate);
|
||||
log_flow ("Balancing: adjusted first leg down", flow2);
|
||||
}
|
||||
|
||||
@@ -779,15 +760,15 @@ Taker::cross (Offer& leg1, Offer& leg2)
|
||||
return fill (ret.first, leg1, ret.second, leg2);
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
Rate
|
||||
Taker::calculateRate (
|
||||
ApplyView const& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& account)
|
||||
{
|
||||
return isXRP (issuer) || (account == issuer)
|
||||
? QUALITY_ONE
|
||||
: rippleTransferRate (view, issuer);
|
||||
? parityRate
|
||||
: transferRate (view, issuer);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Quality.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
@@ -42,28 +43,6 @@ enum class CrossType
|
||||
/** State for the active party during order book or payment operations. */
|
||||
class BasicTaker
|
||||
{
|
||||
private:
|
||||
class Rate
|
||||
{
|
||||
private:
|
||||
std::uint32_t quality_;
|
||||
STAmount rate_;
|
||||
|
||||
public:
|
||||
Rate (std::uint32_t quality)
|
||||
: quality_ (quality)
|
||||
{
|
||||
assert (quality_ != 0);
|
||||
rate_ = amountFromRate (quality_);
|
||||
}
|
||||
|
||||
STAmount
|
||||
divide (STAmount const& amount) const;
|
||||
|
||||
STAmount
|
||||
multiply (STAmount const& amount) const;
|
||||
};
|
||||
|
||||
private:
|
||||
AccountID account_;
|
||||
Quality quality_;
|
||||
@@ -82,9 +61,9 @@ private:
|
||||
Issue const& issue_out_;
|
||||
|
||||
// The rates that will be paid when the input and output currencies are
|
||||
// transfer when the currency issuer isn't involved:
|
||||
std::uint32_t const m_rate_in;
|
||||
std::uint32_t const m_rate_out;
|
||||
// transfered and the currency issuer isn't involved:
|
||||
Rate const m_rate_in;
|
||||
Rate const m_rate_out;
|
||||
|
||||
// The type of crossing that we are performing
|
||||
CrossType cross_type_;
|
||||
@@ -132,7 +111,7 @@ private:
|
||||
// flows for a particular issue between two accounts.
|
||||
static
|
||||
Rate
|
||||
effective_rate (std::uint32_t rate, Issue const &issue,
|
||||
effective_rate (Rate const& rate, Issue const &issue,
|
||||
AccountID const& from, AccountID const& to);
|
||||
|
||||
// The transfer rate for the input currency between the given accounts
|
||||
@@ -155,8 +134,8 @@ public:
|
||||
|
||||
BasicTaker (
|
||||
CrossType cross_type, AccountID const& account, Amounts const& amount,
|
||||
Quality const& quality, std::uint32_t flags, std::uint32_t rate_in,
|
||||
std::uint32_t rate_out, beast::Journal journal = beast::Journal ());
|
||||
Quality const& quality, std::uint32_t flags, Rate const& rate_in,
|
||||
Rate const& rate_out, beast::Journal journal = beast::Journal ());
|
||||
|
||||
virtual ~BasicTaker () = default;
|
||||
|
||||
@@ -291,7 +270,7 @@ public:
|
||||
|
||||
private:
|
||||
static
|
||||
std::uint32_t
|
||||
Rate
|
||||
calculateRate (ApplyView const& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& account);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/ledger/RawView.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/STLedgerEntry.h>
|
||||
#include <ripple/protocol/STObject.h>
|
||||
@@ -90,16 +91,10 @@ forEachItemAfter (ReadView const& view, AccountID const& id,
|
||||
unsigned int limit, std::function<
|
||||
bool (std::shared_ptr<SLE const> const&)> f);
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (ReadView const& view,
|
||||
Rate
|
||||
transferRate (ReadView const& view,
|
||||
AccountID const& issuer);
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (ReadView const& view,
|
||||
AccountID const& uSenderID,
|
||||
AccountID const& uReceiverID,
|
||||
AccountID const& issuer);
|
||||
|
||||
/** Returns `true` if the directory is empty
|
||||
@param key The key of the directory
|
||||
*/
|
||||
|
||||
@@ -328,31 +328,16 @@ forEachItemAfter (ReadView const& view, AccountID const& id,
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (ReadView const& view,
|
||||
Rate
|
||||
transferRate (ReadView const& view,
|
||||
AccountID const& issuer)
|
||||
{
|
||||
auto const sle = view.read(keylet::account(issuer));
|
||||
std::uint32_t quality;
|
||||
if (sle && sle->isFieldPresent (sfTransferRate))
|
||||
quality = sle->getFieldU32 (sfTransferRate);
|
||||
else
|
||||
quality = QUALITY_ONE;
|
||||
return quality;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (ReadView const& view,
|
||||
AccountID const& uSenderID,
|
||||
AccountID const& uReceiverID,
|
||||
AccountID const& issuer)
|
||||
{
|
||||
// If calculating the transfer rate from
|
||||
// or to the issuer of the currency no
|
||||
// fees are assessed.
|
||||
return (uSenderID == issuer || uReceiverID == issuer)
|
||||
? QUALITY_ONE
|
||||
: rippleTransferRate(view, issuer);
|
||||
if (sle && sle->isFieldPresent (sfTransferRate))
|
||||
return Rate{ sle->getFieldU32 (sfTransferRate) };
|
||||
|
||||
return parityRate;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1367,27 +1352,26 @@ rippleTransferFee (ReadView const& view,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
AccountID const& issuer,
|
||||
STAmount const& saAmount,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (from != issuer && to != issuer)
|
||||
{
|
||||
std::uint32_t uTransitRate = rippleTransferRate (view, issuer);
|
||||
Rate const rate = transferRate (view, issuer);
|
||||
|
||||
if (QUALITY_ONE != uTransitRate)
|
||||
if (parityRate != rate)
|
||||
{
|
||||
STAmount saTransferTotal = multiply (
|
||||
saAmount, amountFromRate (uTransitRate), saAmount.issue ());
|
||||
STAmount saTransferFee = saTransferTotal - saAmount;
|
||||
auto const fee = multiply (amount, rate) - amount;
|
||||
|
||||
JLOG (j.debug()) << "rippleTransferFee:" <<
|
||||
" saTransferFee=" << saTransferFee.getFullText ();
|
||||
" amount=" << amount.getFullText () <<
|
||||
" fee=" << fee.getFullText ();
|
||||
|
||||
return saTransferFee;
|
||||
return fee;
|
||||
}
|
||||
}
|
||||
|
||||
return saAmount.zeroed();
|
||||
return amount.zeroed();
|
||||
}
|
||||
|
||||
// Send regardless of limits.
|
||||
@@ -1426,12 +1410,8 @@ rippleSend (ApplyView& view,
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const rate = rippleTransferRate (view, issuer);
|
||||
if (QUALITY_ONE == rate)
|
||||
saActual = saAmount;
|
||||
else
|
||||
saActual =
|
||||
multiply (saAmount, amountFromRate (rate), saAmount.issue ());
|
||||
saActual = multiply (saAmount,
|
||||
transferRate (view, issuer));
|
||||
}
|
||||
|
||||
JLOG (j.debug()) << "rippleSend> " <<
|
||||
|
||||
@@ -646,27 +646,20 @@ class View_test
|
||||
using namespace jtx;
|
||||
Env env(*this);
|
||||
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gw1 = Account("gw1");
|
||||
|
||||
env.fund(XRP(10000), alice, bob, gw1);
|
||||
env.fund(XRP(10000), gw1);
|
||||
env.close();
|
||||
|
||||
auto rdView = env.closed();
|
||||
// Test with no rate set on gw1.
|
||||
expect (rippleTransferRate (*rdView, alice, bob, gw1) == 1000000000);
|
||||
expect (rippleTransferRate (*rdView, gw1, alice, gw1) == 1000000000);
|
||||
expect (rippleTransferRate (*rdView, alice, gw1, gw1) == 1000000000);
|
||||
expect (transferRate (*rdView, gw1) == parityRate);
|
||||
|
||||
env(rate(gw1, 1.02));
|
||||
env.close();
|
||||
|
||||
rdView = env.closed();
|
||||
// Test with a non-unity rate set on gw1.
|
||||
expect (rippleTransferRate (*rdView, alice, bob, gw1) == 1020000000);
|
||||
expect (rippleTransferRate (*rdView, gw1, alice, gw1) == 1000000000);
|
||||
expect (rippleTransferRate (*rdView, alice, gw1, gw1) == 1000000000);
|
||||
expect (transferRate (*rdView, gw1) == Rate{ 1020000000 });
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -30,20 +30,21 @@ namespace ripple {
|
||||
|
||||
/** Represents a transfer rate
|
||||
|
||||
Transfer rates are specified as fractions of 1 billion. For example, a
|
||||
transfer rate of 1% is represented as 1010000000.
|
||||
Transfer rates are specified as fractions of 1 billion.
|
||||
For example, a transfer rate of 1% is represented as
|
||||
1,010,000,000.
|
||||
*/
|
||||
struct Rate
|
||||
: private boost::totally_ordered <Rate>
|
||||
{
|
||||
std::uint32_t value;
|
||||
|
||||
Rate () = default;
|
||||
Rate () = delete;
|
||||
|
||||
explicit
|
||||
Rate (std::uint32_t rate)
|
||||
: value (rate)
|
||||
{
|
||||
assert (rate != 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -69,6 +70,42 @@ operator<< (std::ostream& os, Rate const& rate)
|
||||
return os;
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiply (
|
||||
STAmount const& amount,
|
||||
Rate const& rate);
|
||||
|
||||
STAmount
|
||||
multiplyRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
bool roundUp);
|
||||
|
||||
STAmount
|
||||
multiplyRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
Issue const& issue,
|
||||
bool roundUp);
|
||||
|
||||
STAmount
|
||||
divide (
|
||||
STAmount const& amount,
|
||||
Rate const& rate);
|
||||
|
||||
STAmount
|
||||
divideRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
bool roundUp);
|
||||
|
||||
STAmount
|
||||
divideRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
Issue const& issue,
|
||||
bool roundUp);
|
||||
|
||||
/** A transfer rate signifying a 1:1 exchange */
|
||||
extern Rate const parityRate;
|
||||
|
||||
|
||||
@@ -75,9 +75,6 @@ public:
|
||||
|
||||
static std::uint64_t const uRateOne;
|
||||
|
||||
static STAmount const saZero;
|
||||
static STAmount const saOne;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
STAmount(SerialIter& sit, SField const& name);
|
||||
|
||||
@@ -294,9 +291,6 @@ public:
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STAmount
|
||||
amountFromRate (std::uint64_t uRate);
|
||||
|
||||
// VFALCO TODO The parameter type should be Quality not uint64_t
|
||||
STAmount
|
||||
amountFromQuality (std::uint64_t rate);
|
||||
|
||||
@@ -149,8 +149,6 @@ mulRatio (
|
||||
if (!den)
|
||||
Throw<std::runtime_error> ("division by zero");
|
||||
|
||||
int128_t const den128 (den);
|
||||
int128_t const num128 (num);
|
||||
int128_t const amt128 (amt.drops ());
|
||||
auto const neg = amt.drops () < 0;
|
||||
auto const m = amt128 * num;
|
||||
|
||||
@@ -25,4 +25,121 @@ namespace ripple {
|
||||
|
||||
Rate const parityRate (QUALITY_ONE);
|
||||
|
||||
namespace detail {
|
||||
|
||||
STAmount as_amount (Rate const& rate)
|
||||
{
|
||||
return { noIssue(), rate.value, -9, false };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiply (
|
||||
STAmount const& amount,
|
||||
Rate const& rate)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
return amount;
|
||||
|
||||
return multiply (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
amount.issue());
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiplyRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
bool roundUp)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
return amount;
|
||||
|
||||
return mulRound (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
amount.issue(),
|
||||
roundUp);
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiplyRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
Issue const& issue,
|
||||
bool roundUp)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
return mulRound (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
issue,
|
||||
roundUp);
|
||||
}
|
||||
|
||||
STAmount
|
||||
divide (
|
||||
STAmount const& amount,
|
||||
Rate const& rate)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
return amount;
|
||||
|
||||
return divide (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
amount.issue());
|
||||
}
|
||||
|
||||
STAmount
|
||||
divideRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
bool roundUp)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
return amount;
|
||||
|
||||
return divRound (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
amount.issue(),
|
||||
roundUp);
|
||||
}
|
||||
|
||||
STAmount
|
||||
divideRound (
|
||||
STAmount const& amount,
|
||||
Rate const& rate,
|
||||
Issue const& issue,
|
||||
bool roundUp)
|
||||
{
|
||||
assert (rate.value != 0);
|
||||
|
||||
if (rate == parityRate)
|
||||
return amount;
|
||||
|
||||
return divRound (
|
||||
amount,
|
||||
detail::as_amount(rate),
|
||||
issue,
|
||||
roundUp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -406,9 +406,6 @@ STAmount operator- (STAmount const& v1, STAmount const& v2)
|
||||
|
||||
std::uint64_t const STAmount::uRateOne = getRate (STAmount (1), STAmount (1));
|
||||
|
||||
STAmount const STAmount::saZero (noIssue (), 0u);
|
||||
STAmount const STAmount::saOne (noIssue (), 1u);
|
||||
|
||||
void
|
||||
STAmount::setIssue (Issue const& issue)
|
||||
{
|
||||
@@ -721,12 +718,6 @@ void STAmount::set (std::int64_t v)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STAmount
|
||||
amountFromRate (std::uint64_t uRate)
|
||||
{
|
||||
return { noIssue(), uRate, -9, false };
|
||||
}
|
||||
|
||||
STAmount
|
||||
amountFromQuality (std::uint64_t rate)
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ bool transResultInfo (TER code, std::string& token, std::string& text)
|
||||
{ terNO_LINE, { "terNO_LINE", "No such line." } },
|
||||
{ terPRE_SEQ, { "terPRE_SEQ", "Missing/inapplicable prior transaction." } },
|
||||
{ terOWNERS, { "terOWNERS", "Non-zero owner count." } },
|
||||
{ terQUEUED, { "terQUEUED", "Held until escalated fee drops." } },
|
||||
{ terQUEUED, { "terQUEUED", "Held until escalated fee drops." } },
|
||||
|
||||
{ tesSUCCESS, { "tesSUCCESS", "The transaction was applied. Only final in a validated ledger." } },
|
||||
};
|
||||
|
||||
@@ -56,10 +56,8 @@ void addLine (Json::Value& jsonLines, RippleState const& line)
|
||||
jPeer[jss::currency] = to_string (saBalance.issue ().currency);
|
||||
jPeer[jss::limit] = saLimit.getText ();
|
||||
jPeer[jss::limit_peer] = saLimitPeer.getText ();
|
||||
jPeer[jss::quality_in]
|
||||
= static_cast<Json::UInt> (line.getQualityIn ());
|
||||
jPeer[jss::quality_out]
|
||||
= static_cast<Json::UInt> (line.getQualityOut ());
|
||||
jPeer[jss::quality_in] = line.getQualityIn ().value;
|
||||
jPeer[jss::quality_out] = line.getQualityOut ().value;
|
||||
if (line.getAuth ())
|
||||
jPeer[jss::authorized] = true;
|
||||
if (line.getAuthPeer ())
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <ripple/app/paths/cursor/AdvanceNode.cpp>
|
||||
#include <ripple/app/paths/cursor/DeliverNodeForward.cpp>
|
||||
#include <ripple/app/paths/cursor/DeliverNodeReverse.cpp>
|
||||
#include <ripple/app/paths/cursor/EffectiveRate.cpp>
|
||||
#include <ripple/app/paths/cursor/ForwardLiquidity.cpp>
|
||||
#include <ripple/app/paths/cursor/ForwardLiquidityForAccount.cpp>
|
||||
#include <ripple/app/paths/cursor/Liquidity.cpp>
|
||||
|
||||
Reference in New Issue
Block a user