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