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/Indexes.h>
11#include <xrpl/protocol/MPTIssue.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/STLedgerEntry.h>
14#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
15#include <xrpl/protocol/STTx.h>
16#include <xrpl/protocol/TER.h>
17#include <xrpl/protocol/XRPAmount.h>
18#include <xrpl/tx/Transactor.h>
19
20namespace xrpl {
21
24{
25 if (ctx.tx[sfVaultID] == beast::kZero)
26 {
27 JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID.";
28 return temMALFORMED;
29 }
30
31 return tesSUCCESS;
32}
33
34TER
36{
37 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
38 if (!vault)
39 return tecNO_ENTRY;
40
41 if (vault->at(sfOwner) != ctx.tx[sfAccount])
42 {
43 JLOG(ctx.j.debug()) << "VaultDelete: account is not an owner.";
44 return tecNO_PERMISSION;
45 }
46
47 if (vault->at(sfAssetsAvailable) != 0)
48 {
49 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets available.";
50 return tecHAS_OBLIGATIONS;
51 }
52
53 if (vault->at(sfAssetsTotal) != 0)
54 {
55 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets total.";
56 return tecHAS_OBLIGATIONS;
57 }
58
59 // Verify we can destroy MPTokenIssuance
60 auto const sleMPT = ctx.view.read(keylet::mptokenIssuance(vault->at(sfShareMPTID)));
61
62 if (!sleMPT)
63 {
64 // LCOV_EXCL_START
65 JLOG(ctx.j.error()) << "VaultDelete: missing issuance of vault shares.";
67 // LCOV_EXCL_STOP
68 }
69
70 if (sleMPT->at(sfIssuer) != vault->getAccountID(sfAccount))
71 {
72 // LCOV_EXCL_START
73 JLOG(ctx.j.error()) << "VaultDelete: invalid owner of vault shares.";
74 return tecNO_PERMISSION;
75 // LCOV_EXCL_STOP
76 }
77
78 if (sleMPT->at(sfOutstandingAmount) != 0)
79 {
80 JLOG(ctx.j.debug()) << "VaultDelete: nonzero outstanding shares.";
81 return tecHAS_OBLIGATIONS;
82 }
83
84 return tesSUCCESS;
85}
86
87TER
89{
90 auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
91 if (!vault)
92 return tefINTERNAL; // LCOV_EXCL_LINE
93
94 // Destroy the asset holding.
95 auto asset = vault->at(sfAsset);
96
97 if (auto ter = removeEmptyHolding(view(), vault->at(sfAccount), asset, j_); !isTesSuccess(ter))
98 return ter;
99
100 auto const& pseudoID = vault->at(sfAccount);
101 auto const pseudoAcct = view().peek(keylet::account(pseudoID));
102 if (!pseudoAcct)
103 {
104 // LCOV_EXCL_START
105 JLOG(j_.error()) << "VaultDelete: missing vault pseudo-account.";
106 return tefBAD_LEDGER;
107 // LCOV_EXCL_STOP
108 }
109
110 // Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
111 // no special logic needed. First run few checks, duplicated from preclaim.
112 auto const shareMPTID = *vault->at(sfShareMPTID);
113 auto const mpt = view().peek(keylet::mptokenIssuance(shareMPTID));
114 if (!mpt)
115 {
116 // LCOV_EXCL_START
117 JLOG(j_.error()) << "VaultDelete: missing issuance of vault shares.";
118 return tefINTERNAL;
119 // LCOV_EXCL_STOP
120 }
121
122 // Try to remove MPToken for vault shares for the vault owner if it exists.
123 if (auto const mptoken = view().peek(keylet::mptoken(shareMPTID, accountID_)))
124 {
125 if (auto const ter = removeEmptyHolding(view(), accountID_, MPTIssue(shareMPTID), j_);
126 !isTesSuccess(ter))
127 {
128 // LCOV_EXCL_START
129 JLOG(j_.error()) //
130 << "VaultDelete: failed to remove vault owner's MPToken"
131 << " MPTID=" << to_string(shareMPTID) //
132 << " account=" << toBase58(accountID_) //
133 << " with result: " << transToken(ter);
134 return ter;
135 // LCOV_EXCL_STOP
136 }
137 }
138
139 if (!view().dirRemove(keylet::ownerDir(pseudoID), (*mpt)[sfOwnerNode], mpt->key(), false))
140 {
141 // LCOV_EXCL_START
142 JLOG(j_.error()) << "VaultDelete: failed to delete issuance object.";
143 return tefBAD_LEDGER;
144 // LCOV_EXCL_STOP
145 }
146 adjustOwnerCount(view(), pseudoAcct, -1, j_);
147
148 view().erase(mpt);
149
150 // The pseudo-account's directory should have been deleted already.
151 if (view().peek(keylet::ownerDir(pseudoID)))
152 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
153
154 // Destroy the pseudo-account.
155 auto vaultPseudoSLE = view().peek(keylet::account(pseudoID));
156 if (!vaultPseudoSLE || vaultPseudoSLE->at(~sfVaultID) != vault->key())
157 return tefBAD_LEDGER; // LCOV_EXCL_LINE
158
159 // Making the payment and removing the empty holding should have deleted any
160 // obligations associated with the vault or vault pseudo-account.
161 if (*vaultPseudoSLE->at(sfBalance))
162 {
163 // LCOV_EXCL_START
164 JLOG(j_.error()) << "VaultDelete: pseudo-account has a balance";
165 return tecHAS_OBLIGATIONS;
166 // LCOV_EXCL_STOP
167 }
168 if (vaultPseudoSLE->at(sfOwnerCount) != 0)
169 {
170 // LCOV_EXCL_START
171 JLOG(j_.error()) << "VaultDelete: pseudo-account still owns objects";
172 return tecHAS_OBLIGATIONS;
173 // LCOV_EXCL_STOP
174 }
175 if (view().exists(keylet::ownerDir(pseudoID)))
176 {
177 // LCOV_EXCL_START
178 JLOG(j_.error()) << "VaultDelete: pseudo-account has a directory";
179 return tecHAS_OBLIGATIONS;
180 // LCOV_EXCL_STOP
181 }
182
183 view().erase(vaultPseudoSLE);
184
185 // Remove the vault from its owner's directory.
186 auto const ownerID = vault->at(sfOwner);
187 if (!view().dirRemove(keylet::ownerDir(ownerID), vault->at(sfOwnerNode), vault->key(), false))
188 {
189 // LCOV_EXCL_START
190 JLOG(j_.error()) << "VaultDelete: failed to delete vault object.";
191 return tefBAD_LEDGER;
192 // LCOV_EXCL_STOP
193 }
194
195 auto const owner = view().peek(keylet::account(ownerID));
196 if (!owner)
197 {
198 // LCOV_EXCL_START
199 JLOG(j_.error()) << "VaultDelete: missing vault owner account.";
200 return tefBAD_LEDGER;
201 // LCOV_EXCL_STOP
202 }
203
204 // We are destroying Vault and PseudoAccount, hence decrease by 2
205 adjustOwnerCount(view(), owner, -2, j_);
206
207 // Destroy the vault.
208 view().erase(vault);
209
210 return tesSUCCESS;
211}
212
213void
215{
216 // No transaction-specific invariants yet (future work).
217}
218
219bool
221{
222 // No transaction-specific invariants yet (future work).
223 return true;
224}
225
226} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream error() const
Definition Journal.h:315
Stream debug() const
Definition Journal.h:297
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:31
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::shared_ptr< STLedgerEntry const > const & const_ref
beast::Journal const j_
Definition Transactor.h:118
ApplyView & view()
Definition Transactor.h:136
AccountID const accountID_
Definition Transactor.h:120
ApplyContext & ctx_
Definition Transactor.h:116
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
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:521
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:357
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:551
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:533
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ tefBAD_LEDGER
Definition TER.h:160
@ tefINTERNAL
Definition TER.h:163
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
std::string transToken(TER code)
Definition TER.cpp:247
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
@ temMALFORMED
Definition TER.h:73
bool isTesSuccess(TER x) noexcept
Definition TER.h:663
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecNO_ENTRY
Definition TER.h:304
@ tecOBJECT_NOT_FOUND
Definition TER.h:324
@ tecNO_PERMISSION
Definition TER.h:303
@ tecHAS_OBLIGATIONS
Definition TER.h:315
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
@ tesSUCCESS
Definition TER.h:240
uint256 key
Definition Keylet.h:20
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
beast::Journal const j
Definition Transactor.h:69
State information when preflighting a tx.
Definition Transactor.h:18
beast::Journal const j
Definition Transactor.h:25