rippled
Loading...
Searching...
No Matches
VaultDelete.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2025 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/tx/detail/VaultDelete.h>
21
22#include <xrpl/ledger/View.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/MPTIssue.h>
25#include <xrpl/protocol/STNumber.h>
26#include <xrpl/protocol/TER.h>
27#include <xrpl/protocol/TxFlags.h>
28
29namespace ripple {
30
33{
34 if (!ctx.rules.enabled(featureSingleAssetVault))
35 return temDISABLED;
36
37 if (auto const ter = preflight1(ctx))
38 return ter;
39
40 if (ctx.tx.getFlags() & tfUniversalMask)
41 return temINVALID_FLAG;
42
43 if (ctx.tx[sfVaultID] == beast::zero)
44 {
45 JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID.";
46 return temMALFORMED;
47 }
48
49 return preflight2(ctx);
50}
51
52TER
54{
55 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
56 if (!vault)
57 return tecNO_ENTRY;
58
59 if (vault->at(sfOwner) != ctx.tx[sfAccount])
60 {
61 JLOG(ctx.j.debug()) << "VaultDelete: account is not an owner.";
62 return tecNO_PERMISSION;
63 }
64
65 if (vault->at(sfAssetsAvailable) != 0)
66 {
67 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets available.";
68 return tecHAS_OBLIGATIONS;
69 }
70
71 if (vault->at(sfAssetsTotal) != 0)
72 {
73 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets total.";
74 return tecHAS_OBLIGATIONS;
75 }
76
77 // Verify we can destroy MPTokenIssuance
78 auto const sleMPT =
79 ctx.view.read(keylet::mptIssuance(vault->at(sfShareMPTID)));
80
81 if (!sleMPT)
82 {
83 // LCOV_EXCL_START
84 JLOG(ctx.j.error())
85 << "VaultDeposit: missing issuance of vault shares.";
87 // LCOV_EXCL_STOP
88 }
89
90 if (sleMPT->at(sfIssuer) != vault->getAccountID(sfAccount))
91 {
92 // LCOV_EXCL_START
93 JLOG(ctx.j.error()) << "VaultDeposit: invalid owner of vault shares.";
94 return tecNO_PERMISSION;
95 // LCOV_EXCL_STOP
96 }
97
98 if (sleMPT->at(sfOutstandingAmount) != 0)
99 {
100 JLOG(ctx.j.debug()) << "VaultDelete: nonzero outstanding shares.";
101 return tecHAS_OBLIGATIONS;
102 }
103
104 return tesSUCCESS;
105}
106
107TER
109{
110 auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
111 if (!vault)
112 return tefINTERNAL; // LCOV_EXCL_LINE
113
114 // Destroy the asset holding.
115 auto asset = vault->at(sfAsset);
116 if (auto ter = removeEmptyHolding(view(), vault->at(sfAccount), asset, j_);
117 !isTesSuccess(ter))
118 return ter;
119
120 auto const& pseudoID = vault->at(sfAccount);
121 auto const pseudoAcct = view().peek(keylet::account(pseudoID));
122 if (!pseudoAcct)
123 {
124 // LCOV_EXCL_START
125 JLOG(j_.error()) << "VaultDelete: missing vault pseudo-account.";
126 return tefBAD_LEDGER;
127 // LCOV_EXCL_STOP
128 }
129
130 // Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
131 // no special logic needed. First run few checks, duplicated from preclaim.
132 auto const shareMPTID = *vault->at(sfShareMPTID);
133 auto const mpt = view().peek(keylet::mptIssuance(shareMPTID));
134 if (!mpt)
135 {
136 // LCOV_EXCL_START
137 JLOG(j_.error()) << "VaultDelete: missing issuance of vault shares.";
138 return tefINTERNAL;
139 // LCOV_EXCL_STOP
140 }
141
142 // Try to remove MPToken for vault shares for the vault owner if it exists.
143 if (auto const mptoken = view().peek(keylet::mptoken(shareMPTID, account_)))
144 {
145 if (auto const ter =
146 removeEmptyHolding(view(), account_, MPTIssue(shareMPTID), j_);
147 !isTesSuccess(ter))
148 {
149 // LCOV_EXCL_START
150 JLOG(j_.error()) //
151 << "VaultDelete: failed to remove vault owner's MPToken"
152 << " MPTID=" << to_string(shareMPTID) //
153 << " account=" << toBase58(account_) //
154 << " with result: " << transToken(ter);
155 return ter;
156 // LCOV_EXCL_STOP
157 }
158 }
159
160 if (!view().dirRemove(
161 keylet::ownerDir(pseudoID), (*mpt)[sfOwnerNode], mpt->key(), false))
162 {
163 // LCOV_EXCL_START
164 JLOG(j_.error()) << "VaultDelete: failed to delete issuance object.";
165 return tefBAD_LEDGER;
166 // LCOV_EXCL_STOP
167 }
168 adjustOwnerCount(view(), pseudoAcct, -1, j_);
169
170 view().erase(mpt);
171
172 // The pseudo-account's directory should have been deleted already.
173 if (view().peek(keylet::ownerDir(pseudoID)))
174 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
175
176 // Destroy the pseudo-account.
177 view().erase(view().peek(keylet::account(pseudoID)));
178
179 // Remove the vault from its owner's directory.
180 auto const ownerID = vault->at(sfOwner);
181 if (!view().dirRemove(
182 keylet::ownerDir(ownerID),
183 vault->at(sfOwnerNode),
184 vault->key(),
185 false))
186 {
187 // LCOV_EXCL_START
188 JLOG(j_.error()) << "VaultDelete: failed to delete vault object.";
189 return tefBAD_LEDGER;
190 // LCOV_EXCL_STOP
191 }
192
193 auto const owner = view().peek(keylet::account(ownerID));
194 if (!owner)
195 {
196 // LCOV_EXCL_START
197 JLOG(j_.error()) << "VaultDelete: missing vault owner account.";
198 return tefBAD_LEDGER;
199 // LCOV_EXCL_STOP
200 }
201 adjustOwnerCount(view(), owner, -1, j_);
202
203 // Destroy the vault.
204 view().erase(vault);
205
206 return tesSUCCESS;
207}
208
209} // namespace ripple
Stream error() const
Definition Journal.h:346
Stream debug() const
Definition Journal.h:328
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
virtual std::shared_ptr< SLE const > 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:130
std::uint32_t getFlags() const
Definition STObject.cpp:537
AccountID const account_
Definition Transactor.h:145
ApplyView & view()
Definition Transactor.h:161
beast::Journal const j_
Definition Transactor.h:143
ApplyContext & ctx_
Definition Transactor.h:141
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
TER doApply() override
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:540
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:526
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:564
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:374
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
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:1029
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
@ tefBAD_LEDGER
Definition TER.h:170
@ tefINTERNAL
Definition TER.h:173
std::string transToken(TER code)
Definition TER.cpp:264
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
@ tecNO_ENTRY
Definition TER.h:306
@ tecOBJECT_NOT_FOUND
Definition TER.h:326
@ tecNO_PERMISSION
Definition TER.h:305
@ tecHAS_OBLIGATIONS
Definition TER.h:317
@ tesSUCCESS
Definition TER.h:244
bool isTesSuccess(TER x) noexcept
Definition TER.h:674
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
constexpr std::uint32_t tfUniversalMask
Definition TxFlags.h:63
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, Issue const &issue, beast::Journal journal)
Definition View.cpp:1508
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:605
@ temMALFORMED
Definition TER.h:87
@ temINVALID_FLAG
Definition TER.h:111
@ temDISABLED
Definition TER.h:114
uint256 key
Definition Keylet.h:40
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