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#include <xrpld/ledger/View.h>
22
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/STNumber.h>
25#include <xrpl/protocol/TER.h>
26#include <xrpl/protocol/TxFlags.h>
27
28namespace ripple {
29
32{
33 if (!ctx.rules.enabled(featureSingleAssetVault))
34 return temDISABLED;
35
36 if (auto const ter = preflight1(ctx))
37 return ter;
38
39 if (ctx.tx.getFlags() & tfUniversalMask)
40 return temINVALID_FLAG;
41
42 if (ctx.tx[sfVaultID] == beast::zero)
43 {
44 JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID.";
45 return temMALFORMED;
46 }
47
48 return preflight2(ctx);
49}
50
51TER
53{
54 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
55 if (!vault)
56 return tecNO_ENTRY;
57
58 if (vault->at(sfOwner) != ctx.tx[sfAccount])
59 {
60 JLOG(ctx.j.debug()) << "VaultDelete: account is not an owner.";
61 return tecNO_PERMISSION;
62 }
63
64 if (vault->at(sfAssetsAvailable) != 0)
65 {
66 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets available.";
67 return tecHAS_OBLIGATIONS;
68 }
69
70 if (vault->at(sfAssetsTotal) != 0)
71 {
72 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets total.";
73 return tecHAS_OBLIGATIONS;
74 }
75
76 // Verify we can destroy MPTokenIssuance
77 auto const sleMPT =
78 ctx.view.read(keylet::mptIssuance(vault->at(sfShareMPTID)));
79
80 if (!sleMPT)
81 {
82 // LCOV_EXCL_START
83 JLOG(ctx.j.error())
84 << "VaultDeposit: missing issuance of vault shares.";
86 // LCOV_EXCL_STOP
87 }
88
89 if (sleMPT->at(sfIssuer) != vault->getAccountID(sfAccount))
90 {
91 // LCOV_EXCL_START
92 JLOG(ctx.j.error()) << "VaultDeposit: invalid owner of vault shares.";
93 return tecNO_PERMISSION;
94 // LCOV_EXCL_STOP
95 }
96
97 if (sleMPT->at(sfOutstandingAmount) != 0)
98 {
99 JLOG(ctx.j.debug()) << "VaultDelete: nonzero outstanding shares.";
100 return tecHAS_OBLIGATIONS;
101 }
102
103 return tesSUCCESS;
104}
105
106TER
108{
109 auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
110 if (!vault)
111 return tefINTERNAL; // LCOV_EXCL_LINE
112
113 // Destroy the asset holding.
114 auto asset = vault->at(sfAsset);
115 if (auto ter = removeEmptyHolding(view(), vault->at(sfAccount), asset, j_);
116 !isTesSuccess(ter))
117 return ter;
118
119 auto const& pseudoID = vault->at(sfAccount);
120 auto const pseudoAcct = view().peek(keylet::account(pseudoID));
121 if (!pseudoAcct)
122 {
123 // LCOV_EXCL_START
124 JLOG(j_.error()) << "VaultDelete: missing vault pseudo-account.";
125 return tefBAD_LEDGER;
126 // LCOV_EXCL_STOP
127 }
128
129 // Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
130 // no special logic needed. First run few checks, duplicated from preclaim.
131 auto const mpt = view().peek(keylet::mptIssuance(vault->at(sfShareMPTID)));
132 if (!mpt)
133 {
134 // LCOV_EXCL_START
135 JLOG(j_.error()) << "VaultDelete: missing issuance of vault shares.";
136 return tefINTERNAL;
137 // LCOV_EXCL_STOP
138 }
139
140 if (!view().dirRemove(
141 keylet::ownerDir(pseudoID), (*mpt)[sfOwnerNode], mpt->key(), false))
142 {
143 // LCOV_EXCL_START
144 JLOG(j_.error()) << "VaultDelete: failed to delete issuance object.";
145 return tefBAD_LEDGER;
146 // LCOV_EXCL_STOP
147 }
148 adjustOwnerCount(view(), pseudoAcct, -1, j_);
149
150 view().erase(mpt);
151
152 // The pseudo-account's directory should have been deleted already.
153 if (view().peek(keylet::ownerDir(pseudoID)))
154 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
155
156 // Destroy the pseudo-account.
157 view().erase(view().peek(keylet::account(pseudoID)));
158
159 // Remove the vault from its owner's directory.
160 auto const ownerID = vault->at(sfOwner);
161 if (!view().dirRemove(
162 keylet::ownerDir(ownerID),
163 vault->at(sfOwnerNode),
164 vault->key(),
165 false))
166 {
167 // LCOV_EXCL_START
168 JLOG(j_.error()) << "VaultDelete: failed to delete vault object.";
169 return tefBAD_LEDGER;
170 // LCOV_EXCL_STOP
171 }
172
173 auto const owner = view().peek(keylet::account(ownerID));
174 if (!owner)
175 {
176 // LCOV_EXCL_START
177 JLOG(j_.error()) << "VaultDelete: missing vault owner account.";
178 return tefBAD_LEDGER;
179 // LCOV_EXCL_STOP
180 }
181 adjustOwnerCount(view(), owner, -1, j_);
182
183 // Destroy the vault.
184 view().erase(vault);
185
186 return tesSUCCESS;
187}
188
189} // 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
ApplyView & view()
Definition: Transactor.h:159
beast::Journal const j_
Definition: Transactor.h:141
ApplyContext & ctx_
Definition: Transactor.h:140
static NotTEC preflight(PreflightContext const &ctx)
Definition: VaultDelete.cpp:31
static TER preclaim(PreclaimContext const &ctx)
Definition: VaultDelete.cpp:52
TER doApply() override
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
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
@ tefBAD_LEDGER
Definition: TER.h:170
@ tefINTERNAL
Definition: TER.h:173
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:160
@ 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
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:1346
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:79
ReadView const & view
Definition: Transactor.h:82
beast::Journal const j
Definition: Transactor.h:87
State information when preflighting a tx.
Definition: Transactor.h:34
beast::Journal const j
Definition: Transactor.h:41