rippled
Loading...
Searching...
No Matches
mpt.cpp
1#include <test/jtx.h>
2
3#include <xrpl/protocol/SField.h>
4#include <xrpl/protocol/jss.h>
5
6namespace ripple {
7namespace test {
8namespace jtx {
9
10void
15
16void
21
22void
24{
25 env.test.expect(cb_());
26}
27
30{
32 for (auto const& h : holders)
33 {
34 if (accounts.find(h.human()) != accounts.cend())
35 Throw<std::runtime_error>("Duplicate holder");
36 accounts.emplace(h.human(), h);
37 }
38 return accounts;
39}
40
41MPTTester::MPTTester(Env& env, Account const& issuer, MPTInit const& arg)
42 : env_(env)
43 , issuer_(issuer)
44 , holders_(makeHolders(arg.holders))
45 , close_(arg.close)
46{
47 if (arg.fund)
48 {
49 env_.fund(arg.xrp, issuer_);
50 for (auto it : holders_)
51 env_.fund(arg.xrpHolders, it.second);
52 }
53 if (close_)
54 env.close();
55 if (arg.fund)
56 {
58 for (auto it : holders_)
59 {
60 if (issuer_.id() == it.second.id())
61 Throw<std::runtime_error>("Issuer can't be holder");
62 env_.require(owners(it.second, 0));
63 }
64 }
65}
66
67void
69{
70 if (id_)
71 Throw<std::runtime_error>("MPT can't be reused");
73 Json::Value jv;
74 jv[sfAccount] = issuer_.human();
75 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
76 if (arg.assetScale)
77 jv[sfAssetScale] = *arg.assetScale;
78 if (arg.transferFee)
79 jv[sfTransferFee] = *arg.transferFee;
80 if (arg.metadata)
81 jv[sfMPTokenMetadata] = strHex(*arg.metadata);
82 if (arg.maxAmt)
83 jv[sfMaximumAmount] = std::to_string(*arg.maxAmt);
84 if (arg.domainID)
85 jv[sfDomainID] = to_string(*arg.domainID);
86 if (arg.mutableFlags)
87 jv[sfMutableFlags] = *arg.mutableFlags;
88 if (submit(arg, jv) != tesSUCCESS)
89 {
90 // Verify issuance doesn't exist
91 env_.require(requireAny([&]() -> bool {
92 return env_.le(keylet::mptIssuance(*id_)) == nullptr;
93 }));
94
95 id_.reset();
96 }
97 else
98 env_.require(mptflags(*this, arg.flags.value_or(0)));
99}
100
101void
103{
104 Json::Value jv;
105 if (arg.issuer)
106 jv[sfAccount] = arg.issuer->human();
107 else
108 jv[sfAccount] = issuer_.human();
109 if (arg.id)
110 jv[sfMPTokenIssuanceID] = to_string(*arg.id);
111 else
112 {
113 if (!id_)
114 Throw<std::runtime_error>("MPT has not been created");
115 jv[sfMPTokenIssuanceID] = to_string(*id_);
116 }
117 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
118 submit(arg, jv);
119}
120
121Account const&
122MPTTester::holder(std::string const& holder_) const
123{
124 auto const& it = holders_.find(holder_);
125 if (it == holders_.cend())
126 Throw<std::runtime_error>("Holder is not found");
127 return it->second;
128}
129
130void
132{
133 Json::Value jv;
134 if (arg.account)
135 jv[sfAccount] = arg.account->human();
136 else
137 jv[sfAccount] = issuer_.human();
138 jv[sfTransactionType] = jss::MPTokenAuthorize;
139 if (arg.id)
140 jv[sfMPTokenIssuanceID] = to_string(*arg.id);
141 else
142 {
143 if (!id_)
144 Throw<std::runtime_error>("MPT has not been created");
145 jv[sfMPTokenIssuanceID] = to_string(*id_);
146 }
147 if (arg.holder)
148 jv[sfHolder] = arg.holder->human();
149 if (auto const result = submit(arg, jv); result == tesSUCCESS)
150 {
151 // Issuer authorizes
152 if (!arg.account || *arg.account == issuer_)
153 {
154 auto const flags = getFlags(arg.holder);
155 // issuer un-authorizes the holder
156 if (arg.flags.value_or(0) == tfMPTUnauthorize)
157 env_.require(mptflags(*this, flags, arg.holder));
158 // issuer authorizes the holder
159 else
161 mptflags(*this, flags | lsfMPTAuthorized, arg.holder));
162 }
163 // Holder authorizes
164 else if (arg.flags.value_or(0) != tfMPTUnauthorize)
165 {
166 auto const flags = getFlags(arg.account);
167 // holder creates a token
168 env_.require(mptflags(*this, flags, arg.account));
169 env_.require(mptbalance(*this, *arg.account, 0));
170 }
171 else
172 {
173 // Verify that the MPToken doesn't exist.
174 forObject(
175 [&](SLEP const& sle) { return env_.test.BEAST_EXPECT(!sle); },
176 arg.account);
177 }
178 }
179 else if (
180 arg.account && *arg.account != issuer_ &&
181 arg.flags.value_or(0) != tfMPTUnauthorize && id_)
182 {
183 if (result == tecDUPLICATE)
184 {
185 // Verify that MPToken already exists
186 env_.require(requireAny([&]() -> bool {
187 return env_.le(keylet::mptoken(*id_, arg.account->id())) !=
188 nullptr;
189 }));
190 }
191 else
192 {
193 // Verify MPToken doesn't exist if holder failed authorizing(unless
194 // it already exists)
195 env_.require(requireAny([&]() -> bool {
196 return env_.le(keylet::mptoken(*id_, arg.account->id())) ==
197 nullptr;
198 }));
199 }
200 }
201}
202
203void
205{
206 Json::Value jv;
207 if (arg.account)
208 jv[sfAccount] = arg.account->human();
209 else
210 jv[sfAccount] = issuer_.human();
211 jv[sfTransactionType] = jss::MPTokenIssuanceSet;
212 if (arg.id)
213 jv[sfMPTokenIssuanceID] = to_string(*arg.id);
214 else
215 {
216 if (!id_)
217 Throw<std::runtime_error>("MPT has not been created");
218 jv[sfMPTokenIssuanceID] = to_string(*id_);
219 }
220 if (arg.holder)
221 jv[sfHolder] = arg.holder->human();
222 if (arg.delegate)
223 jv[sfDelegate] = arg.delegate->human();
224 if (arg.domainID)
225 jv[sfDomainID] = to_string(*arg.domainID);
226 if (arg.mutableFlags)
227 jv[sfMutableFlags] = *arg.mutableFlags;
228 if (arg.transferFee)
229 jv[sfTransferFee] = *arg.transferFee;
230 if (arg.metadata)
231 jv[sfMPTokenMetadata] = strHex(*arg.metadata);
232 if (submit(arg, jv) == tesSUCCESS && (arg.flags || arg.mutableFlags))
233 {
234 auto require = [&](std::optional<Account> const& holder,
235 bool unchanged) {
236 auto flags = getFlags(holder);
237 if (!unchanged)
238 {
239 if (arg.flags)
240 {
241 if (*arg.flags & tfMPTLock)
243 else if (*arg.flags & tfMPTUnlock)
244 flags &= ~lsfMPTLocked;
245 }
246
247 if (arg.mutableFlags)
248 {
251 else if (*arg.mutableFlags & tmfMPTClearCanLock)
252 flags &= ~lsfMPTCanLock;
253
256 else if (*arg.mutableFlags & tmfMPTClearRequireAuth)
257 flags &= ~lsfMPTRequireAuth;
258
261 else if (*arg.mutableFlags & tmfMPTClearCanEscrow)
262 flags &= ~lsfMPTCanEscrow;
263
266 else if (*arg.mutableFlags & tmfMPTClearCanClawback)
267 flags &= ~lsfMPTCanClawback;
268
271 else if (*arg.mutableFlags & tmfMPTClearCanTrade)
272 flags &= ~lsfMPTCanTrade;
273
276 else if (*arg.mutableFlags & tmfMPTClearCanTransfer)
277 flags &= ~lsfMPTCanTransfer;
278 }
279 }
280 env_.require(mptflags(*this, flags, holder));
281 };
282 if (arg.account)
283 require(std::nullopt, arg.holder.has_value());
284 if (arg.holder)
285 require(*arg.holder, false);
286 }
287}
288
289bool
291 std::function<bool(SLEP const& sle)> const& cb,
292 std::optional<Account> const& holder_) const
293{
294 if (!id_)
295 Throw<std::runtime_error>("MPT has not been created");
296 auto const key = holder_ ? keylet::mptoken(*id_, holder_->id())
298 if (auto const sle = env_.le(key))
299 return cb(sle);
300 return false;
301}
302
303[[nodiscard]] bool
305{
306 return forObject([&](SLEP const& sle) -> bool {
307 if (sle->isFieldPresent(sfDomainID))
308 return expected == sle->getFieldH256(sfDomainID);
309 return (!expected.has_value());
310 });
311}
312
313[[nodiscard]] bool
315 Account const& holder_,
316 std::int64_t expectedAmount) const
317{
318 return forObject(
319 [&](SLEP const& sle) { return expectedAmount == (*sle)[sfMPTAmount]; },
320 holder_);
321}
322
323[[nodiscard]] bool
325{
326 return forObject([&](SLEP const& sle) {
327 return expectedAmount == (*sle)[sfOutstandingAmount];
328 });
329}
330
331[[nodiscard]] bool
333 uint32_t const expectedFlags,
334 std::optional<Account> const& holder) const
335{
336 return expectedFlags == getFlags(holder);
337}
338
339[[nodiscard]] bool
341{
342 return forObject([&](SLEP const& sle) -> bool {
343 if (sle->isFieldPresent(sfMPTokenMetadata))
344 return strHex(sle->getFieldVL(sfMPTokenMetadata)) ==
345 strHex(metadata);
346 return false;
347 });
348}
349
350[[nodiscard]] bool
352{
353 return forObject([&](SLEP const& sle) -> bool {
354 return sle->isFieldPresent(sfMPTokenMetadata);
355 });
356}
357
358[[nodiscard]] bool
360{
361 return forObject([&](SLEP const& sle) -> bool {
362 if (sle->isFieldPresent(sfTransferFee))
363 return sle->getFieldU16(sfTransferFee) == transferFee;
364 return false;
365 });
366}
367
368[[nodiscard]] bool
370{
371 return forObject([&](SLEP const& sle) -> bool {
372 return sle->isFieldPresent(sfTransferFee);
373 });
374}
375
376void
378 Account const& src,
379 Account const& dest,
380 std::int64_t amount,
383{
384 if (!id_)
385 Throw<std::runtime_error>("MPT has not been created");
386 auto const srcAmt = getBalance(src);
387 auto const destAmt = getBalance(dest);
388 auto const outstnAmt = getBalance(issuer_);
389
390 if (credentials)
391 env_(
392 jtx::pay(src, dest, mpt(amount)),
393 ter(err.value_or(tesSUCCESS)),
394 credentials::ids(*credentials));
395 else
396 env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS)));
397
398 if (env_.ter() != tesSUCCESS)
399 amount = 0;
400 if (close_)
401 env_.close();
402 if (src == issuer_)
403 {
404 env_.require(mptbalance(*this, src, srcAmt + amount));
405 env_.require(mptbalance(*this, dest, destAmt + amount));
406 }
407 else if (dest == issuer_)
408 {
409 env_.require(mptbalance(*this, src, srcAmt - amount));
410 env_.require(mptbalance(*this, dest, destAmt - amount));
411 }
412 else
413 {
414 STAmount const saAmount = {*id_, amount};
415 auto const actual =
416 multiply(saAmount, transferRate(*env_.current(), *id_))
417 .mpt()
418 .value();
419 // Sender pays the transfer fee if any
420 env_.require(mptbalance(*this, src, srcAmt - actual));
421 env_.require(mptbalance(*this, dest, destAmt + amount));
422 // Outstanding amount is reduced by the transfer fee if any
423 env_.require(mptbalance(*this, issuer_, outstnAmt - (actual - amount)));
424 }
425}
426
427void
429 Account const& issuer,
430 Account const& holder,
431 std::int64_t amount,
433{
434 if (!id_)
435 Throw<std::runtime_error>("MPT has not been created");
436 auto const issuerAmt = getBalance(issuer);
437 auto const holderAmt = getBalance(holder);
439 if (env_.ter() != tesSUCCESS)
440 amount = 0;
441 if (close_)
442 env_.close();
443
445 mptbalance(*this, issuer, issuerAmt - std::min(holderAmt, amount)));
447 mptbalance(*this, holder, holderAmt - std::min(holderAmt, amount)));
448}
449
452{
453 if (!id_)
454 Throw<std::runtime_error>("MPT has not been created");
455 return ripple::test::jtx::MPT(issuer_.name(), *id_)(amount);
456}
457
459MPTTester::getBalance(Account const& account) const
460{
461 if (!id_)
462 Throw<std::runtime_error>("MPT has not been created");
463 if (account == issuer_)
464 {
465 if (auto const sle = env_.le(keylet::mptIssuance(*id_)))
466 return sle->getFieldU64(sfOutstandingAmount);
467 }
468 else
469 {
470 if (auto const sle = env_.le(keylet::mptoken(*id_, account.id())))
471 return sle->getFieldU64(sfMPTAmount);
472 }
473 return 0;
474}
475
478{
480 if (!forObject(
481 [&](SLEP const& sle) {
482 flags = sle->getFlags();
483 return true;
484 },
485 holder))
486 Throw<std::runtime_error>("Failed to get the flags");
487 return flags;
488}
489
490MPT
492{
493 return MPT(name, issuanceID());
494}
495
496} // namespace jtx
497} // namespace test
498} // namespace ripple
Represents a JSON value.
Definition json_value.h:130
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:226
constexpr value_type value() const
Returns the underlying value.
Definition MPTAmount.h:114
MPTAmount mpt() const
Definition STAmount.cpp:295
Immutable cryptographic account descriptor.
Definition Account.h:20
AccountID id() const
Returns the Account ID.
Definition Account.h:92
std::string const & name() const
Return the name.
Definition Account.h:68
std::string const & human() const
Returns the human readable public key.
Definition Account.h:99
A transaction testing environment.
Definition Env.h:102
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:250
void require(Args const &... args)
Check a set of requirements.
Definition Env.h:528
TER ter() const
Return the TER for the last JTx.
Definition Env.h:579
beast::unit_test::suite & test
Definition Env.h:104
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:312
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:103
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:271
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition Env.cpp:259
bool checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const
Definition mpt.cpp:324
void authorize(MPTAuthorize const &arg=MPTAuthorize{})
Definition mpt.cpp:131
void set(MPTSet const &set={})
Definition mpt.cpp:204
void pay(Account const &src, Account const &dest, std::int64_t amount, std::optional< TER > err=std::nullopt, std::optional< std::vector< std::string > > credentials=std::nullopt)
Definition mpt.cpp:377
static std::unordered_map< std::string, Account > makeHolders(std::vector< Account > const &holders)
Definition mpt.cpp:29
Account const & issuer_
Definition mpt.h:135
bool isMetadataPresent() const
Definition mpt.cpp:351
bool checkTransferFee(std::uint16_t transferFee) const
Definition mpt.cpp:359
MPTID const & issuanceID() const
Definition mpt.h:208
TER submit(A const &arg, Json::Value const &jv)
Definition mpt.h:230
void claw(Account const &issuer, Account const &holder, std::int64_t amount, std::optional< TER > err=std::nullopt)
Definition mpt.cpp:428
MPTTester(Env &env, Account const &issuer, MPTInit const &constr={})
Definition mpt.cpp:41
PrettyAmount mpt(std::int64_t amount) const
Definition mpt.cpp:451
MPT operator[](std::string const &name) const
Definition mpt.cpp:491
bool checkFlags(uint32_t const expectedFlags, std::optional< Account > const &holder=std::nullopt) const
Definition mpt.cpp:332
Account const & holder(std::string const &h) const
Definition mpt.cpp:122
Account const & issuer() const
Definition mpt.h:183
bool checkMetadata(std::string const &metadata) const
Definition mpt.cpp:340
bool forObject(std::function< bool(SLEP const &sle)> const &cb, std::optional< Account > const &holder=std::nullopt) const
Definition mpt.cpp:290
bool isTransferFeePresent() const
Definition mpt.cpp:369
std::optional< MPTID > id_
Definition mpt.h:137
std::int64_t getBalance(Account const &account) const
Definition mpt.cpp:459
std::unordered_map< std::string, Account > const holders_
Definition mpt.h:136
bool checkDomainID(std::optional< uint256 > expected) const
Definition mpt.cpp:304
std::uint32_t getFlags(std::optional< Account > const &holder) const
Definition mpt.cpp:477
bool checkMPTokenAmount(Account const &holder, std::int64_t expectedAmount) const
Definition mpt.cpp:314
void create(MPTCreate const &arg=MPTCreate{})
Definition mpt.cpp:68
void destroy(MPTDestroy const &arg=MPTDestroy{})
Definition mpt.cpp:102
Converts to MPT Issue or STAmount.
Match set account flags.
Definition flags.h:109
void operator()(Env &env) const
Definition mpt.cpp:17
Account const & account_
Definition mpt.h:43
std::int64_t const amount_
Definition mpt.h:44
MPTTester const & tester_
Definition mpt.h:42
std::uint32_t flags_
Definition mpt.h:22
MPTTester & tester_
Definition mpt.h:21
void operator()(Env &env) const
Definition mpt.cpp:11
std::optional< Account > holder_
Definition mpt.h:23
Match the number of items in the account's owner directory.
Definition owners.h:54
void operator()(Env &env) const
Definition mpt.cpp:23
std::function< bool()> cb_
Definition mpt.h:59
Check a set of conditions.
Definition require.h:47
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:16
T emplace(T... args)
T cend(T... args)
T find(T... args)
T is_same_v
T min(T... args)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:521
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:507
Json::Value claw(Account const &account, STAmount const &amount, std::optional< Account > const &mptHolder)
Definition trust.cpp:50
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
constexpr std::uint32_t const tmfMPTClearCanClawback
Definition TxFlags.h:175
constexpr std::uint32_t const tmfMPTClearCanEscrow
Definition TxFlags.h:169
constexpr std::uint32_t const tmfMPTSetCanClawback
Definition TxFlags.h:174
constexpr std::uint32_t const tmfMPTSetRequireAuth
Definition TxFlags.h:166
constexpr std::uint32_t const tmfMPTClearCanTrade
Definition TxFlags.h:171
constexpr std::uint32_t const tfMPTUnlock
Definition TxFlags.h:158
@ lsfMPTCanTransfer
@ lsfMPTCanEscrow
@ lsfMPTCanClawback
@ lsfMPTRequireAuth
@ lsfMPTAuthorized
constexpr std::uint32_t const tmfMPTClearRequireAuth
Definition TxFlags.h:167
constexpr std::uint32_t const tmfMPTSetCanLock
Definition TxFlags.h:164
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
constexpr std::uint32_t const tmfMPTSetCanTrade
Definition TxFlags.h:170
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
constexpr std::uint32_t const tfMPTUnauthorize
Definition TxFlags.h:153
constexpr std::uint32_t const tmfMPTSetCanEscrow
Definition TxFlags.h:168
constexpr std::uint32_t const tmfMPTClearCanLock
Definition TxFlags.h:165
constexpr std::uint32_t const tmfMPTSetCanTransfer
Definition TxFlags.h:172
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition View.cpp:743
@ tecDUPLICATE
Definition TER.h:297
constexpr std::uint32_t const tfMPTLock
Definition TxFlags.h:157
@ tesSUCCESS
Definition TER.h:226
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
Definition Indexes.cpp:151
constexpr std::uint32_t const tmfMPTClearCanTransfer
Definition TxFlags.h:173
T has_value(T... args)
std::optional< std::uint32_t > flags
Definition mpt.h:112
std::optional< Account > holder
Definition mpt.h:108
std::optional< Account > account
Definition mpt.h:107
std::optional< MPTID > id
Definition mpt.h:109
std::optional< std::uint8_t > assetScale
Definition mpt.h:83
std::optional< std::uint16_t > transferFee
Definition mpt.h:84
std::optional< uint256 > domainID
Definition mpt.h:91
std::optional< std::uint32_t > mutableFlags
Definition mpt.h:90
std::optional< std::uint32_t > flags
Definition mpt.h:89
std::optional< std::string > metadata
Definition mpt.h:85
std::optional< std::uint64_t > maxAmt
Definition mpt.h:82
std::optional< Account > issuer
Definition mpt.h:97
std::optional< MPTID > id
Definition mpt.h:98
PrettyAmount const xrpHolders
Definition mpt.h:74
PrettyAmount const xrp
Definition mpt.h:73
std::optional< std::uint32_t > flags
Definition mpt.h:123
std::optional< std::uint16_t > transferFee
Definition mpt.h:125
std::optional< Account > account
Definition mpt.h:118
std::optional< std::string > metadata
Definition mpt.h:126
std::optional< uint256 > domainID
Definition mpt.h:128
std::optional< std::uint32_t > mutableFlags
Definition mpt.h:124
std::optional< MPTID > id
Definition mpt.h:120
std::optional< Account > holder
Definition mpt.h:119
std::optional< Account > delegate
Definition mpt.h:127
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
T to_string(T... args)
T value_or(T... args)