rippled
Loading...
Searching...
No Matches
VaultSet.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/VaultSet.h>
21
22#include <xrpl/ledger/View.h>
23#include <xrpl/protocol/Asset.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/Indexes.h>
26#include <xrpl/protocol/SField.h>
27#include <xrpl/protocol/STNumber.h>
28#include <xrpl/protocol/TER.h>
29#include <xrpl/protocol/TxFlags.h>
30
31namespace ripple {
32
33bool
35{
36 return !ctx.tx.isFieldPresent(sfDomainID) ||
37 ctx.rules.enabled(featurePermissionedDomains);
38}
39
42{
43 if (ctx.tx[sfVaultID] == beast::zero)
44 {
45 JLOG(ctx.j.debug()) << "VaultSet: zero/empty vault ID.";
46 return temMALFORMED;
47 }
48
49 if (auto const data = ctx.tx[~sfData])
50 {
51 if (data->empty() || data->length() > maxDataPayloadLength)
52 {
53 JLOG(ctx.j.debug()) << "VaultSet: invalid data payload size.";
54 return temMALFORMED;
55 }
56 }
57
58 if (auto const assetMax = ctx.tx[~sfAssetsMaximum])
59 {
60 if (*assetMax < beast::zero)
61 {
62 JLOG(ctx.j.debug()) << "VaultSet: invalid max assets.";
63 return temMALFORMED;
64 }
65 }
66
67 if (!ctx.tx.isFieldPresent(sfDomainID) &&
68 !ctx.tx.isFieldPresent(sfAssetsMaximum) &&
69 !ctx.tx.isFieldPresent(sfData))
70 {
71 JLOG(ctx.j.debug()) << "VaultSet: nothing is being updated.";
72 return temMALFORMED;
73 }
74
75 return tesSUCCESS;
76}
77
78TER
80{
81 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
82 if (!vault)
83 return tecNO_ENTRY;
84
85 // Assert that submitter is the Owner.
86 if (ctx.tx[sfAccount] != vault->at(sfOwner))
87 {
88 JLOG(ctx.j.debug()) << "VaultSet: account is not an owner.";
89 return tecNO_PERMISSION;
90 }
91
92 auto const mptIssuanceID = (*vault)[sfShareMPTID];
93 auto const sleIssuance = ctx.view.read(keylet::mptIssuance(mptIssuanceID));
94 if (!sleIssuance)
95 {
96 // LCOV_EXCL_START
97 JLOG(ctx.j.error()) << "VaultSet: missing issuance of vault shares.";
98 return tefINTERNAL;
99 // LCOV_EXCL_STOP
100 }
101
102 if (auto const domain = ctx.tx[~sfDomainID])
103 {
104 // We can only set domain if private flag was originally set
105 if (!vault->isFlag(lsfVaultPrivate))
106 {
107 JLOG(ctx.j.debug()) << "VaultSet: vault is not private";
108 return tecNO_PERMISSION;
109 }
110
111 if (*domain != beast::zero)
112 {
113 auto const sleDomain =
115 if (!sleDomain)
116 return tecOBJECT_NOT_FOUND;
117 }
118
119 // Sanity check only, this should be enforced by VaultCreate
120 if ((sleIssuance->getFlags() & lsfMPTRequireAuth) == 0)
121 {
122 // LCOV_EXCL_START
123 JLOG(ctx.j.error())
124 << "VaultSet: issuance of vault shares is not private.";
125 return tefINTERNAL;
126 // LCOV_EXCL_STOP
127 }
128 }
129
130 return tesSUCCESS;
131}
132
133TER
135{
136 // All return codes in `doApply` must be `tec`, `ter`, or `tes`.
137 // As we move checks into `preflight` and `preclaim`,
138 // we can consider downgrading them to `tef` or `tem`.
139
140 auto const& tx = ctx_.tx;
141
142 // Update existing object.
143 auto vault = view().peek(keylet::vault(tx[sfVaultID]));
144 if (!vault)
145 return tefINTERNAL; // LCOV_EXCL_LINE
146
147 auto const mptIssuanceID = (*vault)[sfShareMPTID];
148 auto const sleIssuance = view().peek(keylet::mptIssuance(mptIssuanceID));
149 if (!sleIssuance)
150 {
151 // LCOV_EXCL_START
152 JLOG(j_.error()) << "VaultSet: missing issuance of vault shares.";
153 return tefINTERNAL;
154 // LCOV_EXCL_STOP
155 }
156
157 // Update mutable flags and fields if given.
158 if (tx.isFieldPresent(sfData))
159 vault->at(sfData) = tx[sfData];
160 if (tx.isFieldPresent(sfAssetsMaximum))
161 {
162 if (tx[sfAssetsMaximum] != 0 &&
163 tx[sfAssetsMaximum] < *vault->at(sfAssetsTotal))
164 return tecLIMIT_EXCEEDED;
165 vault->at(sfAssetsMaximum) = tx[sfAssetsMaximum];
166 }
167
168 if (auto const domainId = tx[~sfDomainID]; domainId)
169 {
170 if (*domainId != beast::zero)
171 {
172 // In VaultSet::preclaim we enforce that lsfVaultPrivate must have
173 // been set in the vault. We currently do not support making such a
174 // vault public (i.e. removal of lsfVaultPrivate flag). The
175 // sfDomainID flag must be set in the MPTokenIssuance object and can
176 // be freely updated.
177 sleIssuance->setFieldH256(sfDomainID, *domainId);
178 }
179 else if (sleIssuance->isFieldPresent(sfDomainID))
180 {
181 sleIssuance->makeFieldAbsent(sfDomainID);
182 }
183 view().update(sleIssuance);
184 }
185
186 view().update(vault);
187
188 return tesSUCCESS;
189}
190
191} // namespace ripple
Stream error() const
Definition Journal.h:346
Stream debug() const
Definition Journal.h:328
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to 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.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:130
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:484
ApplyView & view()
Definition Transactor.h:163
beast::Journal const j_
Definition Transactor.h:145
ApplyContext & ctx_
Definition Transactor.h:143
static bool checkExtraFeatures(PreflightContext const &ctx)
Definition VaultSet.cpp:34
static TER preclaim(PreclaimContext const &ctx)
Definition VaultSet.cpp:79
TER doApply() override
Definition VaultSet.cpp:134
static NotTEC preflight(PreflightContext const &ctx)
Definition VaultSet.cpp:41
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition Indexes.cpp:570
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
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ lsfVaultPrivate
@ lsfMPTRequireAuth
std::size_t constexpr maxDataPayloadLength
The maximum length of Data payload.
Definition Protocol.h:119
@ tefINTERNAL
Definition TER.h:173
@ tecNO_ENTRY
Definition TER.h:306
@ tecLIMIT_EXCEEDED
Definition TER.h:361
@ tecOBJECT_NOT_FOUND
Definition TER.h:326
@ tecNO_PERMISSION
Definition TER.h:305
@ tesSUCCESS
Definition TER.h:244
@ temMALFORMED
Definition TER.h:87
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