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