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