xrpld
Loading...
Searching...
No Matches
EscrowCreate.cpp
1#include <xrpl/tx/transactors/escrow/EscrowCreate.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/chrono.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/conditions/Condition.h>
7#include <xrpl/core/ServiceRegistry.h>
8#include <xrpl/ledger/ApplyView.h>
9#include <xrpl/ledger/View.h>
10#include <xrpl/ledger/helpers/AccountRootHelpers.h>
11#include <xrpl/ledger/helpers/DirectoryHelpers.h>
12#include <xrpl/ledger/helpers/MPTokenHelpers.h>
13#include <xrpl/ledger/helpers/RippleStateHelpers.h>
14#include <xrpl/ledger/helpers/SponsorHelpers.h>
15#include <xrpl/ledger/helpers/TokenHelpers.h>
16#include <xrpl/protocol/AccountID.h>
17#include <xrpl/protocol/Concepts.h>
18#include <xrpl/protocol/Feature.h>
19#include <xrpl/protocol/Indexes.h>
20#include <xrpl/protocol/Issue.h>
21#include <xrpl/protocol/LedgerFormats.h>
22#include <xrpl/protocol/MPTAmount.h>
23#include <xrpl/protocol/MPTIssue.h>
24#include <xrpl/protocol/Protocol.h>
25#include <xrpl/protocol/Rate.h>
26#include <xrpl/protocol/SField.h>
27#include <xrpl/protocol/STAmount.h>
28#include <xrpl/protocol/STLedgerEntry.h>
29#include <xrpl/protocol/STTx.h>
30#include <xrpl/protocol/TER.h>
31#include <xrpl/protocol/UintTypes.h>
32#include <xrpl/protocol/XRPAmount.h>
33#include <xrpl/tx/Transactor.h>
34#include <xrpl/tx/applySteps.h>
35
36#include <memory>
37#include <system_error>
38#include <variant>
39
40namespace xrpl {
41
42/*
43 Escrow
44 ======
45
46 Escrow is a feature of the XRP Ledger that allows you to send conditional
47 XRP payments. These conditional payments, called escrows, set aside XRP and
48 deliver it later when certain conditions are met. Conditions to successfully
49 finish an escrow include time-based unlocks and crypto-conditions. Escrows
50 can also be set to expire if not finished in time.
51
52 The XRP set aside in an escrow is locked up. No one can use or destroy the
53 XRP until the escrow has been successfully finished or canceled. Before the
54 expiration time, only the intended receiver can get the XRP. After the
55 expiration time, the XRP can only be returned to the sender.
56
57 For more details on escrow, including examples, diagrams and more please
58 visit https://xrpl.org/escrow.html
59
60 For details on specific transactions, including fields and validation rules
61 please see:
62
63 `EscrowCreate`
64 --------------
65 See: https://xrpl.org/escrowcreate.html
66
67 `EscrowFinish`
68 --------------
69 See: https://xrpl.org/escrowfinish.html
70
71 `EscrowCancel`
72 --------------
73 See: https://xrpl.org/escrowcancel.html
74*/
75
76//------------------------------------------------------------------------------
77
80{
81 auto const amount = ctx.tx[sfAmount];
82 return TxConsequences{ctx.tx, isXRP(amount) ? amount.xrp() : beast::kZero};
83}
84
85bool
87{
88 // Only require featureMPTokensV1 when the escrow amount is an MPT and
89 // fixCleanup3_2_0 is active; XRP/IOU escrows are unaffected by this gate.
90 if (ctx.rules.enabled(fixCleanup3_2_0) && ctx.tx[sfAmount].holds<MPTIssue>())
91 return ctx.rules.enabled(featureMPTokensV1);
92 return true;
93}
94
95template <ValidIssueType T>
96static NotTEC
98
99template <>
102{
103 STAmount const amount = ctx.tx[sfAmount];
104 if (amount.native() || amount <= beast::kZero)
105 return temBAD_AMOUNT;
106
107 if (badCurrency() == amount.get<Issue>().currency)
108 return temBAD_CURRENCY;
109
110 return tesSUCCESS;
111}
112
113template <>
116{
117 if (!ctx.rules.enabled(fixCleanup3_2_0) && !ctx.rules.enabled(featureMPTokensV1))
118 return temDISABLED;
119
120 auto const amount = ctx.tx[sfAmount];
121 if (amount.native() || amount.mpt() > MPTAmount{kMaxMpTokenAmount} || amount <= beast::kZero)
122 return temBAD_AMOUNT;
123
124 return tesSUCCESS;
125}
126
127NotTEC
129{
130 STAmount const amount{ctx.tx[sfAmount]};
131 if (!isXRP(amount))
132 {
133 if (!ctx.rules.enabled(featureTokenEscrow))
134 return temBAD_AMOUNT;
135
136 if (auto const ret = std::visit(
137 [&]<typename T>(T const&) { return escrowCreatePreflightHelper<T>(ctx); },
138 amount.asset().value());
139 !isTesSuccess(ret))
140 return ret;
141 }
142 else
143 {
144 if (amount <= beast::kZero)
145 return temBAD_AMOUNT;
146 }
147
148 // We must specify at least one timeout value
149 if (!ctx.tx[~sfCancelAfter] && !ctx.tx[~sfFinishAfter])
150 return temBAD_EXPIRATION;
151
152 // If both finish and cancel times are specified then the cancel time must
153 // be strictly after the finish time.
154 if (ctx.tx[~sfCancelAfter] && ctx.tx[~sfFinishAfter] &&
155 ctx.tx[sfCancelAfter] <= ctx.tx[sfFinishAfter])
156 return temBAD_EXPIRATION;
157
158 // In the absence of a FinishAfter, the escrow can be finished
159 // immediately, which can be confusing. When creating an escrow,
160 // we want to ensure that either a FinishAfter time is explicitly
161 // specified or a completion condition is attached.
162 if (!ctx.tx[~sfFinishAfter] && !ctx.tx[~sfCondition])
163 return temMALFORMED;
164
165 if (auto const cb = ctx.tx[~sfCondition])
166 {
167 using namespace xrpl::cryptoconditions;
168
170
171 auto condition = Condition::deserialize(*cb, ec);
172 if (!condition)
173 {
174 JLOG(ctx.j.debug()) << "Malformed condition during escrow creation: " << ec.message();
175 return temMALFORMED;
176 }
177 }
178
179 return tesSUCCESS;
180}
181
182template <ValidIssueType T>
183static TER
185 PreclaimContext const& ctx,
186 AccountID const& account,
187 AccountID const& dest,
188 STAmount const& amount);
189
190template <>
193 PreclaimContext const& ctx,
194 AccountID const& account,
195 AccountID const& dest,
196 STAmount const& amount)
197{
198 auto const& issue = amount.get<Issue>();
199 AccountID const& issuer = amount.getIssuer();
200 // If the issuer is the same as the account, return tecNO_PERMISSION
201 if (issuer == account)
202 return tecNO_PERMISSION;
203
204 // If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
205 auto const sleIssuer = ctx.view.read(keylet::account(issuer));
206 if (!sleIssuer)
207 return tecNO_ISSUER;
208 if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
209 return tecNO_PERMISSION;
210
211 // If the account does not have a trustline to the issuer, return tecNO_LINE
212 auto const sleRippleState = ctx.view.read(keylet::trustLine(account, issuer, issue.currency));
213 if (!sleRippleState)
214 return tecNO_LINE;
215
216 STAmount const balance = (*sleRippleState)[sfBalance];
217
218 // If balance is positive, issuer must have higher address than account
219 if (balance > beast::kZero && issuer < account)
220 return tecNO_PERMISSION; // LCOV_EXCL_LINE
221
222 // If balance is negative, issuer must have lower address than account
223 if (balance < beast::kZero && issuer > account)
224 return tecNO_PERMISSION; // LCOV_EXCL_LINE
225
226 // If the issuer has requireAuth set, check if the account is authorized
227 if (auto const ter = requireAuth(ctx.view, issue, account); !isTesSuccess(ter))
228 return ter;
229
230 // If the issuer has requireAuth set, check if the destination is authorized
231 if (auto const ter = requireAuth(ctx.view, issue, dest); !isTesSuccess(ter))
232 return ter;
233
234 // If the issuer has frozen the account, return tecFROZEN
235 if (isFrozen(ctx.view, account, issue))
236 return tecFROZEN;
237
238 // If the issuer has frozen the destination, return tecFROZEN
239 if (isFrozen(ctx.view, dest, issue))
240 return tecFROZEN;
241
242 STAmount const spendableAmount = accountHolds(
243 ctx.view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, ctx.j);
244
245 // If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
246 if (spendableAmount <= beast::kZero)
248
249 // If the spendable amount is less than the amount, return
250 // tecINSUFFICIENT_FUNDS
251 if (spendableAmount < amount)
253
254 // If the amount is not addable to the balance, return tecPRECISION_LOSS
255 if (!canAdd(spendableAmount, amount))
256 return tecPRECISION_LOSS;
257
258 return tesSUCCESS;
259}
260
261template <>
264 PreclaimContext const& ctx,
265 AccountID const& account,
266 AccountID const& dest,
267 STAmount const& amount)
268{
269 AccountID const issuer = amount.getIssuer();
270 // If the issuer is the same as the account, return tecNO_PERMISSION
271 if (issuer == account)
272 return tecNO_PERMISSION;
273
274 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
275 auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
276 auto const sleIssuance = ctx.view.read(issuanceKey);
277 if (!sleIssuance)
278 return tecOBJECT_NOT_FOUND;
279
280 // If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
281 if (!sleIssuance->isFlag(lsfMPTCanEscrow))
282 return tecNO_PERMISSION;
283
284 // If the issuer is not the same as the issuer of the mpt, return
285 // tecNO_PERMISSION
286 if (sleIssuance->getAccountID(sfIssuer) != issuer)
287 return tecNO_PERMISSION; // LCOV_EXCL_LINE
288
289 // If the account does not have the mpt, return tecOBJECT_NOT_FOUND
290 if (!ctx.view.exists(keylet::mptoken(issuanceKey.key, account)))
291 return tecOBJECT_NOT_FOUND;
292
293 // If the issuer has requireAuth set, check if the account is
294 // authorized
295 auto const& mptIssue = amount.get<MPTIssue>();
296 if (auto const ter = requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth);
297 !isTesSuccess(ter))
298 return ter;
299
300 // If the issuer has requireAuth set, check if the destination is
301 // authorized
302 if (auto const ter = requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth);
303 !isTesSuccess(ter))
304 return ter;
305
306 // If the issuer has frozen the account, return tecLOCKED
307 if (isFrozen(ctx.view, account, mptIssue))
308 return tecLOCKED;
309
310 // If the issuer has frozen the destination, return tecLOCKED
311 if (isFrozen(ctx.view, dest, mptIssue))
312 return tecLOCKED;
313
314 // If the mpt cannot be transferred, return tecNO_AUTH
315 if (auto const ter = canTransfer(ctx.view, mptIssue, account, dest); !isTesSuccess(ter))
316 return ter;
317
318 STAmount const spendableAmount = accountHolds(
319 ctx.view,
320 account,
321 amount.get<MPTIssue>(),
324 ctx.j);
325
326 // If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
327 if (spendableAmount <= beast::kZero)
329
330 // If the spendable amount is less than the amount, return
331 // tecINSUFFICIENT_FUNDS
332 if (spendableAmount < amount)
334
335 return tesSUCCESS;
336}
337
338TER
340{
341 STAmount const amount{ctx.tx[sfAmount]};
342 AccountID const account{ctx.tx[sfAccount]};
343 AccountID const dest{ctx.tx[sfDestination]};
344
345 auto const sled = ctx.view.read(keylet::account(dest));
346 if (!sled)
347 return tecNO_DST;
348
349 // Pseudo-accounts cannot receive escrow. Note, this is not amendment-gated
350 // because all writes to pseudo-account discriminator fields **are**
351 // amendment gated, hence the behaviour of this check will always match the
352 // currently active amendments.
353 if (isPseudoAccount(sled))
354 return tecNO_PERMISSION;
355
356 if (!isXRP(amount))
357 {
358 if (!ctx.view.rules().enabled(featureTokenEscrow))
359 return temDISABLED; // LCOV_EXCL_LINE
360
361 if (auto const ret = std::visit(
362 [&]<typename T>(T const&) {
363 return escrowCreatePreclaimHelper<T>(ctx, account, dest, amount);
364 },
365 amount.asset().value());
366 !isTesSuccess(ret))
367 return ret;
368 }
369 return tesSUCCESS;
370}
371
372template <ValidIssueType T>
373static TER
375 ApplyView& view,
376 AccountID const& issuer,
377 AccountID const& sender,
378 STAmount const& amount,
379 beast::Journal journal);
380
381template <>
384 ApplyView& view,
385 AccountID const& issuer,
386 AccountID const& sender,
387 STAmount const& amount,
388 beast::Journal journal)
389{
390 // Defensive: Issuer cannot create an escrow
391 if (issuer == sender)
392 return tecINTERNAL; // LCOV_EXCL_LINE
393
394 auto const ter =
395 directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
396 if (!isTesSuccess(ter))
397 return ter; // LCOV_EXCL_LINE
398 return tesSUCCESS;
399}
400
401template <>
404 ApplyView& view,
405 AccountID const& issuer,
406 AccountID const& sender,
407 STAmount const& amount,
408 beast::Journal journal)
409{
410 // Defensive: Issuer cannot create an escrow
411 if (issuer == sender)
412 return tecINTERNAL; // LCOV_EXCL_LINE
413
414 auto const ter = lockEscrowMPT(view, sender, amount, journal);
415 if (!isTesSuccess(ter))
416 return ter; // LCOV_EXCL_LINE
417 return tesSUCCESS;
418}
419
420TER
422{
423 auto const closeTime = ctx_.view().header().parentCloseTime;
424
425 if (ctx_.tx[~sfCancelAfter] && after(closeTime, ctx_.tx[sfCancelAfter]))
426 return tecNO_PERMISSION;
427
428 if (ctx_.tx[~sfFinishAfter] && after(closeTime, ctx_.tx[sfFinishAfter]))
429 return tecNO_PERMISSION;
430
431 auto const sle = ctx_.view().peek(keylet::account(accountID_));
432 if (!sle)
433 return tefINTERNAL; // LCOV_EXCL_LINE
434
435 // Check reserve and funds availability
436 STAmount const amount{ctx_.tx[sfAmount]};
437
438 auto const balance = sle->getFieldAmount(sfBalance).xrp();
439 // First check: whoever is on the hook for the new owner increment
440 // can cover it. When sponsored this hits the sponsor branch and
441 // validates the sponsor's reserve + remaining credit. When
442 // unsponsored this hits the source branch and validates the
443 // source's pre-lock balance against base + (currentOC+1)*increment.
444 if (auto const ret =
445 checkReserve(ctx_.getApplyViewContext(), sle, balance, {.ownerCountDelta = 1}, j_);
446 !isTesSuccess(ret))
447 return ret;
448
449 if (isXRP(amount))
450 {
451 // Second check (XRP escrow only): after locking the escrowed
452 // amount, the source must still meet its own reserve floor. This is
453 // always the source's own balance against the source's own reserve —
454 // the sponsor's reserve was already validated above, and a sponsor
455 // never covers the locked funds. We compare directly (rather than via
456 // checkReserve) because that helper diverts to the sponsor's balance
457 // when a sponsor is present and would ignore the source's post-lock
458 // balance entirely. ownerCountDelta differs by case:
459 // - sponsored: 0 — sponsor covers the new owner increment, so the
460 // source only owes reserve for its current owners.
461 // - unsponsored: 1 — source owes reserve including the new increment.
462 auto const sourceReserve = accountReserve(
463 ctx_.view(), sle, j_, {.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1});
464 if (balance - STAmount(amount).xrp() < sourceReserve)
465 return tecUNFUNDED;
466 }
467
468 // Check destination account
469 {
470 auto const sled = ctx_.view().read(keylet::account(ctx_.tx[sfDestination]));
471 if (!sled)
472 return tecNO_DST; // LCOV_EXCL_LINE
473 if (sled->isFlag(lsfRequireDestTag) && !ctx_.tx[~sfDestinationTag])
474 return tecDST_TAG_NEEDED;
475 }
476
477 // Create escrow in ledger. Note that we use the value from the
478 // sequence or ticket. For more explanation see comments in SeqProxy.h.
479 Keylet const escrowKeylet = keylet::escrow(accountID_, ctx_.tx.getSeqProxy());
480 auto const slep = std::make_shared<SLE>(escrowKeylet);
481 (*slep)[sfAmount] = amount;
482 (*slep)[sfAccount] = accountID_;
483 (*slep)[~sfCondition] = ctx_.tx[~sfCondition];
484 (*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
485 (*slep)[sfDestination] = ctx_.tx[sfDestination];
486 (*slep)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter];
487 (*slep)[~sfFinishAfter] = ctx_.tx[~sfFinishAfter];
488 (*slep)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag];
489
490 if (ctx_.view().rules().enabled(fixIncludeKeyletFields))
491 {
492 (*slep)[sfSequence] = ctx_.tx.getSeqProxy().value();
493 }
494
495 if (ctx_.view().rules().enabled(featureTokenEscrow) && !isXRP(amount))
496 {
497 auto const xferRate = transferRate(ctx_.view(), amount);
498 if (xferRate != kParityRate)
499 (*slep)[sfTransferRate] = xferRate.value;
500 }
501
502 ctx_.view().insert(slep);
503
504 // Add escrow to sender's owner directory
505 {
506 auto page = ctx_.view().dirInsert(
508 if (!page)
509 return tecDIR_FULL; // LCOV_EXCL_LINE
510 (*slep)[sfOwnerNode] = *page;
511 }
512
513 // If it's not a self-send, add escrow to recipient's owner directory.
514 AccountID const dest = ctx_.tx[sfDestination];
515 if (dest != accountID_)
516 {
517 auto page =
518 ctx_.view().dirInsert(keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest));
519 if (!page)
520 return tecDIR_FULL; // LCOV_EXCL_LINE
521 (*slep)[sfDestinationNode] = *page;
522 }
523
524 // IOU escrow objects are added to the issuer's owner directory to help
525 // track the total locked balance. For MPT, this isn't necessary because the
526 // locked balance is already stored directly in the MPTokenIssuance object.
527 AccountID const issuer = amount.getIssuer();
528 if (!isXRP(amount) && issuer != accountID_ && issuer != dest && !amount.holds<MPTIssue>())
529 {
530 auto page =
531 ctx_.view().dirInsert(keylet::ownerDir(issuer), escrowKeylet, describeOwnerDir(issuer));
532 if (!page)
533 return tecDIR_FULL; // LCOV_EXCL_LINE
534 (*slep)[sfIssuerNode] = *page;
535 }
536
537 // Deduct owner's balance
538 if (isXRP(amount))
539 {
540 (*sle)[sfBalance] = (*sle)[sfBalance] - amount;
541 }
542 else
543 {
544 if (auto const ret = std::visit(
545 [&]<typename T>(T const&) {
546 return escrowLockApplyHelper<T>(ctx_.view(), issuer, accountID_, amount, j_);
547 },
548 amount.asset().value());
549 !isTesSuccess(ret))
550 {
551 return ret; // LCOV_EXCL_LINE
552 }
553 }
554
555 // increment owner count
556 increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, ctx_.journal);
557 addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep);
558 ctx_.view().update(sle);
559 return tesSUCCESS;
560}
561
562void
564{
565 // No transaction-specific invariants yet (future work).
566}
567
568bool
570 STTx const&,
571 TER,
572 XRPAmount,
573 ReadView const&,
574 beast::Journal const&)
575{
576 // No transaction-specific invariants yet (future work).
577 return true;
578}
579} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream debug() const
Definition Journal.h:344
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:134
static bool checkExtraFeatures(PreflightContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
TER doApply() override
static TER preclaim(PreclaimContext const &ctx)
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
A currency issued by an account.
Definition Issue.h:18
Currency currency
Definition Issue.h:20
constexpr MPTID const & getMptID() const
Definition MPTIssue.h:43
A view into a ledger.
Definition ReadView.h:41
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:180
constexpr bool holds() const noexcept
Definition STAmount.h:478
constexpr TIss const & get() const
bool native() const noexcept
Definition STAmount.h:471
Asset const & asset() const
Definition STAmount.h:496
AccountID const & getIssuer() const
Definition STAmount.h:516
XRPAmount xrp() const
Definition STAmount.cpp:271
std::shared_ptr< STLedgerEntry const > const & const_ref
beast::Journal const j_
Definition Transactor.h:155
AccountID const accountID_
Definition Transactor.h:157
ApplyContext & ctx_
Definition Transactor.h:153
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:52
static std::unique_ptr< Condition > deserialize(Slice s, std::error_code &ec)
Load a condition from its binary form.
T make_shared(T... args)
T message(T... args)
constexpr Zero kZero
Definition Zero.h:30
Keylet escrow(AccountID const &src, SeqProxy const &seq) noexcept
An escrow entry.
Definition Indexes.cpp:388
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:373
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:543
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Definition Indexes.cpp:537
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:253
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool isXRP(AccountID const &c)
Definition AccountID.h:84
void increaseOwnerCount(ApplyView &view, SLE::ref accountSle, SLE::ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
NotTEC escrowCreatePreflightHelper< Issue >(PreflightContext const &ctx)
@ tefINTERNAL
Definition TER.h:165
TER lockEscrowMPT(ApplyView &view, AccountID const &uGrantorID, STAmount const &saAmount, beast::Journal j)
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to, WaiveMPTCanTransfer waive=WaiveMPTCanTransfer::No, std::uint8_t depth=0)
Check whether to may receive the given MPT from from.
TER escrowCreatePreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
void addSponsorToLedgerEntry(SLE::ref sle, SLE::const_ref sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
Definition STAmount.cpp:464
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:607
TER escrowLockApplyHelper< MPTIssue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:572
Rate const kParityRate
A transfer rate signifying a 1:1 exchange.
TER directSendNoFee(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static directSendNoFeeIOU if saAmount represents Issue.
static TER escrowLockApplyHelper(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, std::uint8_t depth=0)
TER escrowCreatePreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
static NotTEC escrowCreatePreflightHelper(PreflightContext const &ctx)
TER checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
@ temBAD_CURRENCY
Definition TER.h:78
@ temBAD_EXPIRATION
Definition TER.h:79
@ temMALFORMED
Definition TER.h:75
@ temDISABLED
Definition TER.h:102
@ temBAD_AMOUNT
Definition TER.h:77
bool isTesSuccess(TER x) noexcept
Definition TER.h:676
TERSubset< CanCvtToTER > TER
Definition TER.h:647
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, std::uint8_t depth=0)
Check if the account lacks required authorization for MPT.
static TER escrowCreatePreclaimHelper(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
@ tecDIR_FULL
Definition TER.h:290
@ tecLOCKED
Definition TER.h:361
@ tecOBJECT_NOT_FOUND
Definition TER.h:329
@ tecINTERNAL
Definition TER.h:313
@ tecFROZEN
Definition TER.h:306
@ tecINSUFFICIENT_FUNDS
Definition TER.h:328
@ tecNO_LINE
Definition TER.h:304
@ tecPRECISION_LOSS
Definition TER.h:366
@ tecNO_PERMISSION
Definition TER.h:308
@ tecDST_TAG_NEEDED
Definition TER.h:312
@ tecNO_ISSUER
Definition TER.h:302
@ tecNO_DST
Definition TER.h:293
@ tecUNFUNDED
Definition TER.h:298
TER escrowLockApplyHelper< Issue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
NotTEC escrowCreatePreflightHelper< MPTIssue >(PreflightContext const &ctx)
bool isPseudoAccount(SLE::const_pointer sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
XRPAmount accountReserve(ReadView const &view, SLE::const_ref sle, beast::Journal j, Adjustment adj={})
Returns the account reserve, in drops.
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
@ tesSUCCESS
Definition TER.h:245
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:83
ReadView const & view
Definition Transactor.h:86
beast::Journal const j
Definition Transactor.h:91
State information when preflighting a tx.
Definition Transactor.h:38
beast::Journal const j
Definition Transactor.h:45
T visit(T... args)