rippled
Loading...
Searching...
No Matches
Escrow.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/app/misc/HashRouter.h>
22#include <xrpld/app/tx/detail/Escrow.h>
23#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
24#include <xrpld/conditions/Condition.h>
25#include <xrpld/conditions/Fulfillment.h>
26#include <xrpld/ledger/ApplyView.h>
27#include <xrpld/ledger/View.h>
28
29#include <xrpl/basics/Log.h>
30#include <xrpl/basics/chrono.h>
31#include <xrpl/protocol/Feature.h>
32#include <xrpl/protocol/Indexes.h>
33#include <xrpl/protocol/MPTAmount.h>
34#include <xrpl/protocol/TxFlags.h>
35#include <xrpl/protocol/XRPAmount.h>
36
37namespace ripple {
38
39// During an EscrowFinish, the transaction must specify both
40// a condition and a fulfillment. We track whether that
41// fulfillment matches and validates the condition.
44
45/*
46 Escrow
47 ======
48
49 Escrow is a feature of the XRP Ledger that allows you to send conditional
50 XRP payments. These conditional payments, called escrows, set aside XRP and
51 deliver it later when certain conditions are met. Conditions to successfully
52 finish an escrow include time-based unlocks and crypto-conditions. Escrows
53 can also be set to expire if not finished in time.
54
55 The XRP set aside in an escrow is locked up. No one can use or destroy the
56 XRP until the escrow has been successfully finished or canceled. Before the
57 expiration time, only the intended receiver can get the XRP. After the
58 expiration time, the XRP can only be returned to the sender.
59
60 For more details on escrow, including examples, diagrams and more please
61 visit https://xrpl.org/escrow.html
62
63 For details on specific transactions, including fields and validation rules
64 please see:
65
66 `EscrowCreate`
67 --------------
68 See: https://xrpl.org/escrowcreate.html
69
70 `EscrowFinish`
71 --------------
72 See: https://xrpl.org/escrowfinish.html
73
74 `EscrowCancel`
75 --------------
76 See: https://xrpl.org/escrowcancel.html
77*/
78
79//------------------------------------------------------------------------------
80
83{
84 return TxConsequences{
85 ctx.tx, isXRP(ctx.tx[sfAmount]) ? ctx.tx[sfAmount].xrp() : beast::zero};
86}
87
88template <ValidIssueType T>
89static NotTEC
91
92template <>
95{
96 STAmount const amount = ctx.tx[sfAmount];
97 if (amount.native() || amount <= beast::zero)
98 return temBAD_AMOUNT;
99
100 if (badCurrency() == amount.getCurrency())
101 return temBAD_CURRENCY;
102
103 return tesSUCCESS;
104}
105
106template <>
109{
110 if (!ctx.rules.enabled(featureMPTokensV1))
111 return temDISABLED;
112
113 auto const amount = ctx.tx[sfAmount];
114 if (amount.native() || amount.mpt() > MPTAmount{maxMPTokenAmount} ||
115 amount <= beast::zero)
116 return temBAD_AMOUNT;
117
118 return tesSUCCESS;
119}
120
121NotTEC
123{
124 if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask)
125 return temINVALID_FLAG;
126
127 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
128 return ret;
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&) {
138 return escrowCreatePreflightHelper<T>(ctx);
139 },
140 amount.asset().value());
141 !isTesSuccess(ret))
142 return ret;
143 }
144 else
145 {
146 if (amount <= beast::zero)
147 return temBAD_AMOUNT;
148 }
149
150 // We must specify at least one timeout value
151 if (!ctx.tx[~sfCancelAfter] && !ctx.tx[~sfFinishAfter])
152 return temBAD_EXPIRATION;
153
154 // If both finish and cancel times are specified then the cancel time must
155 // be strictly after the finish time.
156 if (ctx.tx[~sfCancelAfter] && ctx.tx[~sfFinishAfter] &&
157 ctx.tx[sfCancelAfter] <= ctx.tx[sfFinishAfter])
158 return temBAD_EXPIRATION;
159
160 if (ctx.rules.enabled(fix1571))
161 {
162 // In the absence of a FinishAfter, the escrow can be finished
163 // immediately, which can be confusing. When creating an escrow,
164 // we want to ensure that either a FinishAfter time is explicitly
165 // specified or a completion condition is attached.
166 if (!ctx.tx[~sfFinishAfter] && !ctx.tx[~sfCondition])
167 return temMALFORMED;
168 }
169
170 if (auto const cb = ctx.tx[~sfCondition])
171 {
172 using namespace ripple::cryptoconditions;
173
175
176 auto condition = Condition::deserialize(*cb, ec);
177 if (!condition)
178 {
179 JLOG(ctx.j.debug())
180 << "Malformed condition during escrow creation: "
181 << ec.message();
182 return temMALFORMED;
183 }
184
185 // Conditions other than PrefixSha256 require the
186 // "CryptoConditionsSuite" amendment:
187 if (condition->type != Type::preimageSha256 &&
188 !ctx.rules.enabled(featureCryptoConditionsSuite))
189 return temDISABLED;
190 }
191
192 return preflight2(ctx);
193}
194
195template <ValidIssueType T>
196static TER
198 PreclaimContext const& ctx,
199 AccountID const& account,
200 AccountID const& dest,
201 STAmount const& amount);
202
203template <>
206 PreclaimContext const& ctx,
207 AccountID const& account,
208 AccountID const& dest,
209 STAmount const& amount)
210{
211 AccountID issuer = amount.getIssuer();
212 // If the issuer is the same as the account, return tecNO_PERMISSION
213 if (issuer == account)
214 return tecNO_PERMISSION;
215
216 // If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
217 auto const sleIssuer = ctx.view.read(keylet::account(issuer));
218 if (!sleIssuer)
219 return tecNO_ISSUER;
220 if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
221 return tecNO_PERMISSION;
222
223 // If the account does not have a trustline to the issuer, return tecNO_LINE
224 auto const sleRippleState =
225 ctx.view.read(keylet::line(account, issuer, amount.getCurrency()));
226 if (!sleRippleState)
227 return tecNO_LINE;
228
229 STAmount const balance = (*sleRippleState)[sfBalance];
230
231 // If balance is positive, issuer must have higher address than account
232 if (balance > beast::zero && issuer < account)
233 return tecNO_PERMISSION; // LCOV_EXCL_LINE
234
235 // If balance is negative, issuer must have lower address than account
236 if (balance < beast::zero && issuer > account)
237 return tecNO_PERMISSION; // LCOV_EXCL_LINE
238
239 // If the issuer has requireAuth set, check if the account is authorized
240 if (auto const ter = requireAuth(ctx.view, amount.issue(), account);
241 ter != tesSUCCESS)
242 return ter;
243
244 // If the issuer has requireAuth set, check if the destination is authorized
245 if (auto const ter = requireAuth(ctx.view, amount.issue(), dest);
246 ter != tesSUCCESS)
247 return ter;
248
249 // If the issuer has frozen the account, return tecFROZEN
250 if (isFrozen(ctx.view, account, amount.issue()))
251 return tecFROZEN;
252
253 // If the issuer has frozen the destination, return tecFROZEN
254 if (isFrozen(ctx.view, dest, amount.issue()))
255 return tecFROZEN;
256
257 STAmount const spendableAmount = accountHolds(
258 ctx.view,
259 account,
260 amount.getCurrency(),
261 issuer,
263 ctx.j);
264
265 // If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
266 if (spendableAmount <= beast::zero)
268
269 // If the spendable amount is less than the amount, return
270 // tecINSUFFICIENT_FUNDS
271 if (spendableAmount < amount)
273
274 // If the amount is not addable to the balance, return tecPRECISION_LOSS
275 if (!canAdd(spendableAmount, amount))
276 return tecPRECISION_LOSS;
277
278 return tesSUCCESS;
279}
280
281template <>
284 PreclaimContext const& ctx,
285 AccountID const& account,
286 AccountID const& dest,
287 STAmount const& amount)
288{
289 AccountID issuer = amount.getIssuer();
290 // If the issuer is the same as the account, return tecNO_PERMISSION
291 if (issuer == account)
292 return tecNO_PERMISSION;
293
294 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
295 auto const issuanceKey =
297 auto const sleIssuance = ctx.view.read(issuanceKey);
298 if (!sleIssuance)
299 return tecOBJECT_NOT_FOUND;
300
301 // If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
302 if (!sleIssuance->isFlag(lsfMPTCanEscrow))
303 return tecNO_PERMISSION;
304
305 // If the issuer is not the same as the issuer of the mpt, return
306 // tecNO_PERMISSION
307 if (sleIssuance->getAccountID(sfIssuer) != issuer)
308 return tecNO_PERMISSION; // LCOV_EXCL_LINE
309
310 // If the account does not have the mpt, return tecOBJECT_NOT_FOUND
311 if (!ctx.view.exists(keylet::mptoken(issuanceKey.key, account)))
312 return tecOBJECT_NOT_FOUND;
313
314 // If the issuer has requireAuth set, check if the account is
315 // authorized
316 auto const& mptIssue = amount.get<MPTIssue>();
317 if (auto const ter =
318 requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth);
319 ter != tesSUCCESS)
320 return ter;
321
322 // If the issuer has requireAuth set, check if the destination is
323 // authorized
324 if (auto const ter =
325 requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth);
326 ter != tesSUCCESS)
327 return ter;
328
329 // If the issuer has frozen the account, return tecLOCKED
330 if (isFrozen(ctx.view, account, mptIssue))
331 return tecLOCKED;
332
333 // If the issuer has frozen the destination, return tecLOCKED
334 if (isFrozen(ctx.view, dest, mptIssue))
335 return tecLOCKED;
336
337 // If the mpt cannot be transferred, return tecNO_AUTH
338 if (auto const ter = canTransfer(ctx.view, mptIssue, account, dest);
339 ter != tesSUCCESS)
340 return ter;
341
342 STAmount const spendableAmount = accountHolds(
343 ctx.view,
344 account,
345 amount.get<MPTIssue>(),
348 ctx.j);
349
350 // If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
351 if (spendableAmount <= beast::zero)
353
354 // If the spendable amount is less than the amount, return
355 // tecINSUFFICIENT_FUNDS
356 if (spendableAmount < amount)
358
359 return tesSUCCESS;
360}
361
362TER
364{
365 STAmount const amount{ctx.tx[sfAmount]};
366 AccountID const account{ctx.tx[sfAccount]};
367 AccountID const dest{ctx.tx[sfDestination]};
368
369 auto const sled = ctx.view.read(keylet::account(dest));
370 if (!sled)
371 return tecNO_DST;
372
373 // Pseudo-accounts cannot receive escrow. Note, this is not amendment-gated
374 // because all writes to pseudo-account discriminator fields **are**
375 // amendment gated, hence the behaviour of this check will always match the
376 // currently active amendments.
377 if (isPseudoAccount(sled))
378 return tecNO_PERMISSION;
379
380 if (!isXRP(amount))
381 {
382 if (!ctx.view.rules().enabled(featureTokenEscrow))
383 return temDISABLED; // LCOV_EXCL_LINE
384
385 if (auto const ret = std::visit(
386 [&]<typename T>(T const&) {
387 return escrowCreatePreclaimHelper<T>(
388 ctx, account, dest, amount);
389 },
390 amount.asset().value());
391 !isTesSuccess(ret))
392 return ret;
393 }
394 return tesSUCCESS;
395}
396
397template <ValidIssueType T>
398static TER
400 ApplyView& view,
401 AccountID const& issuer,
402 AccountID const& sender,
403 STAmount const& amount,
404 beast::Journal journal);
405
406template <>
409 ApplyView& view,
410 AccountID const& issuer,
411 AccountID const& sender,
412 STAmount const& amount,
413 beast::Journal journal)
414{
415 // Defensive: Issuer cannot create an escrow
416 // LCOV_EXCL_START
417 if (issuer == sender)
418 return tecINTERNAL;
419 // LCOV_EXCL_STOP
420
421 auto const ter = rippleCredit(
422 view,
423 sender,
424 issuer,
425 amount,
426 amount.holds<MPTIssue>() ? false : true,
427 journal);
428 if (ter != tesSUCCESS)
429 return ter; // LCOV_EXCL_LINE
430 return tesSUCCESS;
431}
432
433template <>
436 ApplyView& view,
437 AccountID const& issuer,
438 AccountID const& sender,
439 STAmount const& amount,
440 beast::Journal journal)
441{
442 // Defensive: Issuer cannot create an escrow
443 // LCOV_EXCL_START
444 if (issuer == sender)
445 return tecINTERNAL;
446 // LCOV_EXCL_STOP
447
448 auto const ter = rippleLockEscrowMPT(view, sender, amount, journal);
449 if (ter != tesSUCCESS)
450 return ter; // LCOV_EXCL_LINE
451 return tesSUCCESS;
452}
453
454TER
456{
457 auto const closeTime = ctx_.view().info().parentCloseTime;
458
459 // Prior to fix1571, the cancel and finish times could be greater
460 // than or equal to the parent ledgers' close time.
461 //
462 // With fix1571, we require that they both be strictly greater
463 // than the parent ledgers' close time.
464 if (ctx_.view().rules().enabled(fix1571))
465 {
466 if (ctx_.tx[~sfCancelAfter] && after(closeTime, ctx_.tx[sfCancelAfter]))
467 return tecNO_PERMISSION;
468
469 if (ctx_.tx[~sfFinishAfter] && after(closeTime, ctx_.tx[sfFinishAfter]))
470 return tecNO_PERMISSION;
471 }
472 else
473 {
474 if (ctx_.tx[~sfCancelAfter])
475 {
476 auto const cancelAfter = ctx_.tx[sfCancelAfter];
477
478 if (closeTime.time_since_epoch().count() >= cancelAfter)
479 return tecNO_PERMISSION;
480 }
481
482 if (ctx_.tx[~sfFinishAfter])
483 {
484 auto const finishAfter = ctx_.tx[sfFinishAfter];
485
486 if (closeTime.time_since_epoch().count() >= finishAfter)
487 return tecNO_PERMISSION;
488 }
489 }
490
491 auto const sle = ctx_.view().peek(keylet::account(account_));
492 if (!sle)
493 return tefINTERNAL; // LCOV_EXCL_LINE
494
495 // Check reserve and funds availability
496 STAmount const amount{ctx_.tx[sfAmount]};
497
498 auto const reserve =
499 ctx_.view().fees().accountReserve((*sle)[sfOwnerCount] + 1);
500
501 if (mSourceBalance < reserve)
503
504 // Check reserve and funds availability
505 if (isXRP(amount))
506 {
507 if (mSourceBalance < reserve + STAmount(amount).xrp())
508 return tecUNFUNDED;
509 }
510
511 // Check destination account
512 {
513 auto const sled =
514 ctx_.view().read(keylet::account(ctx_.tx[sfDestination]));
515 if (!sled)
516 return tecNO_DST;
517 if (((*sled)[sfFlags] & lsfRequireDestTag) &&
518 !ctx_.tx[~sfDestinationTag])
519 return tecDST_TAG_NEEDED;
520
521 // Obeying the lsfDissalowXRP flag was a bug. Piggyback on
522 // featureDepositAuth to remove the bug.
523 if (!ctx_.view().rules().enabled(featureDepositAuth) &&
524 ((*sled)[sfFlags] & lsfDisallowXRP))
525 return tecNO_TARGET;
526 }
527
528 // Create escrow in ledger. Note that we we use the value from the
529 // sequence or ticket. For more explanation see comments in SeqProxy.h.
530 Keylet const escrowKeylet = keylet::escrow(account_, ctx_.tx.getSeqValue());
531 auto const slep = std::make_shared<SLE>(escrowKeylet);
532 (*slep)[sfAmount] = amount;
533 (*slep)[sfAccount] = account_;
534 (*slep)[~sfCondition] = ctx_.tx[~sfCondition];
535 (*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
536 (*slep)[sfDestination] = ctx_.tx[sfDestination];
537 (*slep)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter];
538 (*slep)[~sfFinishAfter] = ctx_.tx[~sfFinishAfter];
539 (*slep)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag];
540
541 if (ctx_.view().rules().enabled(featureTokenEscrow) && !isXRP(amount))
542 {
543 auto const xferRate = transferRate(ctx_.view(), amount);
544 if (xferRate != parityRate)
545 (*slep)[sfTransferRate] = xferRate.value;
546 }
547
548 ctx_.view().insert(slep);
549
550 // Add escrow to sender's owner directory
551 {
552 auto page = ctx_.view().dirInsert(
554 escrowKeylet,
556 if (!page)
557 return tecDIR_FULL; // LCOV_EXCL_LINE
558 (*slep)[sfOwnerNode] = *page;
559 }
560
561 // If it's not a self-send, add escrow to recipient's owner directory.
562 AccountID const dest = ctx_.tx[sfDestination];
563 if (dest != account_)
564 {
565 auto page = ctx_.view().dirInsert(
566 keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest));
567 if (!page)
568 return tecDIR_FULL; // LCOV_EXCL_LINE
569 (*slep)[sfDestinationNode] = *page;
570 }
571
572 // IOU escrow objects are added to the issuer's owner directory to help
573 // track the total locked balance. For MPT, this isn't necessary because the
574 // locked balance is already stored directly in the MPTokenIssuance object.
575 AccountID const issuer = amount.getIssuer();
576 if (!isXRP(amount) && issuer != account_ && issuer != dest &&
577 !amount.holds<MPTIssue>())
578 {
579 auto page = ctx_.view().dirInsert(
580 keylet::ownerDir(issuer), escrowKeylet, describeOwnerDir(issuer));
581 if (!page)
582 return tecDIR_FULL; // LCOV_EXCL_LINE
583 (*slep)[sfIssuerNode] = *page;
584 }
585
586 // Deduct owner's balance
587 if (isXRP(amount))
588 (*sle)[sfBalance] = (*sle)[sfBalance] - amount;
589 else
590 {
591 if (auto const ret = std::visit(
592 [&]<typename T>(T const&) {
593 return escrowLockApplyHelper<T>(
594 ctx_.view(), issuer, account_, amount, j_);
595 },
596 amount.asset().value());
597 !isTesSuccess(ret))
598 return ret; // LCOV_EXCL_LINE
599 }
600
601 // increment owner count
603 ctx_.view().update(sle);
604 return tesSUCCESS;
605}
606
607//------------------------------------------------------------------------------
608
609static bool
611{
612 using namespace ripple::cryptoconditions;
613
615
616 auto condition = Condition::deserialize(c, ec);
617 if (!condition)
618 return false;
619
620 auto fulfillment = Fulfillment::deserialize(f, ec);
621 if (!fulfillment)
622 return false;
623
624 return validate(*fulfillment, *condition);
625}
626
627NotTEC
629{
630 if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask)
631 return temINVALID_FLAG;
632
633 if (ctx.tx.isFieldPresent(sfCredentialIDs) &&
634 !ctx.rules.enabled(featureCredentials))
635 return temDISABLED;
636
637 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
638 return ret;
639
640 auto const cb = ctx.tx[~sfCondition];
641 auto const fb = ctx.tx[~sfFulfillment];
642
643 // If you specify a condition, then you must also specify
644 // a fulfillment.
645 if (static_cast<bool>(cb) != static_cast<bool>(fb))
646 return temMALFORMED;
647
648 // Verify the transaction signature. If it doesn't work
649 // then don't do any more work.
650 {
651 auto const ret = preflight2(ctx);
652 if (!isTesSuccess(ret))
653 return ret;
654 }
655
656 if (cb && fb)
657 {
658 auto& router = ctx.app.getHashRouter();
659
660 auto const id = ctx.tx.getTransactionID();
661 auto const flags = router.getFlags(id);
662
663 // If we haven't checked the condition, check it
664 // now. Whether it passes or not isn't important
665 // in preflight.
666 if (!any(flags & (SF_CF_INVALID | SF_CF_VALID)))
667 {
668 if (checkCondition(*fb, *cb))
669 router.setFlags(id, SF_CF_VALID);
670 else
671 router.setFlags(id, SF_CF_INVALID);
672 }
673 }
674
675 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
676 !isTesSuccess(err))
677 return err;
678
679 return tesSUCCESS;
680}
681
684{
685 XRPAmount extraFee{0};
686
687 if (auto const fb = tx[~sfFulfillment])
688 {
689 extraFee += view.fees().base * (32 + (fb->size() / 16));
690 }
691
692 return Transactor::calculateBaseFee(view, tx) + extraFee;
693}
694
695template <ValidIssueType T>
696static TER
698 PreclaimContext const& ctx,
699 AccountID const& dest,
700 STAmount const& amount);
701
702template <>
705 PreclaimContext const& ctx,
706 AccountID const& dest,
707 STAmount const& amount)
708{
709 AccountID issuer = amount.getIssuer();
710 // If the issuer is the same as the account, return tesSUCCESS
711 if (issuer == dest)
712 return tesSUCCESS;
713
714 // If the issuer has requireAuth set, check if the destination is authorized
715 if (auto const ter = requireAuth(ctx.view, amount.issue(), dest);
716 ter != tesSUCCESS)
717 return ter;
718
719 // If the issuer has deep frozen the destination, return tecFROZEN
720 if (isDeepFrozen(ctx.view, dest, amount.getCurrency(), amount.getIssuer()))
721 return tecFROZEN;
722
723 return tesSUCCESS;
724}
725
726template <>
729 PreclaimContext const& ctx,
730 AccountID const& dest,
731 STAmount const& amount)
732{
733 AccountID issuer = amount.getIssuer();
734 // If the issuer is the same as the dest, return tesSUCCESS
735 if (issuer == dest)
736 return tesSUCCESS;
737
738 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
739 auto const issuanceKey =
741 auto const sleIssuance = ctx.view.read(issuanceKey);
742 if (!sleIssuance)
743 return tecOBJECT_NOT_FOUND;
744
745 // If the issuer has requireAuth set, check if the destination is
746 // authorized
747 auto const& mptIssue = amount.get<MPTIssue>();
748 if (auto const ter =
749 requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth);
750 ter != tesSUCCESS)
751 return ter;
752
753 // If the issuer has frozen the destination, return tecLOCKED
754 if (isFrozen(ctx.view, dest, mptIssue))
755 return tecLOCKED;
756
757 return tesSUCCESS;
758}
759
760TER
762{
763 if (ctx.view.rules().enabled(featureCredentials))
764 {
765 if (auto const err =
766 credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
767 !isTesSuccess(err))
768 return err;
769 }
770
771 if (ctx.view.rules().enabled(featureTokenEscrow))
772 {
773 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
774 auto const slep = ctx.view.read(k);
775 if (!slep)
776 return tecNO_TARGET;
777
778 AccountID const dest = (*slep)[sfDestination];
779 STAmount const amount = (*slep)[sfAmount];
780
781 if (!isXRP(amount))
782 {
783 if (auto const ret = std::visit(
784 [&]<typename T>(T const&) {
785 return escrowFinishPreclaimHelper<T>(ctx, dest, amount);
786 },
787 amount.asset().value());
788 !isTesSuccess(ret))
789 return ret;
790 }
791 }
792 return tesSUCCESS;
793}
794
795template <ValidIssueType T>
796static TER
798 ApplyView& view,
799 Rate lockedRate,
800 std::shared_ptr<SLE> const& sleDest,
801 STAmount const& xrpBalance,
802 STAmount const& amount,
803 AccountID const& issuer,
804 AccountID const& sender,
805 AccountID const& receiver,
806 bool createAsset,
807 beast::Journal journal);
808
809template <>
812 ApplyView& view,
813 Rate lockedRate,
814 std::shared_ptr<SLE> const& sleDest,
815 STAmount const& xrpBalance,
816 STAmount const& amount,
817 AccountID const& issuer,
818 AccountID const& sender,
819 AccountID const& receiver,
820 bool createAsset,
821 beast::Journal journal)
822{
823 Keylet const trustLineKey = keylet::line(receiver, amount.issue());
824 bool const recvLow = issuer > receiver;
825 bool const senderIssuer = issuer == sender;
826 bool const receiverIssuer = issuer == receiver;
827 bool const issuerHigh = issuer > receiver;
828
829 // LCOV_EXCL_START
830 if (senderIssuer)
831 return tecINTERNAL;
832 // LCOV_EXCL_STOP
833
834 if (receiverIssuer)
835 return tesSUCCESS;
836
837 if (!view.exists(trustLineKey) && createAsset && !receiverIssuer)
838 {
839 // Can the account cover the trust line's reserve?
840 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
841 xrpBalance < view.fees().accountReserve(ownerCount + 1))
842 {
843 JLOG(journal.trace()) << "Trust line does not exist. "
844 "Insufficent reserve to create line.";
845
847 }
848
849 Currency const currency = amount.getCurrency();
850 STAmount initialBalance(amount.issue());
851 initialBalance.setIssuer(noAccount());
852
853 // clang-format off
854 if (TER const ter = trustCreate(
855 view, // payment sandbox
856 recvLow, // is dest low?
857 issuer, // source
858 receiver, // destination
859 trustLineKey.key, // ledger index
860 sleDest, // Account to add to
861 false, // authorize account
862 (sleDest->getFlags() & lsfDefaultRipple) == 0,
863 false, // freeze trust line
864 false, // deep freeze trust line
865 initialBalance, // zero initial balance
866 Issue(currency, receiver), // limit of zero
867 0, // quality in
868 0, // quality out
869 journal); // journal
870 !isTesSuccess(ter))
871 {
872 return ter; // LCOV_EXCL_LINE
873 }
874 // clang-format on
875
876 view.update(sleDest);
877 }
878
879 if (!view.exists(trustLineKey) && !receiverIssuer)
880 return tecNO_LINE;
881
882 auto const xferRate = transferRate(view, amount);
883 // update if issuer rate is less than locked rate
884 if (xferRate < lockedRate)
885 lockedRate = xferRate;
886
887 // Transfer Rate only applies when:
888 // 1. Issuer is not involved in the transfer (senderIssuer or
889 // receiverIssuer)
890 // 2. The locked rate is different from the parity rate
891
892 // NOTE: Transfer fee in escrow works a bit differently from a normal
893 // payment. In escrow, the fee is deducted from the locked/sending amount,
894 // whereas in a normal payment, the transfer fee is taken on top of the
895 // sending amount.
896 auto finalAmt = amount;
897 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
898 {
899 // compute transfer fee, if any
900 auto const xferFee = amount.value() -
901 divideRound(amount, lockedRate, amount.issue(), true);
902 // compute balance to transfer
903 finalAmt = amount.value() - xferFee;
904 }
905
906 // validate the line limit if the account submitting txn is not the receiver
907 // of the funds
908 if (!createAsset)
909 {
910 auto const sleRippleState = view.peek(trustLineKey);
911 if (!sleRippleState)
912 return tecINTERNAL; // LCOV_EXCL_LINE
913
914 // if the issuer is the high, then we use the low limit
915 // otherwise we use the high limit
916 STAmount const lineLimit = sleRippleState->getFieldAmount(
917 issuerHigh ? sfLowLimit : sfHighLimit);
918
919 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
920
921 // flip the sign of the line balance if the issuer is not high
922 if (!issuerHigh)
923 lineBalance.negate();
924
925 // add the final amount to the line balance
926 lineBalance += finalAmt;
927
928 // if the transfer would exceed the line limit return tecLIMIT_EXCEEDED
929 if (lineLimit < lineBalance)
930 return tecLIMIT_EXCEEDED;
931 }
932
933 // if destination is not the issuer then transfer funds
934 if (!receiverIssuer)
935 {
936 auto const ter =
937 rippleCredit(view, issuer, receiver, finalAmt, true, journal);
938 if (ter != tesSUCCESS)
939 return ter; // LCOV_EXCL_LINE
940 }
941 return tesSUCCESS;
942}
943
944template <>
947 ApplyView& view,
948 Rate lockedRate,
949 std::shared_ptr<SLE> const& sleDest,
950 STAmount const& xrpBalance,
951 STAmount const& amount,
952 AccountID const& issuer,
953 AccountID const& sender,
954 AccountID const& receiver,
955 bool createAsset,
956 beast::Journal journal)
957{
958 bool const senderIssuer = issuer == sender;
959 bool const receiverIssuer = issuer == receiver;
960
961 auto const mptID = amount.get<MPTIssue>().getMptID();
962 auto const issuanceKey = keylet::mptIssuance(mptID);
963 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
964 createAsset && !receiverIssuer)
965 {
966 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
967 xrpBalance < view.fees().accountReserve(ownerCount + 1))
968 {
970 }
971
972 if (auto const ter =
973 MPTokenAuthorize::createMPToken(view, mptID, receiver, 0);
974 !isTesSuccess(ter))
975 {
976 return ter; // LCOV_EXCL_LINE
977 }
978
979 // update owner count.
980 adjustOwnerCount(view, sleDest, 1, journal);
981 }
982
983 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
984 !receiverIssuer)
985 return tecNO_PERMISSION;
986
987 auto const xferRate = transferRate(view, amount);
988 // update if issuer rate is less than locked rate
989 if (xferRate < lockedRate)
990 lockedRate = xferRate;
991
992 // Transfer Rate only applies when:
993 // 1. Issuer is not involved in the transfer (senderIssuer or
994 // receiverIssuer)
995 // 2. The locked rate is different from the parity rate
996
997 // NOTE: Transfer fee in escrow works a bit differently from a normal
998 // payment. In escrow, the fee is deducted from the locked/sending amount,
999 // whereas in a normal payment, the transfer fee is taken on top of the
1000 // sending amount.
1001 auto finalAmt = amount;
1002 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
1003 {
1004 // compute transfer fee, if any
1005 auto const xferFee = amount.value() -
1006 divideRound(amount, lockedRate, amount.asset(), true);
1007 // compute balance to transfer
1008 finalAmt = amount.value() - xferFee;
1009 }
1010 return rippleUnlockEscrowMPT(
1011 view,
1012 sender,
1013 receiver,
1014 finalAmt,
1015 view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt,
1016 journal);
1017}
1018
1019TER
1021{
1022 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
1023 auto const slep = ctx_.view().peek(k);
1024 if (!slep)
1025 {
1026 if (ctx_.view().rules().enabled(featureTokenEscrow))
1027 return tecINTERNAL; // LCOV_EXCL_LINE
1028
1029 return tecNO_TARGET;
1030 }
1031
1032 // If a cancel time is present, a finish operation should only succeed prior
1033 // to that time. fix1571 corrects a logic error in the check that would make
1034 // a finish only succeed strictly after the cancel time.
1035 if (ctx_.view().rules().enabled(fix1571))
1036 {
1037 auto const now = ctx_.view().info().parentCloseTime;
1038
1039 // Too soon: can't execute before the finish time
1040 if ((*slep)[~sfFinishAfter] && !after(now, (*slep)[sfFinishAfter]))
1041 return tecNO_PERMISSION;
1042
1043 // Too late: can't execute after the cancel time
1044 if ((*slep)[~sfCancelAfter] && after(now, (*slep)[sfCancelAfter]))
1045 return tecNO_PERMISSION;
1046 }
1047 else
1048 {
1049 // Too soon?
1050 if ((*slep)[~sfFinishAfter] &&
1052 (*slep)[sfFinishAfter])
1053 return tecNO_PERMISSION;
1054
1055 // Too late?
1056 if ((*slep)[~sfCancelAfter] &&
1058 (*slep)[sfCancelAfter])
1059 return tecNO_PERMISSION;
1060 }
1061
1062 // Check cryptocondition fulfillment
1063 {
1064 auto const id = ctx_.tx.getTransactionID();
1065 auto flags = ctx_.app.getHashRouter().getFlags(id);
1066
1067 auto const cb = ctx_.tx[~sfCondition];
1068
1069 // It's unlikely that the results of the check will
1070 // expire from the hash router, but if it happens,
1071 // simply re-run the check.
1072 if (cb && !any(flags & (SF_CF_INVALID | SF_CF_VALID)))
1073 {
1074 auto const fb = ctx_.tx[~sfFulfillment];
1075
1076 if (!fb)
1077 return tecINTERNAL;
1078
1079 if (checkCondition(*fb, *cb))
1080 flags = SF_CF_VALID;
1081 else
1082 flags = SF_CF_INVALID;
1083
1084 ctx_.app.getHashRouter().setFlags(id, flags);
1085 }
1086
1087 // If the check failed, then simply return an error
1088 // and don't look at anything else.
1089 if (any(flags & SF_CF_INVALID))
1091
1092 // Check against condition in the ledger entry:
1093 auto const cond = (*slep)[~sfCondition];
1094
1095 // If a condition wasn't specified during creation,
1096 // one shouldn't be included now.
1097 if (!cond && cb)
1099
1100 // If a condition was specified during creation of
1101 // the suspended payment, the identical condition
1102 // must be presented again. We don't check if the
1103 // fulfillment matches the condition since we did
1104 // that in preflight.
1105 if (cond && (cond != cb))
1107 }
1108
1109 // NOTE: Escrow payments cannot be used to fund accounts.
1110 AccountID const destID = (*slep)[sfDestination];
1111 auto const sled = ctx_.view().peek(keylet::account(destID));
1112 if (!sled)
1113 return tecNO_DST;
1114
1115 if (ctx_.view().rules().enabled(featureDepositAuth))
1116 {
1117 if (auto err = verifyDepositPreauth(
1118 ctx_.tx, ctx_.view(), account_, destID, sled, ctx_.journal);
1119 !isTesSuccess(err))
1120 return err;
1121 }
1122
1123 AccountID const account = (*slep)[sfAccount];
1124
1125 // Remove escrow from owner directory
1126 {
1127 auto const page = (*slep)[sfOwnerNode];
1128 if (!ctx_.view().dirRemove(
1129 keylet::ownerDir(account), page, k.key, true))
1130 {
1131 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
1132 return tefBAD_LEDGER;
1133 }
1134 }
1135
1136 // Remove escrow from recipient's owner directory, if present.
1137 if (auto const optPage = (*slep)[~sfDestinationNode])
1138 {
1139 if (!ctx_.view().dirRemove(
1140 keylet::ownerDir(destID), *optPage, k.key, true))
1141 {
1142 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
1143 return tefBAD_LEDGER;
1144 }
1145 }
1146
1147 STAmount const amount = slep->getFieldAmount(sfAmount);
1148 // Transfer amount to destination
1149 if (isXRP(amount))
1150 (*sled)[sfBalance] = (*sled)[sfBalance] + amount;
1151 else
1152 {
1153 if (!ctx_.view().rules().enabled(featureTokenEscrow))
1154 return temDISABLED; // LCOV_EXCL_LINE
1155
1156 Rate lockedRate = slep->isFieldPresent(sfTransferRate)
1157 ? ripple::Rate(slep->getFieldU32(sfTransferRate))
1158 : parityRate;
1159 auto const issuer = amount.getIssuer();
1160 bool const createAsset = destID == account_;
1161 if (auto const ret = std::visit(
1162 [&]<typename T>(T const&) {
1163 return escrowUnlockApplyHelper<T>(
1164 ctx_.view(),
1165 lockedRate,
1166 sled,
1168 amount,
1169 issuer,
1170 account,
1171 destID,
1172 createAsset,
1173 j_);
1174 },
1175 amount.asset().value());
1176 !isTesSuccess(ret))
1177 return ret;
1178
1179 // Remove escrow from issuers owner directory, if present.
1180 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
1181 {
1182 if (!ctx_.view().dirRemove(
1183 keylet::ownerDir(issuer), *optPage, k.key, true))
1184 {
1185 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
1186 return tefBAD_LEDGER; // LCOV_EXCL_LINE
1187 }
1188 }
1189 }
1190
1191 ctx_.view().update(sled);
1192
1193 // Adjust source owner count
1194 auto const sle = ctx_.view().peek(keylet::account(account));
1195 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
1196 ctx_.view().update(sle);
1197
1198 // Remove escrow from ledger
1199 ctx_.view().erase(slep);
1200 return tesSUCCESS;
1201}
1202
1203//------------------------------------------------------------------------------
1204
1205NotTEC
1207{
1208 if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask)
1209 return temINVALID_FLAG;
1210
1211 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
1212 return ret;
1213
1214 return preflight2(ctx);
1215}
1216
1217template <ValidIssueType T>
1218static TER
1220 PreclaimContext const& ctx,
1221 AccountID const& account,
1222 STAmount const& amount);
1223
1224template <>
1227 PreclaimContext const& ctx,
1228 AccountID const& account,
1229 STAmount const& amount)
1230{
1231 AccountID issuer = amount.getIssuer();
1232 // If the issuer is the same as the account, return tecINTERNAL
1233 if (issuer == account)
1234 return tecINTERNAL; // LCOV_EXCL_LINE
1235
1236 // If the issuer has requireAuth set, check if the account is authorized
1237 if (auto const ter = requireAuth(ctx.view, amount.issue(), account);
1238 ter != tesSUCCESS)
1239 return ter;
1240
1241 return tesSUCCESS;
1242}
1243
1244template <>
1247 PreclaimContext const& ctx,
1248 AccountID const& account,
1249 STAmount const& amount)
1250{
1251 AccountID issuer = amount.getIssuer();
1252 // If the issuer is the same as the account, return tecINTERNAL
1253 if (issuer == account)
1254 return tecINTERNAL; // LCOV_EXCL_LINE
1255
1256 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
1257 auto const issuanceKey =
1259 auto const sleIssuance = ctx.view.read(issuanceKey);
1260 if (!sleIssuance)
1261 return tecOBJECT_NOT_FOUND;
1262
1263 // If the issuer has requireAuth set, check if the account is
1264 // authorized
1265 auto const& mptIssue = amount.get<MPTIssue>();
1266 if (auto const ter =
1267 requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth);
1268 ter != tesSUCCESS)
1269 return ter;
1270
1271 return tesSUCCESS;
1272}
1273
1274TER
1276{
1277 if (ctx.view.rules().enabled(featureTokenEscrow))
1278 {
1279 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
1280 auto const slep = ctx.view.read(k);
1281 if (!slep)
1282 return tecNO_TARGET;
1283
1284 AccountID const account = (*slep)[sfAccount];
1285 STAmount const amount = (*slep)[sfAmount];
1286
1287 if (!isXRP(amount))
1288 {
1289 if (auto const ret = std::visit(
1290 [&]<typename T>(T const&) {
1291 return escrowCancelPreclaimHelper<T>(
1292 ctx, account, amount);
1293 },
1294 amount.asset().value());
1295 !isTesSuccess(ret))
1296 return ret;
1297 }
1298 }
1299 return tesSUCCESS;
1300}
1301
1302TER
1304{
1305 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
1306 auto const slep = ctx_.view().peek(k);
1307 if (!slep)
1308 {
1309 if (ctx_.view().rules().enabled(featureTokenEscrow))
1310 return tecINTERNAL; // LCOV_EXCL_LINE
1311
1312 return tecNO_TARGET;
1313 }
1314
1315 if (ctx_.view().rules().enabled(fix1571))
1316 {
1317 auto const now = ctx_.view().info().parentCloseTime;
1318
1319 // No cancel time specified: can't execute at all.
1320 if (!(*slep)[~sfCancelAfter])
1321 return tecNO_PERMISSION;
1322
1323 // Too soon: can't execute before the cancel time.
1324 if (!after(now, (*slep)[sfCancelAfter]))
1325 return tecNO_PERMISSION;
1326 }
1327 else
1328 {
1329 // Too soon?
1330 if (!(*slep)[~sfCancelAfter] ||
1332 (*slep)[sfCancelAfter])
1333 return tecNO_PERMISSION;
1334 }
1335
1336 AccountID const account = (*slep)[sfAccount];
1337
1338 // Remove escrow from owner directory
1339 {
1340 auto const page = (*slep)[sfOwnerNode];
1341 if (!ctx_.view().dirRemove(
1342 keylet::ownerDir(account), page, k.key, true))
1343 {
1344 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
1345 return tefBAD_LEDGER;
1346 }
1347 }
1348
1349 // Remove escrow from recipient's owner directory, if present.
1350 if (auto const optPage = (*slep)[~sfDestinationNode]; optPage)
1351 {
1352 if (!ctx_.view().dirRemove(
1353 keylet::ownerDir((*slep)[sfDestination]),
1354 *optPage,
1355 k.key,
1356 true))
1357 {
1358 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
1359 return tefBAD_LEDGER;
1360 }
1361 }
1362
1363 auto const sle = ctx_.view().peek(keylet::account(account));
1364 STAmount const amount = slep->getFieldAmount(sfAmount);
1365
1366 // Transfer amount back to the owner
1367 if (isXRP(amount))
1368 (*sle)[sfBalance] = (*sle)[sfBalance] + amount;
1369 else
1370 {
1371 if (!ctx_.view().rules().enabled(featureTokenEscrow))
1372 return temDISABLED; // LCOV_EXCL_LINE
1373
1374 auto const issuer = amount.getIssuer();
1375 bool const createAsset = account == account_;
1376 if (auto const ret = std::visit(
1377 [&]<typename T>(T const&) {
1378 return escrowUnlockApplyHelper<T>(
1379 ctx_.view(),
1380 parityRate,
1381 slep,
1383 amount,
1384 issuer,
1385 account, // sender and receiver are the same
1386 account,
1387 createAsset,
1388 j_);
1389 },
1390 amount.asset().value());
1391 !isTesSuccess(ret))
1392 return ret; // LCOV_EXCL_LINE
1393
1394 // Remove escrow from issuers owner directory, if present.
1395 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
1396 {
1397 if (!ctx_.view().dirRemove(
1398 keylet::ownerDir(issuer), *optPage, k.key, true))
1399 {
1400 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
1401 return tefBAD_LEDGER; // LCOV_EXCL_LINE
1402 }
1403 }
1404 }
1405
1406 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
1407 ctx_.view().update(sle);
1408
1409 // Remove escrow from ledger
1410 ctx_.view().erase(slep);
1411
1412 return tesSUCCESS;
1413}
1414
1415} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream fatal() const
Definition Journal.h:352
Stream debug() const
Definition Journal.h:328
Stream trace() const
Severity stream access functions.
Definition Journal.h:322
virtual HashRouter & getHashRouter()=0
ApplyView & view()
Application & app
beast::Journal const journal
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:144
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 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.
Definition ApplyView.h:318
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
Definition Asset.h:156
TER doApply() override
Definition Escrow.cpp:1303
static NotTEC preflight(PreflightContext const &ctx)
Definition Escrow.cpp:1206
static TER preclaim(PreclaimContext const &ctx)
Definition Escrow.cpp:1275
static NotTEC preflight(PreflightContext const &ctx)
Definition Escrow.cpp:122
TER doApply() override
Definition Escrow.cpp:455
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition Escrow.cpp:82
static TER preclaim(PreclaimContext const &ctx)
Definition Escrow.cpp:363
static TER preclaim(PreclaimContext const &ctx)
Definition Escrow.cpp:761
static NotTEC preflight(PreflightContext const &ctx)
Definition Escrow.cpp:628
TER doApply() override
Definition Escrow.cpp:1020
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition Escrow.cpp:683
HashRouterFlags getFlags(uint256 const &key)
bool setFlags(uint256 const &key, HashRouterFlags flags)
Set the flags on a hash.
A currency issued by an account.
Definition Issue.h:33
constexpr MPTID const & getMptID() const
Definition MPTIssue.h:46
static TER createMPToken(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, std::uint32_t const flags)
A view into a ledger.
Definition ReadView.h:52
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
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.
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.
Definition Rules.cpp:130
constexpr bool holds() const noexcept
Definition STAmount.h:465
Asset const & asset() const
Definition STAmount.h:483
constexpr TIss const & get() const
void setIssuer(AccountID const &uIssuer)
Definition STAmount.h:588
Currency const & getCurrency() const
Definition STAmount.h:502
STAmount const & value() const noexcept
Definition STAmount.h:594
AccountID const & getIssuer() const
Definition STAmount.h:508
Issue const & issue() const
Definition STAmount.h:496
bool native() const noexcept
Definition STAmount.h:458
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:484
std::uint32_t getFlags() const
Definition STObject.cpp:537
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
Definition STTx.cpp:231
uint256 getTransactionID() const
Definition STTx.h:219
An immutable linear range of bytes.
Definition Slice.h:46
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
AccountID const account_
Definition Transactor.h:143
ApplyView & view()
Definition Transactor.h:159
beast::Journal const j_
Definition Transactor.h:141
XRPAmount mPriorBalance
Definition Transactor.h:144
XRPAmount mSourceBalance
Definition Transactor.h:145
ApplyContext & ctx_
Definition Transactor.h:140
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:59
T is_same_v
T message(T... args)
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:540
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:244
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:526
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition Indexes.cpp:389
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:374
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
TER rippleLockEscrowMPT(ApplyView &view, AccountID const &sender, STAmount const &amount, beast::Journal j)
Definition View.cpp:2908
AccountID const & noAccount()
A placeholder for empty accounts.
TER escrowFinishPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition Escrow.cpp:704
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType)
Check if the account lacks required authorization.
Definition View.cpp:2404
@ fhIGNORE_FREEZE
Definition View.h:78
TER escrowCreatePreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
Definition Escrow.cpp:283
bool isXRP(AccountID const &c)
Definition AccountID.h:90
TER rippleUnlockEscrowMPT(ApplyView &view, AccountID const &sender, AccountID const &receiver, STAmount const &netAmount, STAmount const &grossAmount, beast::Journal j)
Definition View.cpp:3005
static TER escrowFinishPreclaimHelper(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
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:528
TER escrowLockApplyHelper< Issue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
Definition Escrow.cpp:408
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition View.cpp:348
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition View.cpp:760
@ lsfRequireDestTag
@ lsfMPTCanEscrow
@ lsfDefaultRipple
@ lsfAllowTrustLineLocking
TER escrowCancelPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition Escrow.cpp:1246
static TER escrowLockApplyHelper(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
@ ahIGNORE_AUTH
Definition View.h:81
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition View.cpp:1048
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
Definition Rate2.cpp:104
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition View.cpp:248
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
Definition View.cpp:2622
constexpr HashRouterFlags SF_CF_VALID
Definition Escrow.cpp:43
@ tefBAD_LEDGER
Definition TER.h:170
@ tefINTERNAL
Definition TER.h:173
HashRouterFlags
Definition HashRouter.h:34
TER escrowCreatePreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
Definition Escrow.cpp:205
static bool adjustOwnerCount(ApplyContext &ctx, int count)
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
static bool checkCondition(Slice f, Slice c)
Definition Escrow.cpp:610
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition Escrow.cpp:946
static NotTEC escrowCreatePreflightHelper(PreflightContext const &ctx)
static TER escrowCancelPreclaimHelper(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
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.
Definition View.cpp:1329
@ tecCRYPTOCONDITION_ERROR
Definition TER.h:312
@ tecNO_DST
Definition TER.h:290
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:292
@ tecLIMIT_EXCEEDED
Definition TER.h:361
@ tecOBJECT_NOT_FOUND
Definition TER.h:326
@ tecNO_ISSUER
Definition TER.h:299
@ tecUNFUNDED
Definition TER.h:295
@ tecNO_TARGET
Definition TER.h:304
@ tecDIR_FULL
Definition TER.h:287
@ tecFROZEN
Definition TER.h:303
@ tecINSUFFICIENT_FUNDS
Definition TER.h:325
@ tecINTERNAL
Definition TER.h:310
@ tecNO_PERMISSION
Definition TER.h:305
@ tecDST_TAG_NEEDED
Definition TER.h:309
@ tecPRECISION_LOSS
Definition TER.h:363
@ tecNO_LINE
Definition TER.h:301
@ tecINSUFFICIENT_RESERVE
Definition TER.h:307
@ tecLOCKED
Definition TER.h:358
@ tesSUCCESS
Definition TER.h:244
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition View.cpp:385
constexpr HashRouterFlags SF_CF_INVALID
Definition Escrow.cpp:42
NotTEC escrowCreatePreflightHelper< MPTIssue >(PreflightContext const &ctx)
Definition Escrow.cpp:108
bool isTesSuccess(TER x) noexcept
Definition TER.h:674
TER escrowFinishPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition Escrow.cpp:728
NotTEC escrowCreatePreflightHelper< Issue >(PreflightContext const &ctx)
Definition Escrow.cpp:94
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:3179
constexpr std::uint32_t tfUniversalMask
Definition TxFlags.h:63
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.
Definition View.cpp:2769
TER escrowCancelPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition Escrow.cpp:1226
TER escrowLockApplyHelper< MPTIssue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
Definition Escrow.cpp:435
static TER escrowUnlockApplyHelper(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition View.cpp:1139
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:605
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition Escrow.cpp:811
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
static TER escrowCreatePreclaimHelper(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
@ temBAD_AMOUNT
Definition TER.h:89
@ temBAD_CURRENCY
Definition TER.h:90
@ temMALFORMED
Definition TER.h:87
@ temBAD_EXPIRATION
Definition TER.h:91
@ temINVALID_FLAG
Definition TER.h:111
@ temDISABLED
Definition TER.h:114
XRPAmount base
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:39
uint256 key
Definition Keylet.h:40
NetClock::time_point parentCloseTime
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:79
ReadView const & view
Definition Transactor.h:82
beast::Journal const j
Definition Transactor.h:87
State information when preflighting a tx.
Definition Transactor.h:34
beast::Journal const j
Definition Transactor.h:41
Represents a transfer rate.
Definition Rate.h:40
T time_since_epoch(T... args)
T visit(T... args)