rippled
Clawback.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2023 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 <ripple/app/tx/impl/Clawback.h>
21 #include <ripple/ledger/View.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/Indexes.h>
24 #include <ripple/protocol/Protocol.h>
25 #include <ripple/protocol/TxFlags.h>
26 #include <ripple/protocol/st.h>
27 
28 namespace ripple {
29 
30 NotTEC
32 {
33  if (!ctx.rules.enabled(featureClawback))
34  return temDISABLED;
35 
36  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
37  return ret;
38 
39  if (ctx.tx.getFlags() & tfClawbackMask)
40  return temINVALID_FLAG;
41 
42  AccountID const issuer = ctx.tx[sfAccount];
43  STAmount const clawAmount = ctx.tx[sfAmount];
44 
45  // The issuer field is used for the token holder instead
46  AccountID const& holder = clawAmount.getIssuer();
47 
48  if (issuer == holder || isXRP(clawAmount) || clawAmount <= beast::zero)
49  return temBAD_AMOUNT;
50 
51  return preflight2(ctx);
52 }
53 
54 TER
56 {
57  AccountID const issuer = ctx.tx[sfAccount];
58  STAmount const clawAmount = ctx.tx[sfAmount];
59  AccountID const& holder = clawAmount.getIssuer();
60 
61  auto const sleIssuer = ctx.view.read(keylet::account(issuer));
62  auto const sleHolder = ctx.view.read(keylet::account(holder));
63  if (!sleIssuer || !sleHolder)
64  return terNO_ACCOUNT;
65 
66  if (sleHolder->isFieldPresent(sfAMMID))
67  return tecAMM_ACCOUNT;
68 
69  std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags);
70 
71  // If AllowTrustLineClawback is not set or NoFreeze is set, return no
72  // permission
73  if (!(issuerFlagsIn & lsfAllowTrustLineClawback) ||
74  (issuerFlagsIn & lsfNoFreeze))
75  return tecNO_PERMISSION;
76 
77  auto const sleRippleState =
78  ctx.view.read(keylet::line(holder, issuer, clawAmount.getCurrency()));
79  if (!sleRippleState)
80  return tecNO_LINE;
81 
82  STAmount const balance = (*sleRippleState)[sfBalance];
83 
84  // If balance is positive, issuer must have higher address than holder
85  if (balance > beast::zero && issuer < holder)
86  return tecNO_PERMISSION;
87 
88  // If balance is negative, issuer must have lower address than holder
89  if (balance < beast::zero && issuer > holder)
90  return tecNO_PERMISSION;
91 
92  // At this point, we know that issuer and holder accounts
93  // are correct and a trustline exists between them.
94  //
95  // Must now explicitly check the balance to make sure
96  // available balance is non-zero.
97  //
98  // We can't directly check the balance of trustline because
99  // the available balance of a trustline is prone to new changes (eg.
100  // XLS-34). So we must use `accountHolds`.
101  if (accountHolds(
102  ctx.view,
103  holder,
104  clawAmount.getCurrency(),
105  issuer,
107  ctx.j) <= beast::zero)
108  return tecINSUFFICIENT_FUNDS;
109 
110  return tesSUCCESS;
111 }
112 
113 TER
115 {
116  AccountID const& issuer = account_;
117  STAmount clawAmount = ctx_.tx[sfAmount];
118  AccountID const holder = clawAmount.getIssuer(); // cannot be reference
119 
120  // Replace the `issuer` field with issuer's account
121  clawAmount.setIssuer(issuer);
122  if (holder == issuer)
123  return tecINTERNAL;
124 
125  // Get the spendable balance. Must use `accountHolds`.
126  STAmount const spendableAmount = accountHolds(
127  view(),
128  holder,
129  clawAmount.getCurrency(),
130  clawAmount.getIssuer(),
132  j_);
133 
134  return rippleCredit(
135  view(),
136  holder,
137  issuer,
138  std::min(spendableAmount, clawAmount),
139  true,
140  j_);
141 }
142 
143 } // namespace ripple
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Definition: View.cpp:950
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:133
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:56
ripple::PreclaimContext::j
const beast::Journal j
Definition: Transactor.h:60
ripple::featureClawback
const uint256 featureClawback
ripple::sfAmount
const SF_AMOUNT sfAmount
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:89
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:643
ripple::tecINSUFFICIENT_FUNDS
@ tecINSUFFICIENT_FUNDS
Definition: TER.h:308
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:226
ripple::tfClawbackMask
constexpr const std::uint32_t tfClawbackMask
Definition: TxFlags.h:164
ripple::STAmount::setIssuer
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:436
ripple::lsfAllowTrustLineClawback
@ lsfAllowTrustLineClawback
Definition: LedgerFormats.h:283
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:81
ripple::STAmount::getIssuer
AccountID const & getIssuer() const
Definition: STAmount.h:362
ripple::base_uint< 160, detail::AccountIDTag >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:110
ripple::Clawback::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: Clawback.cpp:55
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:143
ripple::TERSubset< CanCvtToTER >
ripple::STAmount
Definition: STAmount.h:46
ripple::tecINTERNAL
@ tecINTERNAL
Definition: TER.h:293
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:497
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:88
std::uint32_t
ripple::keylet::line
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:203
ripple::sfAMMID
const SF_UINT256 sfAMMID
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:58
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:213
std::min
T min(T... args)
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:52
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::tecNO_LINE
@ tecNO_LINE
Definition: TER.h:284
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:113
ripple::lsfNoFreeze
@ lsfNoFreeze
Definition: LedgerFormats.h:266
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:288
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:79
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::Clawback::doApply
TER doApply() override
Definition: Clawback.cpp:114
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::STAmount::getCurrency
Currency const & getCurrency() const
Definition: STAmount.h:356
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:238
ripple::Clawback::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: Clawback.cpp:31
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::tecAMM_ACCOUNT
@ tecAMM_ACCOUNT
Definition: TER.h:317
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:574