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