20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
22#include <xrpld/ledger/ReadView.h>
23#include <xrpld/ledger/View.h>
25#include <xrpl/basics/Expected.h>
26#include <xrpl/basics/Log.h>
27#include <xrpl/basics/chrono.h>
28#include <xrpl/beast/utility/instrumentation.h>
29#include <xrpl/protocol/Feature.h>
30#include <xrpl/protocol/Indexes.h>
31#include <xrpl/protocol/LedgerFormats.h>
32#include <xrpl/protocol/MPTIssue.h>
33#include <xrpl/protocol/Protocol.h>
34#include <xrpl/protocol/Quality.h>
35#include <xrpl/protocol/TER.h>
36#include <xrpl/protocol/TxFlags.h>
37#include <xrpl/protocol/digest.h>
38#include <xrpl/protocol/st.h>
51 std::is_same_v<std::remove_cv_t<N>,
SLE> &&
52 std::is_base_of_v<ReadView, V>>>
61 auto const& svIndexes = page->getFieldV256(sfIndexes);
63 index <= svIndexes.size(),
64 "ripple::detail::internalDirNext : index inside range");
66 if (index >= svIndexes.size())
68 auto const next = page->getFieldU64(sfIndexNext);
76 if constexpr (std::is_const_v<N>)
81 XRPL_ASSERT(page,
"ripple::detail::internalDirNext : non-null root");
91 entry = svIndexes[index++];
99 std::is_same_v<std::remove_cv_t<N>,
SLE> &&
100 std::is_base_of_v<ReadView, V>>>
109 if constexpr (std::is_const_v<N>)
206 if constexpr (std::is_same_v<TIss, Issue>)
223 if (issuer != account)
260 if (issuer != account)
293 for (
auto const& account : accounts)
299 for (
auto const& account : accounts)
321 auto const mptIssuance =
323 if (mptIssuance ==
nullptr)
326 auto const issuer = mptIssuance->getAccountID(sfIssuer);
328 if (mptIssuer ==
nullptr)
330 UNREACHABLE(
"ripple::isVaultPseudoAccountFrozen : null MPToken issuer");
334 if (!mptIssuer->isFieldPresent(sfVaultID))
339 if (vault ==
nullptr)
341 UNREACHABLE(
"ripple::isVaultPseudoAccountFrozen : null vault");
345 return isAnyFrozen(view, {issuer, account}, vault->at(sfAsset), depth + 1);
360 if (issuer == account)
402 auto const allowBalance = [&]() {
410 if (
isFrozen(view, account, currency, issuer) ||
425 else if (sleIssuer->isFieldPresent(sfAMMID))
434 (*sleAmm)[sfAsset].get<Issue>(),
435 (*sleAmm)[sfAsset2].get<Issue>()))
448 amount = sle->getFieldAmount(sfBalance);
449 if (account > issuer)
461 JLOG(j.
trace()) <<
"accountHolds:"
495 amount.
clear(mptIssue);
498 amount.
clear(mptIssue);
501 amount =
STAmount{mptIssue, sleMpt->getFieldU64(sfMPTAmount)};
511 amount.
clear(mptIssue);
515 auto const sleIssuance =
522 amount.
clear(mptIssue);
529[[nodiscard]] STAmount
539 [&](
auto const& value) {
544 return accountHolds(view, account, value, zeroIfFrozen, j);
547 view, account, value, zeroIfFrozen, zeroIfUnauthorized, j);
594 <<
"Account " << *
id <<
" owner count exceeds max!";
607 <<
"Account " << *
id <<
" owner count set below 0!";
610 XRPL_ASSERT(!
id,
"ripple::confineOwnerCount : id is not set");
629 view.
ownerCountHook(
id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
632 auto const reserve = sle->isFieldPresent(sfAMMID)
636 auto const fullBalance = sle->getFieldAmount(sfBalance);
641 (balance < reserve) ?
STAmount{0} : balance - reserve;
643 JLOG(j.
trace()) <<
"accountHolds:"
646 <<
" fullBalance=" << fullBalance.getFullText()
647 <<
" balance=" << balance.getFullText()
648 <<
" reserve=" << reserve <<
" ownerCount=" << ownerCount
649 <<
" ownerCountAdj=" << ownerCountAdj;
661 root.type == ltDIR_NODE,
"ripple::forEachItem : valid root type");
663 if (
root.type != ltDIR_NODE)
670 auto sle = view.
read(pos);
673 for (
auto const& key : sle->getFieldV256(sfIndexes))
675 auto const next = sle->getFieldU64(sfIndexNext);
692 root.type == ltDIR_NODE,
"ripple::forEachItemAfter : valid root type");
694 if (
root.type != ltDIR_NODE)
697 auto currentIndex =
root;
700 if (
after.isNonZero())
704 if (
auto hintDir = view.
read(hintIndex))
706 for (
auto const& key : hintDir->getFieldV256(sfIndexes))
711 currentIndex = hintIndex;
720 auto const ownerDir = view.
read(currentIndex);
723 for (
auto const& key : ownerDir->getFieldV256(sfIndexes))
736 auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext);
746 auto const ownerDir = view.
read(currentIndex);
749 for (
auto const& key : ownerDir->getFieldV256(sfIndexes))
752 auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext);
765 if (sle && sle->isFieldPresent(sfTransferRate))
766 return Rate{sle->getFieldU32(sfTransferRate)};
778 sle && sle->isFieldPresent(sfTransferFee))
779 return Rate{1'000'000'000u + 10'000 * sle->getFieldU16(sfTransferFee)};
789 if constexpr (std::is_same_v<TIss, Issue>)
813 if (hash && (*hash != validLedger.
info().
hash))
815 JLOG(s) << reason <<
" incompatible with valid ledger";
817 JLOG(s) <<
"Hash(VSeq): " <<
to_string(*hash);
829 if (hash && (*hash != testLedger.
info().
hash))
831 JLOG(s) << reason <<
" incompatible preceding ledger";
833 JLOG(s) <<
"Hash(NSeq): " <<
to_string(*hash);
843 JLOG(s) << reason <<
" incompatible ledger";
850 JLOG(s) <<
"Val: " << validLedger.
info().
seq <<
" "
853 JLOG(s) <<
"New: " << testLedger.
info().
seq <<
" "
870 if (testLedger.
info().
seq > validIndex)
877 if (hash && (*hash != validHash))
879 JLOG(s) << reason <<
" incompatible following ledger";
880 JLOG(s) <<
"Hash(VSeq): " <<
to_string(*hash);
886 (validIndex == testLedger.
info().
seq) &&
887 (testLedger.
info().
hash != validHash))
889 JLOG(s) << reason <<
" incompatible ledger";
896 JLOG(s) <<
"Val: " << validIndex <<
" " <<
to_string(validHash);
898 JLOG(s) <<
"New: " << testLedger.
info().
seq <<
" "
908 auto const sleNode = view.
read(k);
911 if (!sleNode->getFieldV256(sfIndexes).empty())
916 return sleNode->getFieldU64(sfIndexNext) == 0;
926 if (sle->isFieldPresent(sfAmendments))
928 auto const& v = sle->getFieldV256(sfAmendments);
929 amendments.insert(v.begin(), v.end());
943 if (sle->isFieldPresent(sfMajorities))
946 using d = tp::duration;
948 auto const majorities = sle->getFieldArray(sfMajorities);
950 for (
auto const& m : majorities)
951 ret[m.getFieldH256(sfAmendment)] =
952 tp(d(m.getFieldU32(sfCloseTime)));
963 if (seq > ledger.
seq())
966 <<
"Can't get seq " << seq <<
" from " << ledger.
seq() <<
" future";
969 if (seq == ledger.
seq())
971 if (seq == (ledger.
seq() - 1))
974 if (
int diff = ledger.
seq() - seq; diff <= 256)
981 hashIndex->getFieldU32(sfLastLedgerSequence) ==
983 "ripple::hashOfSeq : matching ledger sequence");
984 STVector256 vec = hashIndex->getFieldV256(sfHashes);
985 if (vec.
size() >= diff)
986 return vec[vec.
size() - diff];
988 <<
"Ledger " << ledger.
seq() <<
" missing hash for " << seq
989 <<
" (" << vec.
size() <<
"," << diff <<
")";
994 <<
"Ledger " << ledger.
seq() <<
":" << ledger.
info().
hash
995 <<
" missing normal list";
999 if ((seq & 0xff) != 0)
1001 JLOG(journal.
debug())
1002 <<
"Can't get seq " << seq <<
" from " << ledger.
seq() <<
" past";
1003 return std::nullopt;
1010 auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence);
1011 XRPL_ASSERT(lastSeq >= seq,
"ripple::hashOfSeq : minimum last ledger");
1013 (lastSeq & 0xff) == 0,
"ripple::hashOfSeq : valid last ledger");
1014 auto const diff = (lastSeq - seq) >> 8;
1015 STVector256 vec = hashIndex->getFieldV256(sfHashes);
1016 if (vec.
size() > diff)
1017 return vec[vec.
size() - diff - 1];
1019 JLOG(journal.
warn()) <<
"Can't get seq " << seq <<
" from " << ledger.
seq()
1021 return std::nullopt;
1039 XRPL_ASSERT(amount,
"ripple::adjustOwnerCount : nonzero amount input");
1044 sle->setFieldU32(sfOwnerCount, adjusted);
1052 (*sle)[sfOwner] = account;
1063 object->setFieldU64(sfOwnerNode, *page);
1076 rsh(hash.data(), hash.size());
1094Expected<std::shared_ptr<SLE>,
TER>
1097 uint256 const& pseudoOwnerKey,
1098 SField const& ownerField)
1104 [&ownerField](
SField const* sf) ->
bool {
1105 return *sf == ownerField;
1107 "ripple::createPseudoAccount : valid owner field");
1110 if (accountId == beast::zero)
1115 account->setAccountID(sfAccount, accountId);
1116 account->setFieldAmount(sfBalance,
STAmount{});
1125 account->setFieldU32(sfSequence, seqno);
1129 account->setFieldU32(
1132 account->setFieldH256(ownerField, pseudoOwnerKey);
1144 return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
1148 [&sleAcct](
SField const* sf) ->
bool {
1149 return sleAcct->isFieldPresent(*sf);
1165 auto const& issuerId = issue.
getIssuer();
1166 auto const& currency = issue.
currency;
1170 auto const& srcId = issuerId;
1171 auto const& dstId = accountID;
1172 auto const high = srcId > dstId;
1173 auto const index =
keylet::line(srcId, dstId, currency);
1176 if (!sleDst || !sleSrc)
1181 if (view.
read(index))
1194 STAmount{Issue{currency, noAccount()}},
1195 STAmount{Issue{currency, dstId}},
1209 auto const& mptID = mptIssue.
getMptID();
1210 auto const mpt = view.
peek(keylet::mptIssuance(mptID));
1215 if (view.
peek(keylet::mptoken(mptID, accountID)))
1218 return MPTokenAuthorize::authorize(
1221 {.priorBalance = priorBalance,
1222 .mptIssuanceID = mptID,
1223 .account = accountID});
1229 bool const bSrcHigh,
1235 bool const bNoRipple,
1246 JLOG(j.
trace()) <<
"trustCreate: " << to_string(uSrcAccountID) <<
", "
1247 << to_string(uDstAccountID) <<
", "
1250 auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
1251 auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
1253 auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
1254 view.
insert(sleRippleState);
1257 keylet::ownerDir(uLowAccountID),
1258 sleRippleState->key(),
1265 keylet::ownerDir(uHighAccountID),
1266 sleRippleState->key(),
1272 bool const bSetDst = saLimit.
getIssuer() == uDstAccountID;
1273 bool const bSetHigh = bSrcHigh ^ bSetDst;
1275 XRPL_ASSERT(sleAccount,
"ripple::trustCreate : non-null SLE");
1280 sleAccount->getAccountID(sfAccount) ==
1281 (bSetHigh ? uHighAccountID : uLowAccountID),
1282 "ripple::trustCreate : matching account ID");
1283 auto const slePeer =
1284 view.
peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
1289 sleRippleState->setFieldU64(sfLowNode, *lowNode);
1290 sleRippleState->setFieldU64(sfHighNode, *highNode);
1292 sleRippleState->setFieldAmount(
1293 bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
1294 sleRippleState->setFieldAmount(
1295 bSetHigh ? sfLowLimit : sfHighLimit,
1297 saBalance.
getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID}));
1300 sleRippleState->setFieldU32(
1301 bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
1304 sleRippleState->setFieldU32(
1305 bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
1332 sleRippleState->setFieldU32(sfFlags, uFlags);
1336 sleRippleState->setFieldAmount(
1337 sfBalance, bSetHigh ? -saBalance : saBalance);
1340 uSrcAccountID, uDstAccountID, saBalance, saBalance.
zeroed());
1354 auto const sle = view.
read(keylet::account(accountID));
1357 auto const balance = sle->getFieldAmount(sfBalance);
1358 if (balance.xrp() != 0)
1364 auto const line = view.
peek(keylet::line(accountID, issue));
1367 if (line->at(sfBalance)->iou() != beast::zero)
1374 auto sleLowAccount =
1375 view.
peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
1388 auto sleHighAccount =
1389 view.
peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
1390 if (!sleHighAccount)
1402 line->at(sfLowLimit)->getIssuer(),
1403 line->at(sfHighLimit)->getIssuer(),
1414 auto const& mptID = mptIssue.
getMptID();
1415 auto const mptoken = view.
peek(keylet::mptoken(mptID, accountID));
1418 if (mptoken->at(sfMPTAmount) != 0)
1421 return MPTokenAuthorize::authorize(
1424 {.priorBalance = {},
1425 .mptIssuanceID = mptID,
1426 .account = accountID,
1439 std::uint64_t uLowNode = sleRippleState->getFieldU64(sfLowNode);
1440 std::uint64_t uHighNode = sleRippleState->getFieldU64(sfHighNode);
1442 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: low";
1445 keylet::ownerDir(uLowAccountID),
1447 sleRippleState->key(),
1453 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: high";
1456 keylet::ownerDir(uHighAccountID),
1458 sleRippleState->key(),
1464 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: state";
1465 view.
erase(sleRippleState);
1475 auto offerIndex = sle->key();
1476 auto owner = sle->getAccountID(sfAccount);
1479 uint256 uDirectory = sle->getFieldH256(sfBookDirectory);
1482 keylet::ownerDir(owner),
1483 sle->getFieldU64(sfOwnerNode),
1491 keylet::page(uDirectory),
1492 sle->getFieldU64(sfBookNode),
1499 if (sle->isFieldPresent(sfAdditionalBooks))
1502 sle->isFlag(
lsfHybrid) && sle->isFieldPresent(sfDomainID),
1503 "ripple::offerDelete : should be a hybrid domain offer");
1505 auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks);
1507 for (
auto const& bookDir : additionalBookDirs)
1509 auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory);
1510 auto const& dirNode = bookDir.getFieldU64(sfBookNode);
1513 keylet::page(dirIndex), dirNode, offerIndex,
false))
1545 !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer,
1546 "ripple::rippleCreditIOU : matching issuer or don't care");
1551 uSenderID != uReceiverID,
1552 "ripple::rippleCreditIOU : sender is not receiver");
1554 bool const bSenderHigh = uSenderID > uReceiverID;
1555 auto const index = keylet::line(uSenderID, uReceiverID, currency);
1559 "ripple::rippleCreditIOU : sender is not XRP");
1562 "ripple::rippleCreditIOU : receiver is not XRP");
1565 if (
auto const sleRippleState = view.
peek(index))
1567 STAmount saBalance = sleRippleState->getFieldAmount(sfBalance);
1572 view.
creditHook(uSenderID, uReceiverID, saAmount, saBalance);
1574 STAmount const saBefore = saBalance;
1576 saBalance -= saAmount;
1578 JLOG(j.
trace()) <<
"rippleCreditIOU: " << to_string(uSenderID) <<
" -> "
1579 << to_string(uReceiverID)
1584 std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags));
1585 bool bDelete =
false;
1589 if (saBefore > beast::zero
1591 && saBalance <= beast::zero
1599 view.
read(keylet::account(uSenderID))->getFlags() &
1602 !sleRippleState->getFieldAmount(
1603 !bSenderHigh ? sfLowLimit : sfHighLimit)
1605 && !sleRippleState->getFieldU32(
1606 !bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1608 && !sleRippleState->getFieldU32(
1609 !bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1614 view, view.
peek(keylet::account(uSenderID)), -1, j);
1617 sleRippleState->setFieldU32(
1622 bDelete = !saBalance
1631 sleRippleState->setFieldAmount(sfBalance, saBalance);
1639 bSenderHigh ? uReceiverID : uSenderID,
1640 !bSenderHigh ? uReceiverID : uSenderID,
1644 view.
update(sleRippleState);
1648 STAmount const saReceiverLimit(
Issue{currency, uReceiverID});
1653 JLOG(j.
debug()) <<
"rippleCreditIOU: "
1655 << to_string(uSenderID) <<
" -> " << to_string(uReceiverID)
1658 auto const sleAccount = view.
peek(keylet::account(uReceiverID));
1695 auto const issuer = saAmount.
getIssuer();
1699 "ripple::rippleSendIOU : neither sender nor receiver is XRP");
1701 uSenderID != uReceiverID,
1702 "ripple::rippleSendIOU : sender is not receiver");
1704 if (uSenderID == issuer || uReceiverID == issuer || issuer ==
noAccount())
1711 saActual = saAmount;
1719 saActual = (waiveFee == WaiveTransferFee::Yes)
1723 JLOG(j.
debug()) <<
"rippleSendIOU> " << to_string(uSenderID) <<
" - > "
1724 << to_string(uReceiverID)
1732 terResult =
rippleCreditIOU(view, uSenderID, issuer, saActual,
true, j);
1757 "ripple::accountSendIOU : minimum amount and not MPT");
1763 if (!saAmount || (uSenderID == uReceiverID))
1770 JLOG(j.
trace()) <<
"accountSendIOU: " << to_string(uSenderID) <<
" -> "
1771 << to_string(uReceiverID) <<
" : "
1775 view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee);
1786 ? view.
peek(keylet::account(uSenderID))
1789 ? view.
peek(keylet::account(uReceiverID))
1792 if (
auto stream = j.
trace())
1798 sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1801 receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1803 stream <<
"accountSendIOU> " << to_string(uSenderID) <<
" ("
1804 << sender_bal <<
") -> " << to_string(uReceiverID) <<
" ("
1805 << receiver_bal <<
") : " << saAmount.
getFullText();
1810 if (sender->getFieldAmount(sfBalance) < saAmount)
1819 auto const sndBal = sender->getFieldAmount(sfBalance);
1823 sender->setFieldAmount(sfBalance, sndBal - saAmount);
1831 auto const rcvBal = receiver->getFieldAmount(sfBalance);
1832 receiver->setFieldAmount(sfBalance, rcvBal + saAmount);
1838 if (
auto stream = j.
trace())
1844 sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1847 receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1849 stream <<
"accountSendIOU< " << to_string(uSenderID) <<
" ("
1850 << sender_bal <<
") -> " << to_string(uReceiverID) <<
" ("
1851 << receiver_bal <<
") : " << saAmount.
getFullText();
1867 auto const issuer = saAmount.
getIssuer();
1868 auto sleIssuance = view.
peek(mptID);
1871 if (uSenderID == issuer)
1873 (*sleIssuance)[sfOutstandingAmount] += saAmount.
mpt().
value();
1874 view.
update(sleIssuance);
1878 auto const mptokenID = keylet::mptoken(mptID.key, uSenderID);
1879 if (
auto sle = view.
peek(mptokenID))
1881 auto const amt = sle->getFieldU64(sfMPTAmount);
1882 auto const pay = saAmount.
mpt().
value();
1885 (*sle)[sfMPTAmount] = amt - pay;
1892 if (uReceiverID == issuer)
1894 auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount);
1895 auto const redeem = saAmount.
mpt().
value();
1896 if (outstanding >= redeem)
1898 sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem);
1899 view.
update(sleIssuance);
1906 auto const mptokenID = keylet::mptoken(mptID.key, uReceiverID);
1907 if (
auto sle = view.
peek(mptokenID))
1909 (*sle)[sfMPTAmount] += saAmount.
mpt().
value();
1930 uSenderID != uReceiverID,
1931 "ripple::rippleSendMPT : sender is not receiver");
1934 auto const issuer = saAmount.
getIssuer();
1941 if (uSenderID == issuer || uReceiverID == issuer)
1945 if (uSenderID == issuer)
1947 auto const sendAmount = saAmount.
mpt().
value();
1948 auto const maximumAmount =
1950 if (sendAmount > maximumAmount ||
1951 sle->getFieldU64(sfOutstandingAmount) >
1952 maximumAmount - sendAmount)
1961 saActual = saAmount;
1966 saActual = (waiveFee == WaiveTransferFee::Yes)
1972 JLOG(j.
debug()) <<
"rippleSendMPT> " << to_string(uSenderID) <<
" - > "
1973 << to_string(uReceiverID)
1977 if (
auto const terResult =
1996 "ripple::accountSendMPT : minimum amount and MPT");
2001 if (!saAmount || (uSenderID == uReceiverID))
2007 view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee);
2021 if constexpr (std::is_same_v<TIss, Issue>)
2023 view, uSenderID, uReceiverID, saAmount, j, waiveFee);
2026 view, uSenderID, uReceiverID, saAmount, j, waiveFee);
2045 auto sle = view.
peek(keylet::account(sender));
2050 if (before > beast::zero
2052 &&
after <= beast::zero
2056 &&
static_cast<bool>(
2060 !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
2062 && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
2065 !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
2094 "ripple::issueIOU : neither account nor issuer is XRP");
2097 XRPL_ASSERT(issue == amount.
issue(),
"ripple::issueIOU : matching issue");
2101 issue.
account != account,
"ripple::issueIOU : not issuer account");
2103 JLOG(j.
trace()) <<
"issueIOU: " << to_string(account) <<
": "
2106 bool bSenderHigh = issue.
account > account;
2108 auto const index = keylet::line(issue.
account, account, issue.
currency);
2110 if (
auto state = view.
peek(index))
2112 STAmount final_balance = state->getFieldAmount(sfBalance);
2117 STAmount const start_balance = final_balance;
2119 final_balance -= amount;
2138 state->setFieldAmount(sfBalance, final_balance);
2143 bSenderHigh ? account : issue.
account,
2144 bSenderHigh ? issue.
account : account,
2160 auto const receiverAccount = view.
peek(keylet::account(account));
2161 if (!receiverAccount)
2194 "ripple::redeemIOU : neither account nor issuer is XRP");
2197 XRPL_ASSERT(issue == amount.
issue(),
"ripple::redeemIOU : matching issue");
2201 issue.
account != account,
"ripple::redeemIOU : not issuer account");
2203 JLOG(j.
trace()) <<
"redeemIOU: " << to_string(account) <<
": "
2206 bool bSenderHigh = account > issue.
account;
2211 STAmount final_balance = state->getFieldAmount(sfBalance);
2216 STAmount const start_balance = final_balance;
2218 final_balance -= amount;
2221 view, state, bSenderHigh, account, start_balance, final_balance, j);
2231 state->setFieldAmount(sfBalance, final_balance);
2238 bSenderHigh ? issue.
account : account,
2239 bSenderHigh ? account : issue.
account,
2250 JLOG(j.
fatal()) <<
"redeemIOU: " << to_string(account)
2252 <<
" but no trust line exists!";
2266 from != beast::zero,
"ripple::transferXRP : nonzero from account");
2267 XRPL_ASSERT(to != beast::zero,
"ripple::transferXRP : nonzero to account");
2268 XRPL_ASSERT(from != to,
"ripple::transferXRP : sender is not receiver");
2269 XRPL_ASSERT(amount.
native(),
"ripple::transferXRP : amount is XRP");
2273 if (!sender || !receiver)
2276 JLOG(j.
trace()) <<
"transferXRP: " << to_string(from) <<
" -> "
2277 << to_string(to) <<
") : " << amount.
getFullText();
2279 if (sender->getFieldAmount(sfBalance) < amount)
2289 sender->setFieldAmount(
2290 sfBalance, sender->getFieldAmount(sfBalance) - amount);
2293 receiver->setFieldAmount(
2294 sfBalance, receiver->getFieldAmount(sfBalance) + amount);
2310 auto const trustLine =
2313 if (!trustLine && authType == AuthType::StrongAuth)
2318 if (
auto const issuerAccount = view.
read(keylet::account(issue.
account));
2322 return ((*trustLine)[sfFlags] &
2340 auto const mptID = keylet::mptIssuance(mptIssue.
getMptID());
2341 auto const sleIssuance = view.
read(mptID);
2345 auto const mptIssuer = sleIssuance->getAccountID(sfIssuer);
2348 if (mptIssuer == account)
2357 auto const sleIssuer = view.
read(keylet::account(mptIssuer));
2361 if (sleIssuer->isFieldPresent(sfVaultID))
2363 auto const sleVault =
2364 view.
read(keylet::vault(sleIssuer->getFieldH256(sfVaultID)));
2368 auto const asset = sleVault->at(sfAsset);
2371 if constexpr (std::is_same_v<TIss, Issue>)
2372 return requireAuth(view, issue, account, authType);
2375 view, issue, account, authType, depth + 1);
2383 auto const mptokenID = keylet::mptoken(mptID.key, account);
2384 auto const sleToken = view.
read(mptokenID);
2388 (authType == AuthType::StrongAuth || authType == AuthType::Legacy))
2393 auto const maybeDomainID = sleIssuance->at(~sfDomainID);
2398 "ripple::requireAuth : issuance requires authorization");
2400 if (
auto const ter =
2401 credentials::validDomain(view, *maybeDomainID, account);
2421 MPTID const& mptIssuanceID,
2426 auto const sleIssuance = view.
read(keylet::mptIssuance(mptIssuanceID));
2432 "ripple::enforceMPTokenAuthorization : authorization required");
2434 if (account == sleIssuance->at(sfIssuer))
2437 auto const keylet = keylet::mptoken(mptIssuanceID, account);
2438 auto const sleToken = view.
read(keylet);
2439 auto const maybeDomainID = sleIssuance->at(~sfDomainID);
2441 bool const authorizedByDomain = [&]() ->
bool {
2443 if (!maybeDomainID.has_value())
2454 if (!authorizedByDomain && sleToken ==
nullptr)
2465 else if (!authorizedByDomain && maybeDomainID.has_value())
2472 else if (!authorizedByDomain)
2477 sleToken !=
nullptr && !maybeDomainID.has_value(),
2478 "ripple::enforceMPTokenAuthorization : found MPToken");
2484 else if (authorizedByDomain && sleToken !=
nullptr)
2489 maybeDomainID.has_value(),
2490 "ripple::enforceMPTokenAuthorization : found MPToken for domain");
2493 else if (authorizedByDomain)
2498 maybeDomainID.has_value() && sleToken ==
nullptr,
2499 "ripple::enforceMPTokenAuthorization : new MPToken for domain");
2500 if (
auto const err = MPTokenAuthorize::authorize(
2504 .priorBalance = priorBalance,
2505 .mptIssuanceID = mptIssuanceID,
2517 "ripple::enforceMPTokenAuthorization : condition list is incomplete");
2528 auto const mptID = keylet::mptIssuance(mptIssue.
getMptID());
2529 auto const sleIssuance = view.
read(mptID);
2535 if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer])
2544 Keylet const& ownerDirKeylet,
2551 unsigned int uDirEntry{0};
2552 uint256 dirEntry{beast::zero};
2555 if (view.
exists(ownerDirKeylet) &&
2556 dirFirst(view, ownerDirKeylet.
key, sleDirNode, uDirEntry, dirEntry))
2560 if (maxNodesToDelete && ++deleted > *maxNodesToDelete)
2564 auto sleItem = view.
peek(keylet::child(dirEntry));
2569 <<
"DeleteAccount: Directory node in ledger " << view.
seq()
2570 <<
" has index to object that is missing: "
2571 << to_string(dirEntry);
2576 sleItem->getFieldU16(sfLedgerEntryType))};
2580 auto const [ter, skipEntry] = deleter(nodeType, dirEntry, sleItem);
2602 "ripple::cleanupOnAccountDelete : minimum dir entries");
2606 <<
"DeleteAccount iterator re-validation failed.";
2609 if (skipEntry == SkipEntry::No)
2613 dirNext(view, ownerDirKeylet.
key, sleDirNode, uDirEntry, dirEntry));
2626 if (!sleState || sleState->getType() != ltRIPPLE_STATE)
2630 sleState->getFieldAmount(sfLowLimit).getIssuer(),
2631 sleState->getFieldAmount(sfHighLimit).getIssuer());
2632 auto sleLow = view.
peek(keylet::account(low));
2633 auto sleHigh = view.
peek(keylet::account(high));
2634 if (!sleLow || !sleHigh)
2636 bool const ammLow = sleLow->isFieldPresent(sfAMMID);
2637 bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
2640 if (ammLow && ammHigh)
2644 if (!ammLow && !ammHigh)
2648 if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
2651 if (
auto const ter =
trustDelete(view, sleState, low, high, j);
2655 <<
"deleteAMMTrustLine: failed to delete the trustline.";
2660 if (!(sleState->getFlags() & uFlags))
2679 if constexpr (std::is_same_v<TIss, Issue>)
2682 view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j);
2688 "ripple::rippleCredit : not checking issuer");
2690 view, uSenderID, uReceiverID, saAmount, j);
2696[[nodiscard]] STAmount
2703 assets.
asset() == vault->at(sfAsset),
2704 "ripple::assetsToSharesDeposit : assets and vault match");
2705 Number assetTotal = vault->at(sfAssetsTotal);
2706 STAmount shares{vault->at(sfShareMPTID),
static_cast<Number>(assets)};
2707 if (assetTotal == 0)
2709 Number shareTotal = issuance->at(sfOutstandingAmount);
2710 shares = shareTotal * (assets / assetTotal);
2714[[nodiscard]] STAmount
2721 assets.
asset() == vault->at(sfAsset),
2722 "ripple::assetsToSharesWithdraw : assets and vault match");
2723 Number assetTotal = vault->at(sfAssetsTotal);
2724 assetTotal -= vault->at(sfLossUnrealized);
2725 STAmount shares{vault->at(sfShareMPTID)};
2726 if (assetTotal == 0)
2728 Number shareTotal = issuance->at(sfOutstandingAmount);
2729 shares = shareTotal * (assets / assetTotal);
2733[[nodiscard]] STAmount
2740 shares.
asset() == vault->at(sfShareMPTID),
2741 "ripple::sharesToAssetsWithdraw : shares and vault match");
2742 Number assetTotal = vault->at(sfAssetsTotal);
2743 assetTotal -= vault->at(sfLossUnrealized);
2744 STAmount assets{vault->at(sfAsset)};
2745 if (assetTotal == 0)
2747 Number shareTotal = issuance->at(sfOutstandingAmount);
2748 assets = assetTotal * (shares / shareTotal);
2760 auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
2761 auto sleIssuance = view.
peek(mptID);
2764 JLOG(j.
error()) <<
"rippleLockEscrowMPT: MPT issuance not found for "
2765 << mptIssue.getMptID();
2772 <<
"rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs.";
2779 auto const mptokenID = keylet::mptoken(mptID.key, sender);
2780 auto sle = view.
peek(mptokenID);
2784 <<
"rippleLockEscrowMPT: MPToken not found for " << sender;
2788 auto const amt = sle->getFieldU64(sfMPTAmount);
2789 auto const pay = amount.
mpt().
value();
2795 <<
"rippleLockEscrowMPT: insufficient MPTAmount for "
2796 << to_string(sender) <<
": " << amt <<
" < " << pay;
2800 (*sle)[sfMPTAmount] = amt - pay;
2803 uint64_t
const locked = (*sle)[~sfLockedAmount].value_or(0);
2808 <<
"rippleLockEscrowMPT: overflow on locked amount for "
2809 << to_string(sender) <<
": " << locked <<
" + " << pay;
2813 if (sle->isFieldPresent(sfLockedAmount))
2814 (*sle)[sfLockedAmount] += pay;
2816 sle->setFieldU64(sfLockedAmount, pay);
2824 uint64_t
const issuanceEscrowed =
2825 (*sleIssuance)[~sfLockedAmount].value_or(0);
2826 auto const pay = amount.
mpt().
value();
2832 JLOG(j.
error()) <<
"rippleLockEscrowMPT: overflow on issuance "
2833 "locked amount for "
2834 << mptIssue.getMptID() <<
": " << issuanceEscrowed
2839 if (sleIssuance->isFieldPresent(sfLockedAmount))
2840 (*sleIssuance)[sfLockedAmount] += pay;
2842 sleIssuance->setFieldU64(sfLockedAmount, pay);
2844 view.
update(sleIssuance);
2859 auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
2860 auto sleIssuance = view.
peek(mptID);
2863 JLOG(j.
error()) <<
"rippleUnlockEscrowMPT: MPT issuance not found for "
2864 << mptIssue.getMptID();
2870 if (!sleIssuance->isFieldPresent(sfLockedAmount))
2873 <<
"rippleUnlockEscrowMPT: no locked amount in issuance for "
2874 << mptIssue.getMptID();
2878 auto const locked = sleIssuance->getFieldU64(sfLockedAmount);
2879 auto const redeem = amount.
mpt().
value();
2886 <<
"rippleUnlockEscrowMPT: insufficient locked amount for "
2887 << mptIssue.getMptID() <<
": " << locked <<
" < " << redeem;
2891 auto const newLocked = locked - redeem;
2893 sleIssuance->makeFieldAbsent(sfLockedAmount);
2895 sleIssuance->setFieldU64(sfLockedAmount, newLocked);
2896 view.
update(sleIssuance);
2899 if (issuer != receiver)
2902 auto const mptokenID = keylet::mptoken(mptID.key, receiver);
2903 auto sle = view.
peek(mptokenID);
2907 <<
"rippleUnlockEscrowMPT: MPToken not found for " << receiver;
2911 auto current = sle->getFieldU64(sfMPTAmount);
2918 <<
"rippleUnlockEscrowMPT: overflow on MPTAmount for "
2919 << to_string(receiver) <<
": " <<
current <<
" + " << delta;
2923 (*sle)[sfMPTAmount] += delta;
2929 auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount);
2930 auto const redeem = amount.
mpt().
value();
2937 <<
"rippleUnlockEscrowMPT: insufficient outstanding amount for "
2938 << mptIssue.getMptID() <<
": " << outstanding <<
" < "
2943 sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem);
2944 view.
update(sleIssuance);
2947 if (issuer == sender)
2949 JLOG(j.
error()) <<
"rippleUnlockEscrowMPT: sender is the issuer, "
2950 "cannot unlock MPTs.";
2956 auto const mptokenID = keylet::mptoken(mptID.key, sender);
2957 auto sle = view.
peek(mptokenID);
2961 <<
"rippleUnlockEscrowMPT: MPToken not found for " << sender;
2965 if (!sle->isFieldPresent(sfLockedAmount))
2968 <<
"rippleUnlockEscrowMPT: no locked amount in MPToken for "
2969 << to_string(sender);
2973 auto const locked = sle->getFieldU64(sfLockedAmount);
2974 auto const delta = amount.
mpt().
value();
2981 <<
"rippleUnlockEscrowMPT: insufficient locked amount for "
2982 << to_string(sender) <<
": " << locked <<
" < " << delta;
2986 auto const newLocked = locked - delta;
2988 sle->makeFieldAbsent(sfLockedAmount);
2990 sle->setFieldU64(sfLockedAmount, newLocked);
Provide a light-weight way to check active() before string formatting.
A generic endpoint for log messages.
static Sink & getNullSink()
Returns a Sink which does nothing.
Stream trace() const
Severity stream access functions.
Writeable view to a ledger, for applying a transaction.
virtual void creditHook(AccountID const &from, AccountID const &to, STAmount const &amount, STAmount const &preCreditBalance)
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
virtual void adjustOwnerCountHook(AccountID const &account, std::uint32_t cur, std::uint32_t next)
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
constexpr value_type const & value() const
A currency issued by an account.
AccountID const & getIssuer() const
constexpr value_type value() const
Returns the underlying value.
constexpr MPTID const & getMptID() const
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
virtual std::uint32_t ownerCountHook(AccountID const &account, std::uint32_t count) const
virtual STAmount balanceHook(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
virtual bool open() const =0
Returns true if this reflects an open ledger.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
constexpr bool holds() const noexcept
Asset const & asset() const
constexpr TIss const & get() const
void setIssuer(AccountID const &uIssuer)
Currency const & getCurrency() const
AccountID const & getIssuer() const
Issue const & issue() const
std::string getFullText() const override
bool native() const noexcept
STAmount zeroed() const
Returns a zero value with the same issuer and currency.
std::shared_ptr< STLedgerEntry > const & ref
bool internalDirFirst(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
bool internalDirNext(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet const & amendments() noexcept
The index of the amendment table.
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet const & skip() noexcept
The index of the "short" skip list.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TER rippleLockEscrowMPT(ApplyView &view, AccountID const &sender, STAmount const &amount, beast::Journal j)
AccountID const & noAccount()
A placeholder for empty accounts.
Expected< std::shared_ptr< SLE >, TER > createPseudoAccount(ApplyView &view, uint256 const &pseudoOwnerKey, SField const &ownerField)
Create pseudo-account, storing pseudoOwnerKey into ownerField.
static bool updateTrustLine(ApplyView &view, SLE::pointer state, bool bSenderHigh, AccountID const &sender, STAmount const &before, STAmount const &after, beast::Journal j)
std::uint8_t constexpr maxAssetCheckDepth
Maximum recursion depth for vault shares being put as an asset inside another vault; counted from 0.
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType)
Check if the account lacks required authorization.
FreezeHandling
Controls the treatment of frozen account balances.
bool cdirFirst(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the first entry in the directory, advancing the index.
bool isXRP(AccountID const &c)
AccountID const & xrpAccount()
Compute AccountID from public key.
STAmount sharesToAssetsWithdraw(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &shares)
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
static TER rippleSendMPT(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j, WaiveTransferFee waiveFee)
bool dirFirst(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
bool dirNext(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
std::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
STAmount multiply(STAmount const &amount, Rate const &rate)
AuthHandling
Controls the treatment of unauthorized MPT balances.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
TER enforceMPTokenAuthorization(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, XRPAmount const &priorBalance, beast::Journal j)
Enforce account has MPToken to match its authorization.
static std::array< SField const *, 2 > const pseudoAccountOwnerFields
@ current
This was a new validation and was added.
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
@ expired
List is expired, but has the largest non-pending sequence seen so far.
std::set< uint256 > getEnabledAmendments(ReadView const &view)
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
TER rippleUnlockEscrowMPT(ApplyView &view, AccountID const &sender, AccountID const &receiver, STAmount const &amount, beast::Journal j)
static std::uint32_t confineOwnerCount(std::uint32_t current, std::int32_t adjustment, std::optional< AccountID > const &id=std::nullopt, beast::Journal j=beast::Journal{beast::Journal::getNullSink()})
static TER rippleCreditIOU(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
static bool adjustOwnerCount(ApplyContext &ctx, int count)
constexpr std::uint32_t const tfMPTUnauthorize
bool isVaultPseudoAccountFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptShare, int depth)
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
static TER accountSendIOU(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
std::map< uint256, NetClock::time_point > majorityAmendments_t
bool cdirNext(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the next entry in the directory, advancing the index.
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
TER addEmptyHolding(ApplyView &view, AccountID const &accountID, XRPAmount priorBalance, Issue const &issue, beast::Journal journal)
AccountID pseudoAccountAddress(ReadView const &view, uint256 const &pseudoOwnerKey)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
bool isLPTokenFrozen(ReadView const &view, AccountID const &account, Issue const &asset, Issue const &asset2)
bool isTesSuccess(TER x) noexcept
majorityAmendments_t getMajorityAmendments(ReadView const &view)
std::string to_string(base_uint< Bits, Tag > const &a)
LedgerEntryType
Identifiers for on-ledger objects.
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
STAmount assetsToSharesWithdraw(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &assets)
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Number root(Number f, unsigned d)
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
STAmount assetsToSharesDeposit(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &assets)
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
static TER rippleSendIOU(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j, WaiveTransferFee waiveFee)
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
bool isAnyFrozen(ReadView const &view, std::initializer_list< AccountID > const &accounts, MPTIssue const &mptIssue, int depth)
TERSubset< CanCvtToTER > TER
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, Issue const &issue, beast::Journal journal)
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, char const *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
static TER rippleCreditMPT(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j)
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
static TER accountSendMPT(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
TER dirLink(ApplyView &view, AccountID const &owner, std::shared_ptr< SLE > &object)
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
A pair of SHAMap key and LedgerEntryType.
Represents a transfer rate.
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
T time_since_epoch(T... args)