本文整理汇总了C++中STAmount类的典型用法代码示例。如果您正苦于以下问题:C++ STAmount类的具体用法?C++ STAmount怎么用?C++ STAmount使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了STAmount类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: saLimitAmount
TER SetTrust::doApply ()
{
TER terResult = tesSUCCESS;
STAmount const saLimitAmount (mTxn.getFieldAmount (sfLimitAmount));
bool const bQualityIn (mTxn.isFieldPresent (sfQualityIn));
bool const bQualityOut (mTxn.isFieldPresent (sfQualityOut));
Currency const currency (saLimitAmount.getCurrency ());
Account uDstAccountID (saLimitAmount.getIssuer ());
// true, iff current is high account.
bool const bHigh = mTxnAccountID > uDstAccountID;
std::uint32_t uQualityIn (bQualityIn ? mTxn.getFieldU32 (sfQualityIn) : 0);
std::uint32_t uQualityOut (bQualityOut ? mTxn.getFieldU32 (sfQualityOut) : 0);
if (!saLimitAmount.isLegalNet ())
return temBAD_AMOUNT;
if (bQualityIn && QUALITY_ONE == uQualityIn)
uQualityIn = 0;
if (bQualityOut && QUALITY_ONE == uQualityOut)
uQualityOut = 0;
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfTrustSetMask)
{
m_journal.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
bool const bSetAuth = (uTxFlags & tfSetfAuth);
bool const bSetNoRipple = (uTxFlags & tfSetNoRipple);
bool const bClearNoRipple = (uTxFlags & tfClearNoRipple);
bool const bSetFreeze = (uTxFlags & tfSetFreeze);
bool const bClearFreeze = (uTxFlags & tfClearFreeze);
if (bSetAuth && !(mTxnAccount->getFieldU32 (sfFlags) & lsfRequireAuth))
{
m_journal.trace <<
"Retry: Auth not required.";
return tefNO_AUTH_REQUIRED;
}
if (saLimitAmount.isNative ())
{
m_journal.trace <<
"Malformed transaction: Native credit limit: " <<
saLimitAmount.getFullText ();
return temBAD_LIMIT;
}
if (saLimitAmount < zero)
{
m_journal.trace <<
"Malformed transaction: Negative credit limit.";
return temBAD_LIMIT;
}
// Check if destination makes sense.
if (!uDstAccountID || uDstAccountID == noAccount())
{
m_journal.trace <<
"Malformed transaction: Destination account not specified.";
return temDST_NEEDED;
}
if (mTxnAccountID == uDstAccountID)
{
SLE::pointer selDelete (
mEngine->entryCache (ltRIPPLE_STATE,
Ledger::getRippleStateIndex (
mTxnAccountID, uDstAccountID, currency)));
if (selDelete)
{
m_journal.warning <<
"Clearing redundant line.";
return mEngine->view ().trustDelete (
selDelete, mTxnAccountID, uDstAccountID);
}
else
{
m_journal.trace <<
"Malformed transaction: Can not extend credit to self.";
return temDST_IS_SRC;
}
}
SLE::pointer sleDst (mEngine->entryCache (
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID)));
if (!sleDst)
{
//.........这里部分代码省略.........
示例2: nodeSize
TER PathCursor::reverseLiquidityForAccount () const
{
TER terResult = tesSUCCESS;
auto const lastNodeIndex = nodeSize () - 1;
auto const isFinalNode = (nodeIndex_ == lastNodeIndex);
// 0 quality means none has yet been determined.
std::uint64_t uRateMax = 0;
// Current is allowed to redeem to next.
const bool previousNodeIsAccount = !nodeIndex_ ||
previousNode().isAccount();
const bool nextNodeIsAccount = isFinalNode || nextNode().isAccount();
AccountID const& previousAccountID = previousNodeIsAccount
? previousNode().account_ : node().account_;
AccountID const& nextAccountID = nextNodeIsAccount ? nextNode().account_
: node().account_; // Offers are always issue.
// This is the quality from from the previous node to this one.
auto const qualityIn
= (nodeIndex_ != 0)
? quality_in (view(),
node().account_,
previousAccountID,
node().issue_.currency)
: parityRate;
// And this is the quality from the next one to this one.
auto const qualityOut
= (nodeIndex_ != lastNodeIndex)
? quality_out (view(),
node().account_,
nextAccountID,
node().issue_.currency)
: parityRate;
// For previousNodeIsAccount:
// Previous account is already owed.
const STAmount saPrvOwed = (previousNodeIsAccount && nodeIndex_ != 0)
? creditBalance (view(),
node().account_,
previousAccountID,
node().issue_.currency)
: STAmount (node().issue_);
// The limit amount that the previous account may owe.
const STAmount saPrvLimit = (previousNodeIsAccount && nodeIndex_ != 0)
? creditLimit (view(),
node().account_,
previousAccountID,
node().issue_.currency)
: STAmount (node().issue_);
// Next account is owed.
const STAmount saNxtOwed = (nextNodeIsAccount && nodeIndex_ != lastNodeIndex)
? creditBalance (view(),
node().account_,
nextAccountID,
node().issue_.currency)
: STAmount (node().issue_);
JLOG (j_.trace())
<< "reverseLiquidityForAccount>"
<< " nodeIndex_=" << nodeIndex_ << "/" << lastNodeIndex
<< " previousAccountID=" << previousAccountID
<< " node.account_=" << node().account_
<< " nextAccountID=" << nextAccountID
<< " currency=" << node().issue_.currency
<< " qualityIn=" << qualityIn
<< " qualityOut=" << qualityOut
<< " saPrvOwed=" << saPrvOwed
<< " saPrvLimit=" << saPrvLimit;
// Requests are computed to be the maximum flow possible.
// Previous can redeem the owed IOUs it holds.
const STAmount saPrvRedeemReq = (saPrvOwed > beast::zero)
? saPrvOwed
: STAmount (saPrvOwed.issue ());
// Previous can issue up to limit minus whatever portion of limit already
// used (not including redeemable amount) - another "maximum flow".
const STAmount saPrvIssueReq = (saPrvOwed < beast::zero)
? saPrvLimit + saPrvOwed : saPrvLimit;
// Precompute these values in case we have an order book.
auto deliverCurrency = previousNode().saRevDeliver.getCurrency ();
const STAmount saPrvDeliverReq (
{deliverCurrency, previousNode().saRevDeliver.getIssuer ()}, -1);
// -1 means unlimited delivery.
// Set to zero, because we're trying to hit the previous node.
auto saCurRedeemAct = node().saRevRedeem.zeroed();
// Track the amount we actually redeem.
auto saCurIssueAct = node().saRevIssue.zeroed();
// For !nextNodeIsAccount
auto saCurDeliverAct = node().saRevDeliver.zeroed();
//.........这里部分代码省略.........
示例3: is_bit_set
TER PaymentTransactor::doApply ()
{
// Ripple if source or destination is non-native or if there are paths.
std::uint32_t const uTxFlags = mTxn.getFlags ();
//bool const bPartialPayment = is_bit_set(uTxFlags, tfPartialPayment);
bool const bLimitQuality = is_bit_set (uTxFlags, tfLimitQuality);
bool const bNoRippleDirect = is_bit_set (uTxFlags, tfNoRippleDirect);
bool const bPaths = mTxn.isFieldPresent (sfPaths);
bool const bMax = mTxn.isFieldPresent (sfSendMax);
uint160 const uDstAccountID = mTxn.getFieldAccount160 (sfDestination);
STAmount const saDstAmount = mTxn.getFieldAmount (sfAmount);
STAmount const saMaxAmount = bMax
? mTxn.getFieldAmount (sfSendMax)
: saDstAmount.isNative ()
? saDstAmount
: STAmount (saDstAmount.getCurrency (),
mTxnAccountID,
saDstAmount.getMantissa (),
saDstAmount.getExponent (),
saDstAmount < zero);
uint160 const uSrcCurrency = saMaxAmount.getCurrency ();
uint160 const uDstCurrency = saDstAmount.getCurrency ();
bool const bSTRDirect = uSrcCurrency.isZero () && uDstCurrency.isZero ();
m_journal.trace <<
"saMaxAmount=" << saMaxAmount.getFullText () <<
" saDstAmount=" << saDstAmount.getFullText ();
if (!saDstAmount.isLegalNet () || !saMaxAmount.isLegalNet ())
return temBAD_AMOUNT;
if (uTxFlags & tfPaymentMask)
{
m_journal.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
else if (!uDstAccountID)
{
m_journal.trace <<
"Malformed transaction: Payment destination account not specified.";
return temDST_NEEDED;
}
else if (bMax && saMaxAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad max amount: " << saMaxAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (saDstAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad dst amount: " << saDstAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (CURRENCY_BAD == uSrcCurrency || CURRENCY_BAD == uDstCurrency)
{
m_journal.trace <<
"Malformed transaction: Bad currency.";
return temBAD_CURRENCY;
}
else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
{
m_journal.trace <<
"Malformed transaction: Redundant transaction:" <<
" src=" << to_string (mTxnAccountID) <<
" dst=" << to_string (uDstAccountID) <<
" src_cur=" << to_string (uSrcCurrency) <<
" dst_cur=" << to_string (uDstCurrency);
return temREDUNDANT;
}
else if (bMax && saMaxAmount == saDstAmount && saMaxAmount.getCurrency () == saDstAmount.getCurrency ())
{
m_journal.trace <<
"Malformed transaction: Redundant SendMax.";
return temREDUNDANT_SEND_MAX;
}
else if (bSTRDirect && bMax)
{
m_journal.trace <<
"Malformed transaction: SendMax specified for STR to STR.";
return temBAD_SEND_STR_MAX;
}
else if (bSTRDirect && bPaths)
{
m_journal.trace <<
"Malformed transaction: Paths specified for STR to STR.";
return temBAD_SEND_STR_PATHS;
}
else if (bSTRDirect && bLimitQuality)
//.........这里部分代码省略.........
示例4: saLimitAmount
TER
SetTrust::doApply ()
{
TER terResult = tesSUCCESS;
STAmount const saLimitAmount (tx().getFieldAmount (sfLimitAmount));
bool const bQualityIn (tx().isFieldPresent (sfQualityIn));
bool const bQualityOut (tx().isFieldPresent (sfQualityOut));
Currency const currency (saLimitAmount.getCurrency ());
AccountID uDstAccountID (saLimitAmount.getIssuer ());
// true, iff current is high account.
bool const bHigh = account_ > uDstAccountID;
auto const sle = view().peek(
keylet::account(account_));
std::uint32_t const uOwnerCount = sle->getFieldU32 (sfOwnerCount);
// The reserve required to create the line. Note that we allow up to
// two trust lines without requiring a reserve because being able to
// exchange currencies is a powerful Ripple feature.
//
// This is also a security feature: if you're a gateway and you want to
// be able to let someone use your services, you would otherwise have to
// give them enough XRP to cover the incremental reserve for their trust
// line. If they had no intention of using your services, they could use
// the XRP for their own purposes. So we make it possible for gateways
// to fund accounts in a way where there's no incentive to trick them
// into creating an account you have no intention of using.
XRPAmount const reserveCreate ((uOwnerCount < 2)
? XRPAmount (zero)
: view().fees().accountReserve(uOwnerCount + 1));
std::uint32_t uQualityIn (bQualityIn ? tx().getFieldU32 (sfQualityIn) : 0);
std::uint32_t uQualityOut (bQualityOut ? tx().getFieldU32 (sfQualityOut) : 0);
if (bQualityOut && QUALITY_ONE == uQualityOut)
uQualityOut = 0;
std::uint32_t const uTxFlags = tx().getFlags ();
bool const bSetAuth = (uTxFlags & tfSetfAuth);
bool const bSetNoRipple = (uTxFlags & tfSetNoRipple);
bool const bClearNoRipple = (uTxFlags & tfClearNoRipple);
bool const bSetFreeze = (uTxFlags & tfSetFreeze);
bool const bClearFreeze = (uTxFlags & tfClearFreeze);
auto viewJ = ctx_.app.journal ("View");
if (bSetAuth && !(sle->getFieldU32 (sfFlags) & lsfRequireAuth))
{
j_.trace <<
"Retry: Auth not required.";
return tefNO_AUTH_REQUIRED;
}
if (account_ == uDstAccountID)
{
// The only purpose here is to allow a mistakenly created
// trust line to oneself to be deleted. If no such trust
// lines exist now, why not remove this code and simply
// return an error?
SLE::pointer sleDelete = view().peek (
keylet::line(account_, uDstAccountID, currency));
if (sleDelete)
{
j_.warning <<
"Clearing redundant line.";
return trustDelete (view(),
sleDelete, account_, uDstAccountID, viewJ);
}
else
{
j_.trace <<
"Malformed transaction: Can not extend credit to self.";
return temDST_IS_SRC;
}
}
SLE::pointer sleDst =
view().peek (keylet::account(uDstAccountID));
if (!sleDst)
{
j_.trace <<
"Delay transaction: Destination account does not exist.";
return tecNO_DST;
}
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.setIssuer (account_);
SLE::pointer sleRippleState = view().peek (
keylet::line(account_, uDstAccountID, currency));
//.........这里部分代码省略.........
示例5: bValidOffer
// Make sure an offer is still valid. If not, mark it unfunded.
bool OfferCreateTransactor::bValidOffer (
SLE::ref sleOffer,
uint256 const& uOfferIndex,
const uint160& uOfferOwnerID,
const STAmount& saOfferPays,
const STAmount& saOfferGets,
const uint160& uTakerAccountID,
boost::unordered_set<uint256>& usOfferUnfundedFound,
boost::unordered_set<uint256>& usOfferUnfundedBecame,
boost::unordered_set<uint160>& usAccountTouched,
STAmount& saOfferFunds) // <--
{
bool bValid = false;
if (sleOffer->isFieldPresent (sfExpiration) && sleOffer->getFieldU32 (sfExpiration) <= mEngine->getLedger ()->getParentCloseTimeNC ())
{
// Offer is expired. Expired offers are considered unfunded. Delete it.
WriteLog (lsINFO, OfferCreateTransactor) << "bValidOffer: encountered expired offer";
usOfferUnfundedFound.insert (uOfferIndex);
bValid = false;
}
else if (uOfferOwnerID == uTakerAccountID)
{
// Would take own offer. Consider old offer expired. Delete it.
WriteLog (lsINFO, OfferCreateTransactor) << "bValidOffer: encountered taker's own old offer";
usOfferUnfundedFound.insert (uOfferIndex);
bValid = false;
}
else if (!saOfferGets.isPositive () || !saOfferPays.isPositive ())
{
// Offer has bad amounts. Consider offer expired. Delete it.
WriteLog (lsWARNING, OfferCreateTransactor) << boost::str (boost::format ("bValidOffer: BAD OFFER: saOfferPays=%s saOfferGets=%s")
% saOfferPays % saOfferGets);
usOfferUnfundedFound.insert (uOfferIndex);
bValid = false;
}
else
{
WriteLog (lsTRACE, OfferCreateTransactor) << "bValidOffer: saOfferPays=" << saOfferPays.getFullText ();
saOfferFunds = mEngine->getNodes ().accountFunds (uOfferOwnerID, saOfferPays);
if (!saOfferFunds.isPositive ())
{
// Offer is unfunded, possibly due to previous balance action.
WriteLog (lsDEBUG, OfferCreateTransactor) << "bValidOffer: offer unfunded: delete";
boost::unordered_set<uint160>::iterator account = usAccountTouched.find (uOfferOwnerID);
if (account != usAccountTouched.end ())
{
// Previously touched account.
usOfferUnfundedBecame.insert (uOfferIndex); // Delete unfunded offer on success.
}
else
{
// Never touched source account.
usOfferUnfundedFound.insert (uOfferIndex); // Delete found unfunded offer when possible.
}
bValid = false;
}
else
{
bValid = true;
}
}
return bValid;
}
示例6: flow
path::RippleCalc::Output
flow (
PaymentSandbox& sb,
STAmount const& deliver,
AccountID const& src,
AccountID const& dst,
STPathSet const& paths,
bool defaultPaths,
bool partialPayment,
bool ownerPaysTransferFee,
boost::optional<Quality> const& limitQuality,
boost::optional<STAmount> const& sendMax,
beast::Journal j,
path::detail::FlowDebugInfo* flowDebugInfo)
{
Issue const srcIssue = [&] {
if (sendMax)
return sendMax->issue ();
if (!isXRP (deliver.issue ().currency))
return Issue (deliver.issue ().currency, src);
return xrpIssue ();
}();
Issue const dstIssue = deliver.issue ();
boost::optional<Issue> sendMaxIssue;
if (sendMax)
sendMaxIssue = sendMax->issue ();
// convert the paths to a collection of strands. Each strand is the collection
// of account->account steps and book steps that may be used in this payment.
auto sr = toStrands (sb, src, dst, dstIssue, sendMaxIssue, paths,
defaultPaths, ownerPaysTransferFee, j);
if (sr.first != tesSUCCESS)
{
path::RippleCalc::Output result;
result.setResult (sr.first);
return result;
}
auto& strands = sr.second;
if (j.trace())
{
j.trace() << "\nsrc: " << src << "\ndst: " << dst
<< "\nsrcIssue: " << srcIssue << "\ndstIssue: " << dstIssue;
j.trace() << "\nNumStrands: " << strands.size ();
for (auto const& curStrand : strands)
{
j.trace() << "NumSteps: " << curStrand.size ();
for (auto const& step : curStrand)
{
j.trace() << '\n' << *step << '\n';
}
}
}
const bool srcIsXRP = isXRP (srcIssue.currency);
const bool dstIsXRP = isXRP (dstIssue.currency);
auto const asDeliver = toAmountSpec (deliver);
// The src account may send either xrp or iou. The dst account may receive
// either xrp or iou. Since XRP and IOU amounts are represented by different
// types, use templates to tell `flow` about the amount types.
if (srcIsXRP && dstIsXRP)
{
return finishFlow (sb, srcIssue, dstIssue,
flow<XRPAmount, XRPAmount> (
sb, strands, asDeliver.xrp, defaultPaths, partialPayment,
limitQuality, sendMax, j, flowDebugInfo));
}
if (srcIsXRP && !dstIsXRP)
{
return finishFlow (sb, srcIssue, dstIssue,
flow<XRPAmount, IOUAmount> (
sb, strands, asDeliver.iou, defaultPaths, partialPayment,
limitQuality, sendMax, j, flowDebugInfo));
}
if (!srcIsXRP && dstIsXRP)
{
return finishFlow (sb, srcIssue, dstIssue,
flow<IOUAmount, XRPAmount> (
sb, strands, asDeliver.xrp, defaultPaths, partialPayment,
limitQuality, sendMax, j, flowDebugInfo));
}
assert (!srcIsXRP && !dstIsXRP);
return finishFlow (sb, srcIssue, dstIssue,
flow<IOUAmount, IOUAmount> (
sb, strands, asDeliver.iou, defaultPaths, partialPayment,
limitQuality, sendMax, j, flowDebugInfo));
}
示例7: signPayment
static Json::Value signPayment(
Json::Value const& params,
Json::Value& tx_json,
RippleAddress const& raSrcAddressID,
RPCDetail::LedgerFacade& ledgerFacade,
Role role)
{
RippleAddress dstAccountID;
if (!tx_json.isMember ("Amount"))
return RPC::missing_field_error ("tx_json.Amount");
STAmount amount;
if (! amountFromJsonNoThrow (amount, tx_json ["Amount"]))
return RPC::invalid_field_error ("tx_json.Amount");
if (!tx_json.isMember ("Destination"))
return RPC::missing_field_error ("tx_json.Destination");
if (!dstAccountID.setAccountID (tx_json["Destination"].asString ()))
return RPC::invalid_field_error ("tx_json.Destination");
if (tx_json.isMember ("Paths") && params.isMember ("build_path"))
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot specify both 'tx_json.Paths' and 'build_path'");
if (!tx_json.isMember ("Paths")
&& tx_json.isMember ("Amount")
&& params.isMember ("build_path"))
{
// Need a ripple path.
Currency uSrcCurrencyID;
Account uSrcIssuerID;
STAmount saSendMax;
if (tx_json.isMember ("SendMax"))
{
if (! amountFromJsonNoThrow (saSendMax, tx_json ["SendMax"]))
return RPC::invalid_field_error ("tx_json.SendMax");
}
else
{
// If no SendMax, default to Amount with sender as issuer.
saSendMax = amount;
saSendMax.setIssuer (raSrcAddressID.getAccountID ());
}
if (saSendMax.isNative () && amount.isNative ())
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot build XRP to XRP paths.");
{
LegacyPathFind lpf (role == Role::ADMIN);
if (!lpf.isOk ())
return rpcError (rpcTOO_BUSY);
STPathSet spsPaths;
STPath fullLiquidityPath;
bool valid = ledgerFacade.findPathsForOneIssuer (
dstAccountID,
saSendMax.issue (),
amount,
getConfig ().PATH_SEARCH_OLD,
4, // iMaxPaths
spsPaths,
fullLiquidityPath);
if (!valid)
{
WriteLog (lsDEBUG, RPCHandler)
<< "transactionSign: build_path: No paths found.";
return rpcError (rpcNO_PATH);
}
WriteLog (lsDEBUG, RPCHandler)
<< "transactionSign: build_path: "
<< spsPaths.getJson (0);
if (!spsPaths.empty ())
tx_json["Paths"] = spsPaths.getJson (0);
}
}
return Json::Value();
}
示例8: computeReverseLiquidityForAccount
TER computeReverseLiquidityForAccount (
RippleCalc& rippleCalc,
const unsigned int nodeIndex, PathState& pathState,
const bool bMultiQuality)
{
TER terResult = tesSUCCESS;
auto const lastNodeIndex = pathState.nodes().size () - 1;
auto const isFinalNode = (nodeIndex == lastNodeIndex);
// 0 quality means none has yet been determined.
std::uint64_t uRateMax = 0;
auto& previousNode = pathState.nodes()[nodeIndex ? nodeIndex - 1 : 0];
auto& node = pathState.nodes()[nodeIndex];
auto& nextNode = pathState.nodes()[isFinalNode ? lastNodeIndex : nodeIndex + 1];
// Current is allowed to redeem to next.
const bool previousNodeIsAccount = !nodeIndex || previousNode.isAccount();
const bool nextNodeIsAccount = isFinalNode || nextNode.isAccount();
const uint160& previousAccountID = previousNodeIsAccount
? previousNode.account_ : node.account_;
const uint160& nextAccountID = nextNodeIsAccount ? nextNode.account_
: node.account_; // Offers are always issue.
// This is the quality from from the previous node to this one.
const std::uint32_t uQualityIn
= (nodeIndex != 0)
? rippleCalc.mActiveLedger.rippleQualityIn (
node.account_, previousAccountID, node.currency_)
: QUALITY_ONE;
// And this is the quality from the next one to this one.
const std::uint32_t uQualityOut
= (nodeIndex != lastNodeIndex)
? rippleCalc.mActiveLedger.rippleQualityOut (
node.account_, nextAccountID, node.currency_)
: QUALITY_ONE;
// For previousNodeIsAccount:
// Previous account is already owed.
const STAmount saPrvOwed = (previousNodeIsAccount && nodeIndex != 0)
? rippleCalc.mActiveLedger.rippleOwed (
node.account_, previousAccountID, node.currency_)
: STAmount (node.currency_, node.account_);
// The limit amount that the previous account may owe.
const STAmount saPrvLimit = (previousNodeIsAccount && nodeIndex != 0)
? rippleCalc.mActiveLedger.rippleLimit (
node.account_, previousAccountID, node.currency_)
: STAmount (node.currency_, node.account_);
// Next account is owed.
const STAmount saNxtOwed = (nextNodeIsAccount && nodeIndex != lastNodeIndex)
? rippleCalc.mActiveLedger.rippleOwed (
node.account_, nextAccountID, node.currency_)
: STAmount (node.currency_, node.account_);
WriteLog (lsTRACE, RippleCalc)
<< "computeReverseLiquidityForAccount>"
<< " nodeIndex=%d/%d" << nodeIndex << "/" << lastNodeIndex
<< " previousAccountID=" << previousAccountID
<< " node.account_=" << node.account_
<< " nextAccountID=" << nextAccountID
<< " currency_=" << node.currency_
<< " uQualityIn=" << uQualityIn
<< " uQualityOut=" << uQualityOut
<< " saPrvOwed=" << saPrvOwed
<< " saPrvLimit=" << saPrvLimit;
// Requests are computed to be the maximum flow possible.
// Previous can redeem the owed IOUs it holds.
const STAmount saPrvRedeemReq = (saPrvOwed > zero)
? saPrvOwed
: STAmount (saPrvOwed.getCurrency (), saPrvOwed.getIssuer ());
// This is the amount we're actually going to be setting for the previous
// node.
STAmount& saPrvRedeemAct = previousNode.saRevRedeem;
// Previous can issue up to limit minus whatever portion of limit already
// used (not including redeemable amount) - another "maximum flow".
const STAmount saPrvIssueReq = (saPrvOwed < zero)
? saPrvLimit + saPrvOwed : saPrvLimit;
STAmount& saPrvIssueAct = previousNode.saRevIssue;
// Precompute these values in case we have an order book.
auto deliverCurrency = previousNode.saRevDeliver.getCurrency ();
const STAmount saPrvDeliverReq (
deliverCurrency, previousNode.saRevDeliver.getIssuer (), -1);
// Unlimited delivery.
STAmount& saPrvDeliverAct = previousNode.saRevDeliver;
// For nextNodeIsAccount
const STAmount& saCurRedeemReq = node.saRevRedeem;
// Set to zero, because we're trying to hit the previous node.
STAmount saCurRedeemAct (
saCurRedeemReq.getCurrency (), saCurRedeemReq.getIssuer ());
//.........这里部分代码省略.........
示例9: doRipplePathFind
// This interface is deprecated.
Json::Value doRipplePathFind (RPC::Context& context)
{
RPC::LegacyPathFind lpf (context.role == Role::ADMIN);
if (!lpf.isOk ())
return rpcError (rpcTOO_BUSY);
context.loadType = Resource::feeHighBurdenRPC;
RippleAddress raSrc;
RippleAddress raDst;
STAmount saDstAmount;
Ledger::pointer lpLedger;
Json::Value jvResult;
if (getConfig().RUN_STANDALONE ||
context.params.isMember(jss::ledger) ||
context.params.isMember(jss::ledger_index) ||
context.params.isMember(jss::ledger_hash))
{
// The caller specified a ledger
jvResult = RPC::lookupLedger (
context.params, lpLedger, context.netOps);
if (!lpLedger)
return jvResult;
}
if (!context.params.isMember (jss::source_account))
{
jvResult = rpcError (rpcSRC_ACT_MISSING);
}
else if (!context.params[jss::source_account].isString ()
|| !raSrc.setAccountID (
context.params[jss::source_account].asString ()))
{
jvResult = rpcError (rpcSRC_ACT_MALFORMED);
}
else if (!context.params.isMember (jss::destination_account))
{
jvResult = rpcError (rpcDST_ACT_MISSING);
}
else if (!context.params[jss::destination_account].isString ()
|| !raDst.setAccountID (
context.params[jss::destination_account].asString ()))
{
jvResult = rpcError (rpcDST_ACT_MALFORMED);
}
else if (
// Parse saDstAmount.
!context.params.isMember (jss::destination_amount)
|| ! amountFromJsonNoThrow(saDstAmount, context.params[jss::destination_amount])
|| saDstAmount <= zero
|| (!isXRP(saDstAmount.getCurrency ())
&& (!saDstAmount.getIssuer () ||
noAccount() == saDstAmount.getIssuer ())))
{
WriteLog (lsINFO, RPCHandler) << "Bad destination_amount.";
jvResult = rpcError (rpcINVALID_PARAMS);
}
else if (
// Checks on source_currencies.
context.params.isMember (jss::source_currencies)
&& (!context.params[jss::source_currencies].isArray ()
|| !context.params[jss::source_currencies].size ())
// Don't allow empty currencies.
)
{
WriteLog (lsINFO, RPCHandler) << "Bad source_currencies.";
jvResult = rpcError (rpcINVALID_PARAMS);
}
else
{
context.loadType = Resource::feeHighBurdenRPC;
RippleLineCache::pointer cache;
if (lpLedger)
{
// The caller specified a ledger
lpLedger = std::make_shared<Ledger> (std::ref (*lpLedger), false);
cache = std::make_shared<RippleLineCache>(lpLedger);
}
else
{
// The closed ledger is recent and any nodes made resident
// have the best chance to persist
lpLedger = context.netOps.getClosedLedger();
cache = getApp().getPathRequests().getLineCache(lpLedger, false);
}
Json::Value jvSrcCurrencies;
if (context.params.isMember (jss::source_currencies))
{
jvSrcCurrencies = context.params[jss::source_currencies];
}
else
{
jvSrcCurrencies = buildSrcCurrencies(raSrc, cache);
}
//.........这里部分代码省略.........
示例10: autofill_fee
/** Fill in the fee on behalf of the client.
This is called when the client does not explicitly specify the fee.
The client may also put a ceiling on the amount of the fee. This ceiling
is expressed as a multiplier based on the current ledger's fee schedule.
JSON fields
"Fee" The fee paid by the transaction. Omitted when the client
wants the fee filled in.
"fee_mult_max" A multiplier applied to the current ledger's transaction
fee that caps the maximum the fee server should auto fill.
If this optional field is not specified, then a default
multiplier is used.
@param tx The JSON corresponding to the transaction to fill in
@param ledger A ledger for retrieving the current fee schedule
@param result A JSON object for injecting error results, if any
@param admin `true` if this is called by an administrative endpoint.
*/
static void autofill_fee (
Json::Value& request,
RPCDetail::LedgerFacade& ledgerFacade,
Json::Value& result,
bool admin)
{
Json::Value& tx (request["tx_json"]);
if (tx.isMember ("Fee"))
return;
std::uint64_t feeByTrans = 0;
if (tx.isMember("TransactionType") && tx["TransactionType"].asString() == "Payment")
{
if (!tx.isMember("Destination"))
{
RPC::inject_error (rpcINVALID_PARAMS, "no destination account", result);
return;
}
Config d;
std::string dstAccountID = tx["Destination"].asString();
RippleAddress dstAddress;
if (!dstAddress.setAccountID(dstAccountID))
{
RPC::inject_error (rpcINVALID_PARAMS, "invalid account id", result);
return;
}
//dst account not exist yet, charge a fix amount of fee(0.01) for creating
if (!ledgerFacade.isAccountExist(dstAddress.getAccountID()))
{
feeByTrans = d.FEE_DEFAULT_CREATE;
}
//if currency is native(VRP/VBC), charge 1/1000 of transfer amount,
//otherwise charge a fix amount of fee(0.001)
if (tx.isMember("Amount"))
{
STAmount amount;
if (!amountFromJsonNoThrow(amount, tx["Amount"]))
{
RPC::inject_error (rpcINVALID_PARAMS, "wrong amount format", result);
return;
}
feeByTrans += amount.isNative() ? amount.getNValue() * d.FEE_DEFAULT_RATE_NATIVE : d.FEE_DEFAULT_NONE_NATIVE;
}
}
int mult = Tuning::defaultAutoFillFeeMultiplier;
if (request.isMember ("fee_mult_max"))
{
if (request["fee_mult_max"].isNumeric ())
{
mult = request["fee_mult_max"].asInt();
}
else
{
RPC::inject_error (rpcHIGH_FEE, RPC::expected_field_message (
"fee_mult_max", "a number"), result);
return;
}
}
// Default fee in fee units.
std::uint64_t const feeDefault = getConfig().TRANSACTION_FEE_BASE;
// Administrative endpoints are exempt from local fees.
std::uint64_t const fee = ledgerFacade.scaleFeeLoad (feeDefault, admin);
std::uint64_t const limit = mult * ledgerFacade.scaleFeeBase (feeDefault);
if (fee > limit)
{
std::stringstream ss;
ss <<
"Fee of " << fee <<
" exceeds the requested tx limit of " << limit;
RPC::inject_error (rpcHIGH_FEE, ss.str(), result);
return;
}
std::stringstream ss;
//.........这里部分代码省略.........
示例11: rippleLiquidity
void rippleLiquidity (
RippleCalc& rippleCalc,
std::uint32_t const uQualityIn,
std::uint32_t const uQualityOut,
STAmount const& saPrvReq, // --> in limit including fees, <0 = unlimited
STAmount const& saCurReq, // --> out limit
STAmount& saPrvAct, // <-> in limit including achieved so far: <-- <= -->
STAmount& saCurAct, // <-> out limit including achieved so far: <-- <= -->
std::uint64_t& uRateMax)
{
WriteLog (lsTRACE, RippleCalc)
<< "rippleLiquidity>"
<< " uQualityIn=" << uQualityIn
<< " uQualityOut=" << uQualityOut
<< " saPrvReq=" << saPrvReq
<< " saCurReq=" << saCurReq
<< " saPrvAct=" << saPrvAct
<< " saCurAct=" << saCurAct;
// saCurAct was once zero in a production server.
assert (saCurReq != zero);
assert (saCurReq > zero);
assert (saPrvReq.getCurrency () == saCurReq.getCurrency ());
assert (saPrvReq.getCurrency () == saPrvAct.getCurrency ());
assert (saPrvReq.getIssuer () == saPrvAct.getIssuer ());
const bool bPrvUnlimited = (saPrvReq < zero); // -1 means unlimited.
// Unlimited stays unlimited - don't do calculations.
// How much could possibly flow through the previous node?
const STAmount saPrv = bPrvUnlimited ? saPrvReq : saPrvReq - saPrvAct;
// How much could possibly flow through the current node?
const STAmount saCur = saCurReq - saCurAct;
WriteLog (lsTRACE, RippleCalc)
<< "rippleLiquidity: "
<< " bPrvUnlimited=" << bPrvUnlimited
<< " saPrv=" << saPrv
<< " saCur=" << saCur;
// If nothing can flow, we might as well not do any work.
if (saPrv == zero || saCur == zero)
return;
if (uQualityIn >= uQualityOut)
{
// You're getting better quality than you asked for, so no fee.
WriteLog (lsTRACE, RippleCalc) << "rippleLiquidity: No fees";
// Only process if the current rate, 1:1, is not worse than the previous
// rate, uRateMax - otherwise there is no flow.
if (!uRateMax || STAmount::uRateOne <= uRateMax)
{
// Limit amount to transfer if need - the minimum of amount being
// paid and the amount that's wanted.
STAmount saTransfer = bPrvUnlimited ? saCur
: std::min (saPrv, saCur);
// In reverse, we want to propagate the limited cur to prv and set
// actual cur.
//
// In forward, we want to propagate the limited prv to cur and set
// actual prv.
//
// This is the actual flow.
saPrvAct += saTransfer;
saCurAct += saTransfer;
// If no rate limit, set rate limit to avoid combining with
// something with a worse rate.
if (uRateMax == 0)
uRateMax = STAmount::uRateOne;
}
}
else
{
// If the quality is worse than the previous
WriteLog (lsTRACE, RippleCalc) << "rippleLiquidity: Fee";
std::uint64_t uRate = getRate (
STAmount (uQualityOut), STAmount (uQualityIn));
// 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);
// True means "round up" to get best flow.
STAmount saCurIn = divRound (
numerator, uQualityIn, {currency, uCurIssuerID}, true);
WriteLog (lsTRACE, RippleCalc)
//.........这里部分代码省略.........
示例12: uAuthKeyID
TER WalletAddTransactor::doApply ()
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfUniversalMask)
{
m_journal.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
Blob const vucPubKey = mTxn.getFieldVL (sfPublicKey);
Blob const vucSignature = mTxn.getFieldVL (sfSignature);
uint160 const uAuthKeyID (mTxn.getFieldAccount160 (sfRegularKey));
RippleAddress const naMasterPubKey (
RippleAddress::createAccountPublic (vucPubKey));
uint160 const uDstAccountID (naMasterPubKey.getAccountID ());
// FIXME: This should be moved to the transaction's signature check logic and cached
if (!naMasterPubKey.verifySignature(
Serializer::getSHA512Half (uAuthKeyID.begin (), uAuthKeyID.size ()),
vucSignature))
{
m_journal.trace <<
"Unauthorized: bad signature ";
return tefBAD_ADD_AUTH;
}
SLE::pointer sleDst (mEngine->entryCache (
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID)));
if (sleDst)
{
m_journal.trace <<
"account already created";
return tefCREATED;
}
// Direct STR payment.
STAmount saDstAmount = mTxn.getFieldAmount (sfAmount);
STAmount saPaid = mTxn.getTransactionFee ();
STAmount const saSrcBalance = mTxnAccount->getFieldAmount (sfBalance);
std::uint32_t const uOwnerCount = mTxnAccount->getFieldU32 (sfOwnerCount);
std::uint64_t const uReserve = mEngine->getLedger ()->getReserve (uOwnerCount);
// Make sure have enough reserve to send. Allow final spend to use reserve
// for fee.
// Note: Reserve is not scaled by fee.
if (saSrcBalance + saPaid < saDstAmount + uReserve)
{
// Vote no. However, transaction might succeed, if applied in a
// different order.
m_journal.trace <<
"Delay transaction: Insufficient funds: %s / %s (%d)" <<
saSrcBalance.getText () << " / " <<
(saDstAmount + uReserve).getText () << " with reserve = " <<
uReserve;
return tecUNFUNDED_ADD;
}
// Deduct initial balance from source account.
mTxnAccount->setFieldAmount (sfBalance, saSrcBalance - saDstAmount);
// Create the account.
sleDst = mEngine->entryCreate (ltACCOUNT_ROOT,
Ledger::getAccountRootIndex (uDstAccountID));
sleDst->setFieldAccount (sfAccount, uDstAccountID);
sleDst->setFieldU32 (sfSequence, 1);
sleDst->setFieldAmount (sfBalance, saDstAmount);
sleDst->setFieldAccount (sfRegularKey, uAuthKeyID);
return tesSUCCESS;
}
示例13: signPayment
static Json::Value signPayment(
Json::Value const& params,
Json::Value& tx_json,
RippleAddress const& raSrcAddressID,
Ledger::pointer lSnapshot,
int role)
{
RippleAddress dstAccountID;
if (!tx_json.isMember ("Amount"))
return RPC::missing_field_error ("tx_json.Amount");
STAmount amount;
if (!amount.bSetJson (tx_json ["Amount"]))
return RPC::invalid_field_error ("tx_json.Amount");
if (!tx_json.isMember ("Destination"))
return RPC::missing_field_error ("tx_json.Destination");
if (!dstAccountID.setAccountID (tx_json["Destination"].asString ()))
return RPC::invalid_field_error ("tx_json.Destination");
if (tx_json.isMember ("Paths") && params.isMember ("build_path"))
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot specify both 'tx_json.Paths' and 'tx_json.build_path'");
if (!tx_json.isMember ("Paths")
&& tx_json.isMember ("Amount")
&& params.isMember ("build_path"))
{
// Need a ripple path.
STPathSet spsPaths;
uint160 uSrcCurrencyID;
uint160 uSrcIssuerID;
STAmount saSendMax;
if (tx_json.isMember ("SendMax"))
{
if (!saSendMax.bSetJson (tx_json ["SendMax"]))
return RPC::invalid_field_error ("tx_json.SendMax");
}
else
{
// If no SendMax, default to Amount with sender as issuer.
saSendMax = amount;
saSendMax.setIssuer (raSrcAddressID.getAccountID ());
}
if (saSendMax.isNative () && amount.isNative ())
return RPC::make_error (rpcINVALID_PARAMS,
"Cannot build STR to STR paths.");
{
LegacyPathFind lpf (role == Config::ADMIN);
if (!lpf.isOk ())
return rpcError (rpcTOO_BUSY);
bool bValid;
auto cache = boost::make_shared<RippleLineCache> (lSnapshot);
Pathfinder pf (cache, raSrcAddressID, dstAccountID,
saSendMax.getCurrency (), saSendMax.getIssuer (),
amount, bValid);
STPath extraPath;
if (!bValid || !pf.findPaths (getConfig ().PATH_SEARCH_OLD, 4, spsPaths, extraPath))
{
WriteLog (lsDEBUG, RPCHandler)
<< "transactionSign: build_path: No paths found.";
return rpcError (rpcNO_PATH);
}
WriteLog (lsDEBUG, RPCHandler)
<< "transactionSign: build_path: "
<< spsPaths.getJson (0);
if (!spsPaths.isEmpty ())
tx_json["Paths"] = spsPaths.getJson (0);
}
}
return Json::Value();
}
示例14: doApply
TER doApply () override
{
// Ripple if source or destination is non-native or if there are paths.
std::uint32_t const uTxFlags = mTxn.getFlags ();
bool const partialPaymentAllowed = uTxFlags & tfPartialPayment;
bool const limitQuality = uTxFlags & tfLimitQuality;
bool const defaultPathsAllowed = !(uTxFlags & tfNoRippleDirect);
bool const bPaths = mTxn.isFieldPresent (sfPaths);
bool const bMax = mTxn.isFieldPresent (sfSendMax);
Account const uDstAccountID (mTxn.getFieldAccount160 (sfDestination));
STAmount const saDstAmount (mTxn.getFieldAmount (sfAmount));
STAmount maxSourceAmount;
if (bMax)
maxSourceAmount = mTxn.getFieldAmount (sfSendMax);
else if (saDstAmount.isNative ())
maxSourceAmount = saDstAmount;
else
maxSourceAmount = STAmount (
{saDstAmount.getCurrency (), mTxnAccountID},
saDstAmount.mantissa(), saDstAmount.exponent (),
saDstAmount < zero);
auto const& uSrcCurrency = maxSourceAmount.getCurrency ();
auto const& uDstCurrency = saDstAmount.getCurrency ();
// isZero() is XRP. FIX!
bool const bXRPDirect = uSrcCurrency.isZero () && uDstCurrency.isZero ();
m_journal.trace <<
"maxSourceAmount=" << maxSourceAmount.getFullText () <<
" saDstAmount=" << saDstAmount.getFullText ();
if (!isLegalNet (saDstAmount) || !isLegalNet (maxSourceAmount))
return temBAD_AMOUNT;
if (uTxFlags & tfPaymentMask)
{
m_journal.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
else if (!uDstAccountID)
{
m_journal.trace <<
"Malformed transaction: Payment destination account not specified.";
return temDST_NEEDED;
}
else if (bMax && maxSourceAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad max amount: " << maxSourceAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (saDstAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad dst amount: " << saDstAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (badCurrency() == uSrcCurrency || badCurrency() == uDstCurrency)
{
m_journal.trace <<
"Malformed transaction: Bad currency.";
return temBAD_CURRENCY;
}
else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
{
// You're signing yourself a payment.
// If bPaths is true, you might be trying some arbitrage.
m_journal.trace <<
"Malformed transaction: Redundant transaction:" <<
" src=" << to_string (mTxnAccountID) <<
" dst=" << to_string (uDstAccountID) <<
" src_cur=" << to_string (uSrcCurrency) <<
" dst_cur=" << to_string (uDstCurrency);
return temREDUNDANT;
}
else if (bMax && maxSourceAmount == saDstAmount &&
maxSourceAmount.getCurrency () == saDstAmount.getCurrency ())
{
// Consistent but redundant transaction.
m_journal.trace <<
"Malformed transaction: Redundant SendMax.";
return temREDUNDANT_SEND_MAX;
}
else if (bXRPDirect && bMax)
{
// Consistent but redundant transaction.
m_journal.trace <<
"Malformed transaction: SendMax specified for XRP to XRP.";
return temBAD_SEND_XRP_MAX;
}
else if (bXRPDirect && bPaths)
//.........这里部分代码省略.........
示例15: assert
// Take as much as possible. Adjusts account balances. Charges fees on top to taker.
// --> uBookBase: The order book to take against.
// --> saTakerPays: What the taker offers (w/ issuer)
// --> saTakerGets: What the taker wanted (w/ issuer)
// <-- saTakerPaid: What taker could have paid including saved not including fees. To reduce an offer.
// <-- saTakerGot: What taker got not including fees. To reduce an offer.
// <-- terResult: tesSUCCESS, terNO_ACCOUNT, telFAILED_PROCESSING, or tecFAILED_PROCESSING
// <-- bUnfunded: if tesSUCCESS, consider offer unfunded after taking.
TER OfferCreateTransactor::takeOffers (
const bool bOpenLedger,
const bool bPassive,
const bool bSell,
uint256 const& uBookBase,
const uint160& uTakerAccountID,
SLE::ref sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot,
bool& bUnfunded)
{
// The book has the most elements. Take the perspective of the book.
// Book is ordered for taker: taker pays / taker gets (smaller is better)
// The order is for the other books currencys for get and pays are opposites.
// We want the same ratio for the respective currencies.
// So we swap paid and gets for determing take quality.
assert (saTakerPays && saTakerGets);
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: bSell: " << bSell << ": against book: " << uBookBase.ToString ();
LedgerEntrySet& lesActive = mEngine->getNodes ();
uint256 uTipIndex = uBookBase;
const uint256 uBookEnd = Ledger::getQualityNext (uBookBase);
const uint64 uTakeQuality = STAmount::getRate (saTakerGets, saTakerPays);
STAmount saTakerRate = STAmount::setRate (uTakeQuality);
const uint160 uTakerPaysAccountID = saTakerPays.getIssuer ();
const uint160 uTakerGetsAccountID = saTakerGets.getIssuer ();
TER terResult = temUNCERTAIN;
boost::unordered_set<uint256> usOfferUnfundedBecame; // Offers that became unfunded.
boost::unordered_set<uint160> usAccountTouched; // Accounts touched.
saTakerPaid = STAmount (saTakerPays.getCurrency (), saTakerPays.getIssuer ());
saTakerGot = STAmount (saTakerGets.getCurrency (), saTakerGets.getIssuer ());
bUnfunded = false;
while (temUNCERTAIN == terResult)
{
SLE::pointer sleOfferDir;
uint64 uTipQuality = 0;
STAmount saTakerFunds = lesActive.accountFunds (uTakerAccountID, saTakerPays);
STAmount saSubTakerPays = saTakerPays - saTakerPaid; // How much more to spend.
STAmount saSubTakerGets = saTakerGets - saTakerGot; // How much more is wanted.
// Figure out next offer to take, if needed.
if (saTakerFunds.isPositive () // Taker has funds available.
&& saSubTakerPays.isPositive ()
&& saSubTakerGets.isPositive ())
{
sleOfferDir = mEngine->entryCache (ltDIR_NODE, lesActive.getNextLedgerIndex (uTipIndex, uBookEnd));
if (sleOfferDir)
{
uTipIndex = sleOfferDir->getIndex ();
uTipQuality = Ledger::getQuality (uTipIndex);
WriteLog (lsDEBUG, OfferCreateTransactor) << boost::str (boost::format ("takeOffers: possible counter offer found: uTipQuality=%d uTipIndex=%s")
% uTipQuality
% uTipIndex.ToString ());
}
else
{
WriteLog (lsTRACE, OfferCreateTransactor) << "takeOffers: counter offer book is empty: "
<< uTipIndex.ToString ()
<< " ... "
<< uBookEnd.ToString ();
}
}
if (!saTakerFunds.isPositive ()) // Taker has no funds.
{
// Done. Ran out of funds on previous round. As fees aren't calculated directly in this routine, funds are checked here.
WriteLog (lsDEBUG, OfferCreateTransactor) << "takeOffers: done: taker unfunded.";
bUnfunded = true; // Don't create an order.
terResult = tesSUCCESS;
}
else if (!sleOfferDir // No offer directory to take.
|| uTakeQuality < uTipQuality // No offers of sufficient quality available.
|| (bPassive && uTakeQuality == uTipQuality))
{
// Done.
STAmount saTipRate = sleOfferDir ? STAmount::setRate (uTipQuality) : saTakerRate;
WriteLog (lsDEBUG, OfferCreateTransactor) << boost::str (boost::format ("takeOffers: done: dir=%d uTakeQuality=%d %c uTipQuality=%d saTakerRate=%s %c saTipRate=%s bPassive=%d")
% !!sleOfferDir
% uTakeQuality
//.........这里部分代码省略.........