xrpld
Loading...
Searching...
No Matches
VaultDelete.cpp
1#include <xrpl/tx/transactors/vault/VaultDelete.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/MPTokenHelpers.h>
8#include <xrpl/ledger/helpers/TokenHelpers.h>
9#include <xrpl/protocol/AccountID.h>
10#include <xrpl/protocol/Feature.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/MPTIssue.h>
13#include <xrpl/protocol/Protocol.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STLedgerEntry.h>
16#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
17#include <xrpl/protocol/STTx.h>
18#include <xrpl/protocol/TER.h>
19#include <xrpl/protocol/XRPAmount.h>
20#include <xrpl/tx/Transactor.h>
21
22namespace xrpl {
23
26{
27 if (ctx.tx[sfVaultID] == beast::kZero)
28 {
29 JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID.";
30 return temMALFORMED;
31 }
32
33 if (ctx.tx.isFieldPresent(sfMemoData) && !ctx.rules.enabled(featureLendingProtocolV1_1))
34 return temDISABLED;
35
36 if (!validDataLength(ctx.tx[~sfMemoData], kMaxDataPayloadLength))
37 return temMALFORMED;
38
39 return tesSUCCESS;
40}
41
42TER
44{
45 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
46 if (!vault)
47 return tecNO_ENTRY;
48
49 if (vault->at(sfOwner) != ctx.tx[sfAccount])
50 {
51 JLOG(ctx.j.debug()) << "VaultDelete: account is not an owner.";
52 return tecNO_PERMISSION;
53 }
54
55 if (vault->at(sfAssetsAvailable) != 0)
56 {
57 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets available.";
58 return tecHAS_OBLIGATIONS;
59 }
60
61 if (vault->at(sfAssetsTotal) != 0)
62 {
63 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets total.";
64 return tecHAS_OBLIGATIONS;
65 }
66
67 // Verify we can destroy MPTokenIssuance
68 auto const sleMPT = ctx.view.read(keylet::mptokenIssuance(vault->at(sfShareMPTID)));
69
70 if (!sleMPT)
71 {
72 // LCOV_EXCL_START
73 JLOG(ctx.j.error()) << "VaultDelete: missing issuance of vault shares.";
75 // LCOV_EXCL_STOP
76 }
77
78 if (sleMPT->at(sfIssuer) != vault->getAccountID(sfAccount))
79 {
80 // LCOV_EXCL_START
81 JLOG(ctx.j.error()) << "VaultDelete: invalid owner of vault shares.";
82 return tecNO_PERMISSION;
83 // LCOV_EXCL_STOP
84 }
85
86 if (sleMPT->at(sfOutstandingAmount) != 0)
87 {
88 JLOG(ctx.j.debug()) << "VaultDelete: nonzero outstanding shares.";
89 return tecHAS_OBLIGATIONS;
90 }
91
92 return tesSUCCESS;
93}
94
95TER
97{
98 auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
99 auto applyViewContext = ctx_.getApplyViewContext();
100 if (!vault)
101 return tefINTERNAL; // LCOV_EXCL_LINE
102
103 // Destroy the asset holding.
104 auto asset = vault->at(sfAsset);
105
106 if (auto ter = removeEmptyHolding(applyViewContext, vault->at(sfAccount), asset, j_);
107 !isTesSuccess(ter))
108 return ter;
109
110 auto const& pseudoID = vault->at(sfAccount);
111 auto const pseudoAcct = view().peek(keylet::account(pseudoID));
112 if (!pseudoAcct)
113 {
114 // LCOV_EXCL_START
115 JLOG(j_.error()) << "VaultDelete: missing vault pseudo-account.";
116 return tefBAD_LEDGER;
117 // LCOV_EXCL_STOP
118 }
119
120 // Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
121 // no special logic needed. First run few checks, duplicated from preclaim.
122 auto const shareMPTID = *vault->at(sfShareMPTID);
123 auto const mpt = view().peek(keylet::mptokenIssuance(shareMPTID));
124 if (!mpt)
125 {
126 // LCOV_EXCL_START
127 JLOG(j_.error()) << "VaultDelete: missing issuance of vault shares.";
128 return tefINTERNAL;
129 // LCOV_EXCL_STOP
130 }
131
132 // Try to remove MPToken for vault shares for the vault owner if it exists.
133 if (auto const mptoken = view().peek(keylet::mptoken(shareMPTID, accountID_)))
134 {
135 if (auto const ter =
136 removeEmptyHolding(applyViewContext, accountID_, MPTIssue(shareMPTID), j_);
137 !isTesSuccess(ter))
138 {
139 // LCOV_EXCL_START
140 JLOG(j_.error()) //
141 << "VaultDelete: failed to remove vault owner's MPToken"
142 << " MPTID=" << to_string(shareMPTID) //
143 << " account=" << toBase58(accountID_) //
144 << " with result: " << transToken(ter);
145 return ter;
146 // LCOV_EXCL_STOP
147 }
148 }
149
150 if (!view().dirRemove(keylet::ownerDir(pseudoID), (*mpt)[sfOwnerNode], mpt->key(), false))
151 {
152 // LCOV_EXCL_START
153 JLOG(j_.error()) << "VaultDelete: failed to delete issuance object.";
154 return tefBAD_LEDGER;
155 // LCOV_EXCL_STOP
156 }
157 decreaseOwnerCountForObject(view(), pseudoAcct, mpt, 1, j_);
158
159 view().erase(mpt);
160
161 // The pseudo-account's directory should have been deleted already.
162 if (view().peek(keylet::ownerDir(pseudoID)))
163 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
164
165 // Destroy the pseudo-account.
166 auto vaultPseudoSLE = view().peek(keylet::account(pseudoID));
167 if (!vaultPseudoSLE || vaultPseudoSLE->at(~sfVaultID) != vault->key())
168 return tefBAD_LEDGER; // LCOV_EXCL_LINE
169
170 // Making the payment and removing the empty holding should have deleted any
171 // obligations associated with the vault or vault pseudo-account.
172 if (*vaultPseudoSLE->at(sfBalance))
173 {
174 // LCOV_EXCL_START
175 JLOG(j_.error()) << "VaultDelete: pseudo-account has a balance";
176 return tecHAS_OBLIGATIONS;
177 // LCOV_EXCL_STOP
178 }
179 if (vaultPseudoSLE->at(sfOwnerCount) != 0)
180 {
181 // LCOV_EXCL_START
182 JLOG(j_.error()) << "VaultDelete: pseudo-account still owns objects";
183 return tecHAS_OBLIGATIONS;
184 // LCOV_EXCL_STOP
185 }
186 if (view().exists(keylet::ownerDir(pseudoID)))
187 {
188 // LCOV_EXCL_START
189 JLOG(j_.error()) << "VaultDelete: pseudo-account has a directory";
190 return tecHAS_OBLIGATIONS;
191 // LCOV_EXCL_STOP
192 }
193
194 view().erase(vaultPseudoSLE);
195
196 // Remove the vault from its owner's directory.
197 auto const ownerID = vault->at(sfOwner);
198 if (!view().dirRemove(keylet::ownerDir(ownerID), vault->at(sfOwnerNode), vault->key(), false))
199 {
200 // LCOV_EXCL_START
201 JLOG(j_.error()) << "VaultDelete: failed to delete vault object.";
202 return tefBAD_LEDGER;
203 // LCOV_EXCL_STOP
204 }
205
206 auto const owner = view().peek(keylet::account(ownerID));
207 if (!owner)
208 {
209 // LCOV_EXCL_START
210 JLOG(j_.error()) << "VaultDelete: missing vault owner account.";
211 return tefBAD_LEDGER;
212 // LCOV_EXCL_STOP
213 }
214
215 // We are destroying Vault and PseudoAccount, hence decrease by 2
216 decreaseOwnerCountForObject(view(), owner, vault, 2, j_);
217
218 // Destroy the vault.
219 view().erase(vault);
220
221 return tesSUCCESS;
222}
223
224void
226{
227 // No transaction-specific invariants yet (future work).
228}
229
230bool
232{
233 // No transaction-specific invariants yet (future work).
234 return true;
235}
236
237} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream error() const
Definition Journal.h:362
Stream debug() const
Definition Journal.h:344
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(SLE::ref sle)=0
Remove a peeked SLE.
A view into a ledger.
Definition ReadView.h:41
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:180
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
beast::Journal const j_
Definition Transactor.h:155
ApplyView & view()
Definition Transactor.h:175
AccountID const accountID_
Definition Transactor.h:157
static bool validDataLength(std::optional< Slice > const &slice, std::size_t maxLength)
ApplyContext & ctx_
Definition Transactor.h:153
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
TER doApply() override
constexpr Zero kZero
Definition Zero.h:30
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:373
Keylet vault(AccountID const &owner, SeqProxy const &seq) noexcept
Definition Indexes.cpp:561
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:543
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Definition Indexes.cpp:537
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void decreaseOwnerCountForObject(ApplyView &view, SLE::ref accountSle, SLE::ref objectSle, std::uint32_t count, beast::Journal j)
Decrease owner-count fields for an existing ledger object.
TER removeEmptyHolding(ApplyViewContext ctx, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
@ tefBAD_LEDGER
Definition TER.h:162
@ tefINTERNAL
Definition TER.h:165
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::string transToken(TER code)
Definition TER.cpp:251
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
constexpr std::size_t kMaxDataPayloadLength
The maximum length of Data payload.
Definition Protocol.h:302
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:607
@ temMALFORMED
Definition TER.h:75
@ temDISABLED
Definition TER.h:102
bool isTesSuccess(TER x) noexcept
Definition TER.h:676
TERSubset< CanCvtToTER > TER
Definition TER.h:647
@ tecNO_ENTRY
Definition TER.h:309
@ tecOBJECT_NOT_FOUND
Definition TER.h:329
@ tecNO_PERMISSION
Definition TER.h:308
@ tecHAS_OBLIGATIONS
Definition TER.h:320
@ tesSUCCESS
Definition TER.h:245
uint256 key
Definition Keylet.h:21
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:83
ReadView const & view
Definition Transactor.h:86
beast::Journal const j
Definition Transactor.h:91
State information when preflighting a tx.
Definition Transactor.h:38
beast::Journal const j
Definition Transactor.h:45