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  std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags);
67 
68  // If AllowTrustLineClawback is not set or NoFreeze is set, return no
69  // permission
70  if (!(issuerFlagsIn & lsfAllowTrustLineClawback) ||
71  (issuerFlagsIn & lsfNoFreeze))
72  return tecNO_PERMISSION;
73 
74  auto const sleRippleState =
75  ctx.view.read(keylet::line(holder, issuer, clawAmount.getCurrency()));
76  if (!sleRippleState)
77  return tecNO_LINE;
78 
79  STAmount const balance = (*sleRippleState)[sfBalance];
80 
81  // If balance is positive, issuer must have higher address than holder
82  if (balance > beast::zero && issuer < holder)
83  return tecNO_PERMISSION;
84 
85  // If balance is negative, issuer must have lower address than holder
86  if (balance < beast::zero && issuer > holder)
87  return tecNO_PERMISSION;
88 
89  // At this point, we know that issuer and holder accounts
90  // are correct and a trustline exists between them.
91  //
92  // Must now explicitly check the balance to make sure
93  // available balance is non-zero.
94  //
95  // We can't directly check the balance of trustline because
96  // the available balance of a trustline is prone to new changes (eg.
97  // XLS-34). So we must use `accountHolds`.
98  if (accountHolds(
99  ctx.view,
100  holder,
101  clawAmount.getCurrency(),
102  issuer,
104  ctx.j) <= beast::zero)
105  return tecINSUFFICIENT_FUNDS;
106 
107  return tesSUCCESS;
108 }
109 
110 TER
112 {
113  AccountID const& issuer = account_;
114  STAmount clawAmount = ctx_.tx[sfAmount];
115  AccountID const holder = clawAmount.getIssuer(); // cannot be reference
116 
117  // Replace the `issuer` field with issuer's account
118  clawAmount.setIssuer(issuer);
119  if (holder == issuer)
120  return tecINTERNAL;
121 
122  // Get the spendable balance. Must use `accountHolds`.
123  STAmount const spendableAmount = accountHolds(
124  view(),
125  holder,
126  clawAmount.getCurrency(),
127  clawAmount.getIssuer(),
129  j_);
130 
131  return rippleCredit(
132  view(),
133  holder,
134  issuer,
135  std::min(spendableAmount, clawAmount),
136  true,
137  j_);
138 }
139 
140 } // 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:967
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:130
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:604
ripple::tecINSUFFICIENT_FUNDS
@ tecINSUFFICIENT_FUNDS
Definition: TER.h:295
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:243
ripple::tfClawbackMask
constexpr const std::uint32_t tfClawbackMask
Definition: TxFlags.h:164
ripple::STAmount::setIssuer
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:433
ripple::lsfAllowTrustLineClawback
@ lsfAllowTrustLineClawback
Definition: LedgerFormats.h:253
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:78
ripple::STAmount::getIssuer
AccountID const & getIssuer() const
Definition: STAmount.h:359
ripple::base_uint< 160, detail::AccountIDTag >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
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:134
ripple::TERSubset< CanCvtToTER >
ripple::STAmount
Definition: STAmount.h:45
ripple::tecINTERNAL
@ tecINTERNAL
Definition: TER.h:280
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:481
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:87
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:194
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:200
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:271
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:112
ripple::lsfNoFreeze
@ lsfNoFreeze
Definition: LedgerFormats.h:236
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:275
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:78
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::Clawback::doApply
TER doApply() override
Definition: Clawback.cpp:111
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:353
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:225
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::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:535