rippled
Loading...
Searching...
No Matches
VaultDelete.cpp
1#include <xrpl/ledger/View.h>
2#include <xrpl/ledger/helpers/AccountRootHelpers.h>
3#include <xrpl/ledger/helpers/MPTokenHelpers.h>
4#include <xrpl/ledger/helpers/TokenHelpers.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/MPTIssue.h>
7#include <xrpl/protocol/STNumber.h>
8#include <xrpl/protocol/STTakesAsset.h>
9#include <xrpl/protocol/TER.h>
10#include <xrpl/protocol/TxFlags.h>
11#include <xrpl/tx/transactors/vault/VaultDelete.h>
12
13namespace xrpl {
14
17{
18 if (ctx.tx[sfVaultID] == beast::zero)
19 {
20 JLOG(ctx.j.debug()) << "VaultDelete: zero/empty vault ID.";
21 return temMALFORMED;
22 }
23
24 return tesSUCCESS;
25}
26
27TER
29{
30 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
31 if (!vault)
32 return tecNO_ENTRY;
33
34 if (vault->at(sfOwner) != ctx.tx[sfAccount])
35 {
36 JLOG(ctx.j.debug()) << "VaultDelete: account is not an owner.";
37 return tecNO_PERMISSION;
38 }
39
40 if (vault->at(sfAssetsAvailable) != 0)
41 {
42 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets available.";
43 return tecHAS_OBLIGATIONS;
44 }
45
46 if (vault->at(sfAssetsTotal) != 0)
47 {
48 JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets total.";
49 return tecHAS_OBLIGATIONS;
50 }
51
52 // Verify we can destroy MPTokenIssuance
53 auto const sleMPT = ctx.view.read(keylet::mptIssuance(vault->at(sfShareMPTID)));
54
55 if (!sleMPT)
56 {
57 // LCOV_EXCL_START
58 JLOG(ctx.j.error()) << "VaultDelete: missing issuance of vault shares.";
60 // LCOV_EXCL_STOP
61 }
62
63 if (sleMPT->at(sfIssuer) != vault->getAccountID(sfAccount))
64 {
65 // LCOV_EXCL_START
66 JLOG(ctx.j.error()) << "VaultDelete: invalid owner of vault shares.";
67 return tecNO_PERMISSION;
68 // LCOV_EXCL_STOP
69 }
70
71 if (sleMPT->at(sfOutstandingAmount) != 0)
72 {
73 JLOG(ctx.j.debug()) << "VaultDelete: nonzero outstanding shares.";
74 return tecHAS_OBLIGATIONS;
75 }
76
77 return tesSUCCESS;
78}
79
80TER
82{
83 auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
84 if (!vault)
85 return tefINTERNAL; // LCOV_EXCL_LINE
86
87 // Destroy the asset holding.
88 auto asset = vault->at(sfAsset);
89
90 if (auto ter = removeEmptyHolding(view(), vault->at(sfAccount), asset, j_); !isTesSuccess(ter))
91 return ter;
92
93 auto const& pseudoID = vault->at(sfAccount);
94 auto const pseudoAcct = view().peek(keylet::account(pseudoID));
95 if (!pseudoAcct)
96 {
97 // LCOV_EXCL_START
98 JLOG(j_.error()) << "VaultDelete: missing vault pseudo-account.";
99 return tefBAD_LEDGER;
100 // LCOV_EXCL_STOP
101 }
102
103 // Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
104 // no special logic needed. First run few checks, duplicated from preclaim.
105 auto const shareMPTID = *vault->at(sfShareMPTID);
106 auto const mpt = view().peek(keylet::mptIssuance(shareMPTID));
107 if (!mpt)
108 {
109 // LCOV_EXCL_START
110 JLOG(j_.error()) << "VaultDelete: missing issuance of vault shares.";
111 return tefINTERNAL;
112 // LCOV_EXCL_STOP
113 }
114
115 // Try to remove MPToken for vault shares for the vault owner if it exists.
116 if (auto const mptoken = view().peek(keylet::mptoken(shareMPTID, account_)))
117 {
118 if (auto const ter = removeEmptyHolding(view(), account_, MPTIssue(shareMPTID), j_);
119 !isTesSuccess(ter))
120 {
121 // LCOV_EXCL_START
122 JLOG(j_.error()) //
123 << "VaultDelete: failed to remove vault owner's MPToken"
124 << " MPTID=" << to_string(shareMPTID) //
125 << " account=" << toBase58(account_) //
126 << " with result: " << transToken(ter);
127 return ter;
128 // LCOV_EXCL_STOP
129 }
130 }
131
132 if (!view().dirRemove(keylet::ownerDir(pseudoID), (*mpt)[sfOwnerNode], mpt->key(), false))
133 {
134 // LCOV_EXCL_START
135 JLOG(j_.error()) << "VaultDelete: failed to delete issuance object.";
136 return tefBAD_LEDGER;
137 // LCOV_EXCL_STOP
138 }
139 adjustOwnerCount(view(), pseudoAcct, -1, j_);
140
141 view().erase(mpt);
142
143 // The pseudo-account's directory should have been deleted already.
144 if (view().peek(keylet::ownerDir(pseudoID)))
145 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
146
147 // Destroy the pseudo-account.
148 auto vaultPseudoSLE = view().peek(keylet::account(pseudoID));
149 if (!vaultPseudoSLE || vaultPseudoSLE->at(~sfVaultID) != vault->key())
150 return tefBAD_LEDGER; // LCOV_EXCL_LINE
151
152 // Making the payment and removing the empty holding should have deleted any
153 // obligations associated with the vault or vault pseudo-account.
154 if (*vaultPseudoSLE->at(sfBalance))
155 {
156 // LCOV_EXCL_START
157 JLOG(j_.error()) << "VaultDelete: pseudo-account has a balance";
158 return tecHAS_OBLIGATIONS;
159 // LCOV_EXCL_STOP
160 }
161 if (vaultPseudoSLE->at(sfOwnerCount) != 0)
162 {
163 // LCOV_EXCL_START
164 JLOG(j_.error()) << "VaultDelete: pseudo-account still owns objects";
165 return tecHAS_OBLIGATIONS;
166 // LCOV_EXCL_STOP
167 }
168 if (view().exists(keylet::ownerDir(pseudoID)))
169 {
170 // LCOV_EXCL_START
171 JLOG(j_.error()) << "VaultDelete: pseudo-account has a directory";
172 return tecHAS_OBLIGATIONS;
173 // LCOV_EXCL_STOP
174 }
175
176 view().erase(vaultPseudoSLE);
177
178 // Remove the vault from its owner's directory.
179 auto const ownerID = vault->at(sfOwner);
180 if (!view().dirRemove(keylet::ownerDir(ownerID), vault->at(sfOwnerNode), vault->key(), false))
181 {
182 // LCOV_EXCL_START
183 JLOG(j_.error()) << "VaultDelete: failed to delete vault object.";
184 return tefBAD_LEDGER;
185 // LCOV_EXCL_STOP
186 }
187
188 auto const owner = view().peek(keylet::account(ownerID));
189 if (!owner)
190 {
191 // LCOV_EXCL_START
192 JLOG(j_.error()) << "VaultDelete: missing vault owner account.";
193 return tefBAD_LEDGER;
194 // LCOV_EXCL_STOP
195 }
196
197 // We are destroying Vault and PseudoAccount, hence decrease by 2
198 adjustOwnerCount(view(), owner, -2, j_);
199
200 // Destroy the vault.
201 view().erase(vault);
202
203 return tesSUCCESS;
204}
205
206} // namespace xrpl
Stream error() const
Definition Journal.h:319
Stream debug() const
Definition Journal.h:301
STTx const & tx
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
AccountID const account_
Definition Transactor.h:116
beast::Journal const j_
Definition Transactor.h:114
ApplyView & view()
Definition Transactor.h:132
ApplyContext & ctx_
Definition Transactor.h:112
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
TER doApply() override
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:336
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:474
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:504
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:486
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
@ tefBAD_LEDGER
Definition TER.h:150
@ tefINTERNAL
Definition TER.h:153
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
std::string transToken(TER code)
Definition TER.cpp:243
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
@ temMALFORMED
Definition TER.h:67
bool isTesSuccess(TER x) noexcept
Definition TER.h:651
@ tecNO_ENTRY
Definition TER.h:287
@ tecOBJECT_NOT_FOUND
Definition TER.h:307
@ tecNO_PERMISSION
Definition TER.h:286
@ tecHAS_OBLIGATIONS
Definition TER.h:298
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:582
@ tesSUCCESS
Definition TER.h:225
uint256 key
Definition Keylet.h:20
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:57
ReadView const & view
Definition Transactor.h:60
beast::Journal const j
Definition Transactor.h:65
State information when preflighting a tx.
Definition Transactor.h:14
beast::Journal const j
Definition Transactor.h:21