rippled
Loading...
Searching...
No Matches
SetTrust.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/DelegateUtils.h>
21#include <xrpld/app/tx/detail/SetTrust.h>
22#include <xrpld/ledger/View.h>
23
24#include <xrpl/basics/Log.h>
25#include <xrpl/protocol/AMMCore.h>
26#include <xrpl/protocol/Feature.h>
27#include <xrpl/protocol/Indexes.h>
28#include <xrpl/protocol/Quality.h>
29#include <xrpl/protocol/SField.h>
30#include <xrpl/protocol/TER.h>
31
32namespace {
33
34uint32_t
35computeFreezeFlags(
36 uint32_t uFlags,
37 bool bHigh,
38 bool bNoFreeze,
39 bool bSetFreeze,
40 bool bClearFreeze,
41 bool bSetDeepFreeze,
42 bool bClearDeepFreeze)
43{
44 if (bSetFreeze && !bClearFreeze && !bNoFreeze)
45 {
46 uFlags |= (bHigh ? ripple::lsfHighFreeze : ripple::lsfLowFreeze);
47 }
48 else if (bClearFreeze && !bSetFreeze)
49 {
50 uFlags &= ~(bHigh ? ripple::lsfHighFreeze : ripple::lsfLowFreeze);
51 }
52 if (bSetDeepFreeze && !bClearDeepFreeze && !bNoFreeze)
53 {
54 uFlags |=
56 }
57 else if (bClearDeepFreeze && !bSetDeepFreeze)
58 {
59 uFlags &=
61 }
62
63 return uFlags;
64}
65
66} // namespace
67
68namespace ripple {
69
72{
73 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
74 return ret;
75
76 auto& tx = ctx.tx;
77 auto& j = ctx.j;
78
79 std::uint32_t const uTxFlags = tx.getFlags();
80
81 if (uTxFlags & tfTrustSetMask)
82 {
83 JLOG(j.trace()) << "Malformed transaction: Invalid flags set.";
84 return temINVALID_FLAG;
85 }
86
87 if (!ctx.rules.enabled(featureDeepFreeze))
88 {
89 // Even though the deep freeze flags are included in the
90 // `tfTrustSetMask`, they are not valid if the amendment is not enabled.
91 if (uTxFlags & (tfSetDeepFreeze | tfClearDeepFreeze))
92 {
93 return temINVALID_FLAG;
94 }
95 }
96
97 STAmount const saLimitAmount(tx.getFieldAmount(sfLimitAmount));
98
99 if (!isLegalNet(saLimitAmount))
100 return temBAD_AMOUNT;
101
102 if (saLimitAmount.native())
103 {
104 JLOG(j.trace()) << "Malformed transaction: specifies native limit "
105 << saLimitAmount.getFullText();
106 return temBAD_LIMIT;
107 }
108
109 if (badCurrency() == saLimitAmount.getCurrency())
110 {
111 JLOG(j.trace()) << "Malformed transaction: specifies XRP as IOU";
112 return temBAD_CURRENCY;
113 }
114
115 if (saLimitAmount < beast::zero)
116 {
117 JLOG(j.trace()) << "Malformed transaction: Negative credit limit.";
118 return temBAD_LIMIT;
119 }
120
121 // Check if destination makes sense.
122 auto const& issuer = saLimitAmount.getIssuer();
123
124 if (!issuer || issuer == noAccount())
125 {
126 JLOG(j.trace()) << "Malformed transaction: no destination account.";
127 return temDST_NEEDED;
128 }
129
130 return preflight2(ctx);
131}
132
133TER
135{
136 auto const delegate = tx[~sfDelegate];
137 if (!delegate)
138 return tesSUCCESS;
139
140 auto const delegateKey = keylet::delegate(tx[sfAccount], *delegate);
141 auto const sle = view.read(delegateKey);
142
143 if (!sle)
145
146 if (checkTxPermission(sle, tx) == tesSUCCESS)
147 return tesSUCCESS;
148
149 std::uint32_t const txFlags = tx.getFlags();
150
151 // Currently we only support TrustlineAuthorize, TrustlineFreeze and
152 // TrustlineUnfreeze granular permission. Setting other flags returns
153 // error.
154 if (txFlags & tfTrustSetPermissionMask)
156
157 if (tx.isFieldPresent(sfQualityIn) || tx.isFieldPresent(sfQualityOut))
159
160 auto const saLimitAmount = tx.getFieldAmount(sfLimitAmount);
161 auto const sleRippleState = view.read(keylet::line(
162 tx[sfAccount], saLimitAmount.getIssuer(), saLimitAmount.getCurrency()));
163
164 // if the trustline does not exist, granular permissions are
165 // not allowed to create trustline
166 if (!sleRippleState)
168
170 loadGranularPermission(sle, ttTRUST_SET, granularPermissions);
171
172 if (txFlags & tfSetfAuth &&
173 !granularPermissions.contains(TrustlineAuthorize))
175 if (txFlags & tfSetFreeze && !granularPermissions.contains(TrustlineFreeze))
177 if (txFlags & tfClearFreeze &&
178 !granularPermissions.contains(TrustlineUnfreeze))
180
181 // updating LimitAmount is not allowed only with granular permissions,
182 // unless there's a new granular permission for this in the future.
183 auto const curLimit = tx[sfAccount] > saLimitAmount.getIssuer()
184 ? sleRippleState->getFieldAmount(sfHighLimit)
185 : sleRippleState->getFieldAmount(sfLowLimit);
186
187 STAmount saLimitAllow = saLimitAmount;
188 saLimitAllow.setIssuer(tx[sfAccount]);
189
190 if (curLimit != saLimitAllow)
192
193 return tesSUCCESS;
194}
195
196TER
198{
199 auto const id = ctx.tx[sfAccount];
200
201 auto const sle = ctx.view.read(keylet::account(id));
202 if (!sle)
203 return terNO_ACCOUNT;
204
205 std::uint32_t const uTxFlags = ctx.tx.getFlags();
206
207 bool const bSetAuth = (uTxFlags & tfSetfAuth);
208
209 if (bSetAuth && !(sle->getFieldU32(sfFlags) & lsfRequireAuth))
210 {
211 JLOG(ctx.j.trace()) << "Retry: Auth not required.";
212 return tefNO_AUTH_REQUIRED;
213 }
214
215 auto const saLimitAmount = ctx.tx[sfLimitAmount];
216
217 auto const currency = saLimitAmount.getCurrency();
218 auto const uDstAccountID = saLimitAmount.getIssuer();
219
220 if (ctx.view.rules().enabled(fixTrustLinesToSelf))
221 {
222 if (id == uDstAccountID)
223 return temDST_IS_SRC;
224 }
225 else
226 {
227 if (id == uDstAccountID)
228 {
229 // Prevent trustline to self from being created,
230 // unless one has somehow already been created
231 // (in which case doApply will clean it up).
232 auto const sleDelete =
233 ctx.view.read(keylet::line(id, uDstAccountID, currency));
234
235 if (!sleDelete)
236 {
237 JLOG(ctx.j.trace())
238 << "Malformed transaction: Can not extend credit to self.";
239 return temDST_IS_SRC;
240 }
241 }
242 }
243
244 // This might be nullptr
245 auto const sleDst = ctx.view.read(keylet::account(uDstAccountID));
246 if ((ctx.view.rules().enabled(featureDisallowIncoming) ||
247 ammEnabled(ctx.view.rules()) ||
248 ctx.view.rules().enabled(featureSingleAssetVault)) &&
249 sleDst == nullptr)
250 return tecNO_DST;
251
252 // If the destination has opted to disallow incoming trustlines
253 // then honour that flag
254 if (ctx.view.rules().enabled(featureDisallowIncoming))
255 {
256 if (sleDst->getFlags() & lsfDisallowIncomingTrustline)
257 {
258 // The original implementation of featureDisallowIncoming was
259 // too restrictive. If
260 // o fixDisallowIncomingV1 is enabled and
261 // o The trust line already exists
262 // Then allow the TrustSet.
263 if (ctx.view.rules().enabled(fixDisallowIncomingV1) &&
264 ctx.view.exists(keylet::line(id, uDstAccountID, currency)))
265 {
266 // pass
267 }
268 else
269 return tecNO_PERMISSION;
270 }
271 }
272
273 // In general, trust lines to pseudo accounts are not permitted, unless
274 // enabled in the code section below, for specific cases. This block is not
275 // amendment-gated because sleDst will not have a pseudo-account designator
276 // field populated, unless the appropriate amendment was already enabled.
277 if (sleDst && isPseudoAccount(sleDst))
278 {
279 // If destination is AMM and the trustline doesn't exist then only allow
280 // SetTrust if the asset is AMM LP token and AMM is not in empty state.
281 if (sleDst->isFieldPresent(sfAMMID))
282 {
283 if (ctx.view.exists(keylet::line(id, uDstAccountID, currency)))
284 {
285 // pass
286 }
287 else if (
288 auto const ammSle =
289 ctx.view.read({ltAMM, sleDst->getFieldH256(sfAMMID)}))
290 {
291 if (auto const lpTokens =
292 ammSle->getFieldAmount(sfLPTokenBalance);
293 lpTokens == beast::zero)
294 return tecAMM_EMPTY;
295 else if (lpTokens.getCurrency() != saLimitAmount.getCurrency())
296 return tecNO_PERMISSION;
297 }
298 else
299 return tecINTERNAL; // LCOV_EXCL_LINE
300 }
301 else if (sleDst->isFieldPresent(sfVaultID))
302 {
303 if (!ctx.view.exists(keylet::line(id, uDstAccountID, currency)))
304 return tecNO_PERMISSION;
305 // else pass
306 }
307 else
308 return tecPSEUDO_ACCOUNT;
309 }
310
311 // Checking all freeze/deep freeze flag invariants.
312 if (ctx.view.rules().enabled(featureDeepFreeze))
313 {
314 bool const bNoFreeze = sle->isFlag(lsfNoFreeze);
315 bool const bSetFreeze = (uTxFlags & tfSetFreeze);
316 bool const bSetDeepFreeze = (uTxFlags & tfSetDeepFreeze);
317
318 if (bNoFreeze && (bSetFreeze || bSetDeepFreeze))
319 {
320 // Cannot freeze the trust line if NoFreeze is set
321 return tecNO_PERMISSION;
322 }
323
324 bool const bClearFreeze = (uTxFlags & tfClearFreeze);
325 bool const bClearDeepFreeze = (uTxFlags & tfClearDeepFreeze);
326 if ((bSetFreeze || bSetDeepFreeze) &&
327 (bClearFreeze || bClearDeepFreeze))
328 {
329 // Freezing and unfreezing in the same transaction should be
330 // illegal
331 return tecNO_PERMISSION;
332 }
333
334 bool const bHigh = id > uDstAccountID;
335 // Fetching current state of trust line
336 auto const sleRippleState =
337 ctx.view.read(keylet::line(id, uDstAccountID, currency));
338 std::uint32_t uFlags =
339 sleRippleState ? sleRippleState->getFieldU32(sfFlags) : 0u;
340 // Computing expected trust line state
341 uFlags = computeFreezeFlags(
342 uFlags,
343 bHigh,
344 bNoFreeze,
345 bSetFreeze,
346 bClearFreeze,
347 bSetDeepFreeze,
348 bClearDeepFreeze);
349
350 auto const frozen = uFlags & (bHigh ? lsfHighFreeze : lsfLowFreeze);
351 auto const deepFrozen =
352 uFlags & (bHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
353
354 // Trying to set deep freeze on not already frozen trust line must
355 // fail. This also checks that clearing normal freeze while deep
356 // frozen must not work
357 if (deepFrozen && !frozen)
358 {
359 return tecNO_PERMISSION;
360 }
361 }
362
363 return tesSUCCESS;
364}
365
366TER
368{
369 TER terResult = tesSUCCESS;
370
371 STAmount const saLimitAmount(ctx_.tx.getFieldAmount(sfLimitAmount));
372 bool const bQualityIn(ctx_.tx.isFieldPresent(sfQualityIn));
373 bool const bQualityOut(ctx_.tx.isFieldPresent(sfQualityOut));
374
375 Currency const currency(saLimitAmount.getCurrency());
376 AccountID uDstAccountID(saLimitAmount.getIssuer());
377
378 // true, if current is high account.
379 bool const bHigh = account_ > uDstAccountID;
380
381 auto const sle = view().peek(keylet::account(account_));
382 if (!sle)
383 return tefINTERNAL;
384
385 std::uint32_t const uOwnerCount = sle->getFieldU32(sfOwnerCount);
386
387 // The reserve that is required to create the line. Note
388 // that although the reserve increases with every item
389 // an account owns, in the case of trust lines we only
390 // *enforce* a reserve if the user owns more than two
391 // items.
392 //
393 // We do this because being able to exchange currencies,
394 // which needs trust lines, is a powerful Ripple feature.
395 // So we want to make it easy for a gateway to fund the
396 // accounts of its users without fear of being tricked.
397 //
398 // Without this logic, a gateway that wanted to have a
399 // new user use its services, would have to give that
400 // user enough XRP to cover not only the account reserve
401 // but the incremental reserve for the trust line as
402 // well. A person with no intention of using the gateway
403 // could use the extra XRP for their own purposes.
404
405 XRPAmount const reserveCreate(
406 (uOwnerCount < 2) ? XRPAmount(beast::zero)
407 : view().fees().accountReserve(uOwnerCount + 1));
408
409 std::uint32_t uQualityIn(bQualityIn ? ctx_.tx.getFieldU32(sfQualityIn) : 0);
410 std::uint32_t uQualityOut(
411 bQualityOut ? ctx_.tx.getFieldU32(sfQualityOut) : 0);
412
413 if (bQualityOut && QUALITY_ONE == uQualityOut)
414 uQualityOut = 0;
415
416 std::uint32_t const uTxFlags = ctx_.tx.getFlags();
417
418 bool const bSetAuth = (uTxFlags & tfSetfAuth);
419 bool const bSetNoRipple = (uTxFlags & tfSetNoRipple);
420 bool const bClearNoRipple = (uTxFlags & tfClearNoRipple);
421 bool const bSetFreeze = (uTxFlags & tfSetFreeze);
422 bool const bClearFreeze = (uTxFlags & tfClearFreeze);
423 bool const bSetDeepFreeze = (uTxFlags & tfSetDeepFreeze);
424 bool const bClearDeepFreeze = (uTxFlags & tfClearDeepFreeze);
425
426 auto viewJ = ctx_.app.journal("View");
427
428 // Trust lines to self are impossible but because of the old bug there
429 // are two on 19-02-2022. This code was here to allow those trust lines
430 // to be deleted. The fixTrustLinesToSelf fix amendment will remove them
431 // when it enables so this code will no longer be needed.
432 if (!view().rules().enabled(fixTrustLinesToSelf) &&
433 account_ == uDstAccountID)
434 {
435 return trustDelete(
436 view(),
437 view().peek(keylet::line(account_, uDstAccountID, currency)),
438 account_,
439 uDstAccountID,
440 viewJ);
441 }
442
443 SLE::pointer sleDst = view().peek(keylet::account(uDstAccountID));
444
445 if (!sleDst)
446 {
447 JLOG(j_.trace())
448 << "Delay transaction: Destination account does not exist.";
449 return tecNO_DST;
450 }
451
452 STAmount saLimitAllow = saLimitAmount;
453 saLimitAllow.setIssuer(account_);
454
455 SLE::pointer sleRippleState =
456 view().peek(keylet::line(account_, uDstAccountID, currency));
457
458 if (sleRippleState)
459 {
460 STAmount saLowBalance;
461 STAmount saLowLimit;
462 STAmount saHighBalance;
463 STAmount saHighLimit;
464 std::uint32_t uLowQualityIn;
465 std::uint32_t uLowQualityOut;
466 std::uint32_t uHighQualityIn;
467 std::uint32_t uHighQualityOut;
468 auto const& uLowAccountID = !bHigh ? account_ : uDstAccountID;
469 auto const& uHighAccountID = bHigh ? account_ : uDstAccountID;
470 SLE::ref sleLowAccount = !bHigh ? sle : sleDst;
471 SLE::ref sleHighAccount = bHigh ? sle : sleDst;
472
473 //
474 // Balances
475 //
476
477 saLowBalance = sleRippleState->getFieldAmount(sfBalance);
478 saHighBalance = -saLowBalance;
479
480 //
481 // Limits
482 //
483
484 sleRippleState->setFieldAmount(
485 !bHigh ? sfLowLimit : sfHighLimit, saLimitAllow);
486
487 saLowLimit =
488 !bHigh ? saLimitAllow : sleRippleState->getFieldAmount(sfLowLimit);
489 saHighLimit =
490 bHigh ? saLimitAllow : sleRippleState->getFieldAmount(sfHighLimit);
491
492 //
493 // Quality in
494 //
495
496 if (!bQualityIn)
497 {
498 // Not setting. Just get it.
499
500 uLowQualityIn = sleRippleState->getFieldU32(sfLowQualityIn);
501 uHighQualityIn = sleRippleState->getFieldU32(sfHighQualityIn);
502 }
503 else if (uQualityIn)
504 {
505 // Setting.
506
507 sleRippleState->setFieldU32(
508 !bHigh ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
509
510 uLowQualityIn = !bHigh
511 ? uQualityIn
512 : sleRippleState->getFieldU32(sfLowQualityIn);
513 uHighQualityIn = bHigh
514 ? uQualityIn
515 : sleRippleState->getFieldU32(sfHighQualityIn);
516 }
517 else
518 {
519 // Clearing.
520
521 sleRippleState->makeFieldAbsent(
522 !bHigh ? sfLowQualityIn : sfHighQualityIn);
523
524 uLowQualityIn =
525 !bHigh ? 0 : sleRippleState->getFieldU32(sfLowQualityIn);
526 uHighQualityIn =
527 bHigh ? 0 : sleRippleState->getFieldU32(sfHighQualityIn);
528 }
529
530 if (QUALITY_ONE == uLowQualityIn)
531 uLowQualityIn = 0;
532
533 if (QUALITY_ONE == uHighQualityIn)
534 uHighQualityIn = 0;
535
536 //
537 // Quality out
538 //
539
540 if (!bQualityOut)
541 {
542 // Not setting. Just get it.
543
544 uLowQualityOut = sleRippleState->getFieldU32(sfLowQualityOut);
545 uHighQualityOut = sleRippleState->getFieldU32(sfHighQualityOut);
546 }
547 else if (uQualityOut)
548 {
549 // Setting.
550
551 sleRippleState->setFieldU32(
552 !bHigh ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
553
554 uLowQualityOut = !bHigh
555 ? uQualityOut
556 : sleRippleState->getFieldU32(sfLowQualityOut);
557 uHighQualityOut = bHigh
558 ? uQualityOut
559 : sleRippleState->getFieldU32(sfHighQualityOut);
560 }
561 else
562 {
563 // Clearing.
564
565 sleRippleState->makeFieldAbsent(
566 !bHigh ? sfLowQualityOut : sfHighQualityOut);
567
568 uLowQualityOut =
569 !bHigh ? 0 : sleRippleState->getFieldU32(sfLowQualityOut);
570 uHighQualityOut =
571 bHigh ? 0 : sleRippleState->getFieldU32(sfHighQualityOut);
572 }
573
574 std::uint32_t const uFlagsIn(sleRippleState->getFieldU32(sfFlags));
575 std::uint32_t uFlagsOut(uFlagsIn);
576
577 if (bSetNoRipple && !bClearNoRipple)
578 {
579 if ((bHigh ? saHighBalance : saLowBalance) >= beast::zero)
580 uFlagsOut |= (bHigh ? lsfHighNoRipple : lsfLowNoRipple);
581
582 else if (view().rules().enabled(fix1578))
583 // Cannot set noRipple on a negative balance.
584 return tecNO_PERMISSION;
585 }
586 else if (bClearNoRipple && !bSetNoRipple)
587 {
588 uFlagsOut &= ~(bHigh ? lsfHighNoRipple : lsfLowNoRipple);
589 }
590
591 // Have to use lsfNoFreeze to maintain pre-deep freeze behavior
592 bool const bNoFreeze = sle->isFlag(lsfNoFreeze);
593 uFlagsOut = computeFreezeFlags(
594 uFlagsOut,
595 bHigh,
596 bNoFreeze,
597 bSetFreeze,
598 bClearFreeze,
599 bSetDeepFreeze,
600 bClearDeepFreeze);
601
602 if (QUALITY_ONE == uLowQualityOut)
603 uLowQualityOut = 0;
604
605 if (QUALITY_ONE == uHighQualityOut)
606 uHighQualityOut = 0;
607
608 bool const bLowDefRipple = sleLowAccount->getFlags() & lsfDefaultRipple;
609 bool const bHighDefRipple =
610 sleHighAccount->getFlags() & lsfDefaultRipple;
611
612 bool const bLowReserveSet = uLowQualityIn || uLowQualityOut ||
613 ((uFlagsOut & lsfLowNoRipple) == 0) != bLowDefRipple ||
614 (uFlagsOut & lsfLowFreeze) || saLowLimit ||
615 saLowBalance > beast::zero;
616 bool const bLowReserveClear = !bLowReserveSet;
617
618 bool const bHighReserveSet = uHighQualityIn || uHighQualityOut ||
619 ((uFlagsOut & lsfHighNoRipple) == 0) != bHighDefRipple ||
620 (uFlagsOut & lsfHighFreeze) || saHighLimit ||
621 saHighBalance > beast::zero;
622 bool const bHighReserveClear = !bHighReserveSet;
623
624 bool const bDefault = bLowReserveClear && bHighReserveClear;
625
626 bool const bLowReserved = (uFlagsIn & lsfLowReserve);
627 bool const bHighReserved = (uFlagsIn & lsfHighReserve);
628
629 bool bReserveIncrease = false;
630
631 if (bSetAuth)
632 {
633 uFlagsOut |= (bHigh ? lsfHighAuth : lsfLowAuth);
634 }
635
636 if (bLowReserveSet && !bLowReserved)
637 {
638 // Set reserve for low account.
639 adjustOwnerCount(view(), sleLowAccount, 1, viewJ);
640 uFlagsOut |= lsfLowReserve;
641
642 if (!bHigh)
643 bReserveIncrease = true;
644 }
645
646 if (bLowReserveClear && bLowReserved)
647 {
648 // Clear reserve for low account.
649 adjustOwnerCount(view(), sleLowAccount, -1, viewJ);
650 uFlagsOut &= ~lsfLowReserve;
651 }
652
653 if (bHighReserveSet && !bHighReserved)
654 {
655 // Set reserve for high account.
656 adjustOwnerCount(view(), sleHighAccount, 1, viewJ);
657 uFlagsOut |= lsfHighReserve;
658
659 if (bHigh)
660 bReserveIncrease = true;
661 }
662
663 if (bHighReserveClear && bHighReserved)
664 {
665 // Clear reserve for high account.
666 adjustOwnerCount(view(), sleHighAccount, -1, viewJ);
667 uFlagsOut &= ~lsfHighReserve;
668 }
669
670 if (uFlagsIn != uFlagsOut)
671 sleRippleState->setFieldU32(sfFlags, uFlagsOut);
672
673 if (bDefault || badCurrency() == currency)
674 {
675 // Delete.
676
677 terResult = trustDelete(
678 view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ);
679 }
680 // Reserve is not scaled by load.
681 else if (bReserveIncrease && mPriorBalance < reserveCreate)
682 {
683 JLOG(j_.trace()) << "Delay transaction: Insufficent reserve to "
684 "add trust line.";
685
686 // Another transaction could provide XRP to the account and then
687 // this transaction would succeed.
688 terResult = tecINSUF_RESERVE_LINE;
689 }
690 else
691 {
692 view().update(sleRippleState);
693
694 JLOG(j_.trace()) << "Modify ripple line";
695 }
696 }
697 // Line does not exist.
698 else if (
699 !saLimitAmount && // Setting default limit.
700 (!bQualityIn || !uQualityIn) && // Not setting quality in or
701 // setting default quality in.
702 (!bQualityOut || !uQualityOut) && // Not setting quality out or
703 // setting default quality out.
704 (!bSetAuth))
705 {
706 JLOG(j_.trace())
707 << "Redundant: Setting non-existent ripple line to defaults.";
709 }
710 else if (mPriorBalance < reserveCreate) // Reserve is not scaled by
711 // load.
712 {
713 JLOG(j_.trace()) << "Delay transaction: Line does not exist. "
714 "Insufficent reserve to create line.";
715
716 // Another transaction could create the account and then this
717 // transaction would succeed.
718 terResult = tecNO_LINE_INSUF_RESERVE;
719 }
720 else
721 {
722 // Zero balance in currency.
723 STAmount saBalance(Issue{currency, noAccount()});
724
725 auto const k = keylet::line(account_, uDstAccountID, currency);
726
727 JLOG(j_.trace()) << "doTrustSet: Creating ripple line: "
728 << to_string(k.key);
729
730 // Create a new ripple line.
731 terResult = trustCreate(
732 view(),
733 bHigh,
734 account_,
735 uDstAccountID,
736 k.key,
737 sle,
738 bSetAuth,
739 bSetNoRipple && !bClearNoRipple,
740 bSetFreeze && !bClearFreeze,
741 bSetDeepFreeze,
742 saBalance,
743 saLimitAllow, // Limit for who is being charged.
744 uQualityIn,
745 uQualityOut,
746 viewJ);
747 }
748
749 return terResult;
750}
751
752} // namespace ripple
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
virtual beast::Journal journal(std::string const &name)=0
Application & app
Definition: ApplyContext.h:71
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
A currency issued by an account.
Definition: Issue.h:33
A view into a ledger.
Definition: ReadView.h:52
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
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
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:588
Currency const & getCurrency() const
Definition: STAmount.h:502
AccountID const & getIssuer() const
Definition: STAmount.h:508
std::string getFullText() const override
Definition: STAmount.cpp:696
bool native() const noexcept
Definition: STAmount.h:458
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:615
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:665
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:484
std::uint32_t getFlags() const
Definition: STObject.cpp:537
static NotTEC preflight(PreflightContext const &ctx)
Definition: SetTrust.cpp:71
static TER preclaim(PreclaimContext const &ctx)
Definition: SetTrust.cpp:197
TER doApply() override
Definition: SetTrust.cpp:367
static TER checkPermission(ReadView const &view, STTx const &tx)
Definition: SetTrust.cpp:134
AccountID const account_
Definition: Transactor.h:143
ApplyView & view()
Definition: Transactor.h:159
beast::Journal const j_
Definition: Transactor.h:141
XRPAmount mPriorBalance
Definition: Transactor.h:144
ApplyContext & ctx_
Definition: Transactor.h:140
T contains(T... args)
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition: Indexes.cpp:465
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 account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
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.
Definition: AccountID.cpp:185
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:133
constexpr std::uint32_t tfSetDeepFreeze
Definition: TxFlags.h:120
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:600
@ lsfHighDeepFreeze
@ lsfDefaultRipple
@ lsfHighNoRipple
@ lsfRequireAuth
@ lsfHighFreeze
@ lsfLowNoRipple
@ lsfHighReserve
@ lsfDisallowIncomingTrustline
@ lsfLowReserve
@ lsfLowFreeze
@ lsfLowDeepFreeze
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:129
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
constexpr std::uint32_t tfTrustSetPermissionMask
Definition: TxFlags.h:125
@ tefNO_AUTH_REQUIRED
Definition: TER.h:174
@ tefINTERNAL
Definition: TER.h:173
constexpr std::uint32_t tfClearNoRipple
Definition: TxFlags.h:117
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
void loadGranularPermission(std::shared_ptr< SLE const > const &delegate, TxType const &type, std::unordered_set< GranularPermissionType > &granularPermissions)
Load the granular permissions granted to the delegate account for the specified transaction type.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:160
constexpr std::uint32_t tfSetfAuth
Definition: TxFlags.h:115
constexpr std::uint32_t tfClearFreeze
Definition: TxFlags.h:119
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
Definition: View.cpp:1329
TER checkTxPermission(std::shared_ptr< SLE const > const &delegate, STTx const &tx)
Check if the delegate account has permission to execute the transaction.
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
Definition: View.cpp:1534
@ tecNO_LINE_REDUNDANT
Definition: TER.h:293
@ tecNO_DELEGATE_PERMISSION
Definition: TER.h:364
@ tecPSEUDO_ACCOUNT
Definition: TER.h:362
@ tecNO_DST
Definition: TER.h:290
@ tecNO_LINE_INSUF_RESERVE
Definition: TER.h:292
@ tecINSUF_RESERVE_LINE
Definition: TER.h:288
@ tecAMM_EMPTY
Definition: TER.h:332
@ tecINTERNAL
Definition: TER.h:310
@ tecNO_PERMISSION
Definition: TER.h:305
@ tesSUCCESS
Definition: TER.h:244
constexpr std::uint32_t tfClearDeepFreeze
Definition: TxFlags.h:121
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
constexpr std::uint32_t tfTrustSetMask
Definition: TxFlags.h:122
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ terNO_ACCOUNT
Definition: TER.h:217
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:118
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:116
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition: View.cpp:1139
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:605
@ temBAD_AMOUNT
Definition: TER.h:89
@ temBAD_LIMIT
Definition: TER.h:94
@ temDST_NEEDED
Definition: TER.h:109
@ temBAD_CURRENCY
Definition: TER.h:90
@ temINVALID_FLAG
Definition: TER.h:111
@ temDST_IS_SRC
Definition: TER.h:108
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:79
ReadView const & view
Definition: Transactor.h:82
beast::Journal const j
Definition: Transactor.h:87
State information when preflighting a tx.
Definition: Transactor.h:34
beast::Journal const j
Definition: Transactor.h:41