xrpld
Loading...
Searching...
No Matches
VaultRPC_test.cpp
1#include <test/app/vault/VaultTestBase.h>
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/pay.h>
6#include <test/jtx/vault.h>
7
8#include <xrpl/basics/base_uint.h>
9#include <xrpl/basics/chrono.h>
10#include <xrpl/basics/strHex.h>
11#include <xrpl/beast/unit_test/suite.h>
12#include <xrpl/beast/utility/Zero.h>
13#include <xrpl/json/json_forwards.h>
14#include <xrpl/json/json_value.h>
15#include <xrpl/json/to_string.h>
16#include <xrpl/protocol/AccountID.h>
17#include <xrpl/protocol/Asset.h>
18#include <xrpl/protocol/ErrorCodes.h>
19#include <xrpl/protocol/Issue.h>
20#include <xrpl/protocol/Keylet.h>
21#include <xrpl/protocol/LedgerFormats.h>
22#include <xrpl/protocol/Protocol.h>
23#include <xrpl/protocol/SField.h>
24#include <xrpl/protocol/jss.h>
25
26#include <chrono>
27#include <memory>
28#include <string>
29#include <tuple>
30#include <utility>
31
32namespace xrpl {
33
35{
36private:
37 void
39 {
40 using namespace test::jtx;
41
42 testcase("RPC");
43 Env env{*this, testableAmendments()};
44 Account const owner{"owner"};
45 Account const issuer{"issuer"};
46 Vault const vault{env};
47 env.fund(XRP(1000), issuer, owner);
48 env.close();
49
50 PrettyAsset const asset = issuer["IOU"];
51 env.trust(asset(1000), owner);
52 env(pay(issuer, owner, asset(200)));
53 env.close();
54
55 auto const sequence = env.seq(owner);
56 auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
57 env(tx);
58 env.close();
59
60 // Set some fields
61 {
62 auto tx1 = vault.deposit({.depositor = owner, .id = keylet.key, .amount = asset(50)});
63 env(tx1);
64
65 auto tx2 = vault.set({.owner = owner, .id = keylet.key});
66 tx2[sfAssetsMaximum] = asset(1000).number();
67 env(tx2);
68 env.close();
69 }
70
71 auto const sleVault = [&env, keylet = keylet, this]() {
72 auto const vault = env.le(keylet);
73 BEAST_EXPECT(vault != nullptr);
74 return vault;
75 }();
76
77 auto const check = [&, keylet = keylet, sle = sleVault, this](
78 json::Value const& vault,
79 json::Value const& issuance = json::ValueType::Null) {
80 BEAST_EXPECT(vault.isObject());
81
82 static constexpr auto kCheckString =
83 [](auto& node, SField const& field, std::string v) -> bool {
84 return node.isMember(field.fieldName) && node[field.fieldName].isString() &&
85 node[field.fieldName] == v;
86 };
87 static constexpr auto kCheckObject =
88 [](auto& node, SField const& field, json::Value v) -> bool {
89 return node.isMember(field.fieldName) && node[field.fieldName].isObject() &&
90 node[field.fieldName] == v;
91 };
92 static constexpr auto kCheckInt = [](auto& node, SField const& field, int v) -> bool {
93 return node.isMember(field.fieldName) &&
94 ((node[field.fieldName].isInt() && node[field.fieldName] == json::Int(v)) ||
95 (node[field.fieldName].isUInt() && node[field.fieldName] == json::UInt(v)));
96 };
97
98 BEAST_EXPECT(vault["LedgerEntryType"].asString() == "Vault");
99 BEAST_EXPECT(vault[jss::index].asString() == strHex(keylet.key));
100 BEAST_EXPECT(kCheckInt(vault, sfFlags, 0));
101 // Ignore all other standard fields, this test doesn't care
102
103 BEAST_EXPECT(kCheckString(vault, sfAccount, toBase58(sle->at(sfAccount))));
104 BEAST_EXPECT(kCheckObject(vault, sfAsset, toJson(sle->at(sfAsset))));
105 BEAST_EXPECT(kCheckString(vault, sfAssetsAvailable, "50"));
106 BEAST_EXPECT(kCheckString(vault, sfAssetsMaximum, "1000"));
107 BEAST_EXPECT(kCheckString(vault, sfAssetsTotal, "50"));
108 BEAST_EXPECT(!vault.isMember(sfLossUnrealized.getJsonName()));
109
110 auto const strShareID = strHex(sle->at(sfShareMPTID));
111 BEAST_EXPECT(kCheckString(vault, sfShareMPTID, strShareID));
112 BEAST_EXPECT(kCheckString(vault, sfOwner, toBase58(owner.id())));
113 BEAST_EXPECT(kCheckInt(vault, sfSequence, sequence));
114 BEAST_EXPECT(kCheckInt(vault, sfWithdrawalPolicy, kVaultStrategyFirstComeFirstServe));
115
116 if (issuance.isObject())
117 {
118 BEAST_EXPECT(issuance["LedgerEntryType"].asString() == "MPTokenIssuance");
119 BEAST_EXPECT(issuance[jss::mpt_issuance_id].asString() == strShareID);
120 BEAST_EXPECT(kCheckInt(issuance, sfSequence, 1));
121 BEAST_EXPECT(kCheckInt(
122 issuance, sfFlags, int(lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer)));
123 BEAST_EXPECT(kCheckString(issuance, sfOutstandingAmount, "50000000"));
124 }
125 };
126
127 // An error response must carry a registered token together with the matching code and
128 // message, so that clients dispatching on either of them reach the same conclusion.
129 auto const checkError = [this](
130 json::Value const& result,
131 std::string const& token,
132 ErrorCodeI const code,
133 std::string const& message) {
134 BEAST_EXPECT(result[jss::error].asString() == token);
135 BEAST_EXPECT(result[jss::error_code].asInt() == code);
136 BEAST_EXPECT(result[jss::error_message].asString() == message);
137 };
138
139 std::string const badSeqMessage = "Invalid field 'seq', not a positive 32-bit integer.";
140 std::string const badFieldsMessage =
141 "Must specify either 'vault_id' or both 'owner' and 'seq'.";
142
143 {
144 testcase("RPC ledger_entry selected by key");
145 json::Value jvParams;
146 jvParams[jss::ledger_index] = jss::validated;
147 jvParams[jss::vault] = strHex(keylet.key);
148 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
149
150 BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
151 BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
152 check(jvVault[jss::result][jss::node]);
153 }
154
155 {
156 testcase("RPC ledger_entry selected by owner and seq");
157 json::Value jvParams;
158 jvParams[jss::ledger_index] = jss::validated;
159 jvParams[jss::vault][jss::owner] = owner.human();
160 jvParams[jss::vault][jss::seq] = sequence;
161 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
162
163 BEAST_EXPECT(!jvVault[jss::result].isMember(jss::error));
164 BEAST_EXPECT(jvVault[jss::result].isMember(jss::node));
165 check(jvVault[jss::result][jss::node]);
166 }
167
168 {
169 testcase("RPC ledger_entry cannot find vault by key");
170 json::Value jvParams;
171 jvParams[jss::ledger_index] = jss::validated;
172 jvParams[jss::vault] = to_string(UInt256(42));
173 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
174 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound");
175 }
176
177 {
178 testcase("RPC ledger_entry cannot find vault by owner and seq");
179 json::Value jvParams;
180 jvParams[jss::ledger_index] = jss::validated;
181 jvParams[jss::vault][jss::owner] = issuer.human();
182 jvParams[jss::vault][jss::seq] = 1'000'000;
183 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
184 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound");
185 }
186
187 {
188 testcase("RPC ledger_entry malformed key");
189 json::Value jvParams;
190 jvParams[jss::ledger_index] = jss::validated;
191 jvParams[jss::vault] = 42;
192 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
193 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
194 }
195
196 {
197 testcase("RPC ledger_entry malformed owner");
198 json::Value jvParams;
199 jvParams[jss::ledger_index] = jss::validated;
200 jvParams[jss::vault][jss::owner] = 42;
201 jvParams[jss::vault][jss::seq] = sequence;
202 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
203 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedOwner");
204 }
205
206 {
207 testcase("RPC ledger_entry malformed seq");
208 json::Value jvParams;
209 jvParams[jss::ledger_index] = jss::validated;
210 jvParams[jss::vault][jss::owner] = issuer.human();
211 jvParams[jss::vault][jss::seq] = "foo";
212 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
213 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
214 }
215
216 {
217 testcase("RPC ledger_entry negative seq");
218 json::Value jvParams;
219 jvParams[jss::ledger_index] = jss::validated;
220 jvParams[jss::vault][jss::owner] = issuer.human();
221 jvParams[jss::vault][jss::seq] = -1;
222 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
223 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
224 }
225
226 {
227 testcase("RPC ledger_entry oversized seq");
228 json::Value jvParams;
229 jvParams[jss::ledger_index] = jss::validated;
230 jvParams[jss::vault][jss::owner] = issuer.human();
231 jvParams[jss::vault][jss::seq] = 1e20;
232 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
233 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
234 }
235
236 {
237 testcase("RPC ledger_entry bool seq");
238 json::Value jvParams;
239 jvParams[jss::ledger_index] = jss::validated;
240 jvParams[jss::vault][jss::owner] = issuer.human();
241 jvParams[jss::vault][jss::seq] = true;
242 auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
243 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
244 }
245
246 {
247 testcase("RPC account_objects");
248
249 json::Value jvParams;
250 jvParams[jss::account] = owner.human();
251 jvParams[jss::type] = jss::vault;
252 auto jv = env.rpc("json", "account_objects", to_string(jvParams))[jss::result];
253
254 BEAST_EXPECT(jv[jss::account_objects].size() == 1);
255 check(jv[jss::account_objects][0u]);
256 }
257
258 {
259 testcase("RPC ledger_data");
260
261 json::Value jvParams;
262 jvParams[jss::ledger_index] = jss::validated;
263 jvParams[jss::binary] = false;
264 jvParams[jss::type] = jss::vault;
265 json::Value jv = env.rpc("json", "ledger_data", to_string(jvParams));
266 BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
267 check(jv[jss::result][jss::state][0u]);
268 }
269
270 {
271 testcase("RPC vault_info command line");
272 json::Value jv = env.rpc("vault_info", strHex(keylet.key), "validated");
273
274 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
275 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
276 check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]);
277 }
278
279 {
280 testcase("RPC vault_info json");
281 json::Value jvParams;
282 jvParams[jss::ledger_index] = jss::validated;
283 jvParams[jss::vault_id] = strHex(keylet.key);
284 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
285
286 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
287 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
288 check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]);
289 }
290
291 {
292 testcase("RPC vault_info invalid vault_id");
293 json::Value jvParams;
294 jvParams[jss::ledger_index] = jss::validated;
295 jvParams[jss::vault_id] = "foobar";
296 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
297 checkError(
298 jv[jss::result],
299 "invalidParams",
301 "Invalid field 'vault_id', not hex string.");
302 }
303
304 {
305 testcase("RPC vault_info json numeric vault_id");
306 json::Value jvParams;
307 jvParams[jss::ledger_index] = jss::validated;
308 jvParams[jss::vault_id] = 0;
309 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
310 checkError(
311 jv[jss::result],
312 "invalidParams",
314 "Invalid field 'vault_id', not hex string.");
315 }
316
317 {
318 testcase("RPC vault_info json object vault_id");
319 json::Value jvParams;
320 jvParams[jss::ledger_index] = jss::validated;
321 jvParams[jss::vault_id] = json::Value(json::ValueType::Object);
322 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
323 checkError(
324 jv[jss::result],
325 "invalidParams",
327 "Invalid field 'vault_id', not hex string.");
328 }
329
330 {
331 // An all-zero key is a well-formed request for a vault that cannot exist, not a
332 // malformed one. parseHex accepts both the padded form and the short "0".
333 testcase("RPC vault_info json all zero vault_id");
334 json::Value jvParams;
335 jvParams[jss::ledger_index] = jss::validated;
336 jvParams[jss::vault_id] = strHex(UInt256(beast::kZero));
337 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
338 checkError(jv[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
339 }
340
341 {
342 testcase("RPC vault_info json short zero vault_id");
343 json::Value jvParams;
344 jvParams[jss::ledger_index] = jss::validated;
345 jvParams[jss::vault_id] = "0";
346 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
347 checkError(jv[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
348 }
349
350 {
351 testcase("RPC vault_info json by owner and sequence");
352 json::Value jvParams;
353 jvParams[jss::ledger_index] = jss::validated;
354 jvParams[jss::owner] = owner.human();
355 jvParams[jss::seq] = sequence;
356 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
357
358 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
359 BEAST_EXPECT(jv[jss::result].isMember(jss::vault));
360 check(jv[jss::result][jss::vault], jv[jss::result][jss::vault][jss::shares]);
361 }
362
363 {
364 testcase("RPC vault_info json malformed sequence");
365 json::Value jvParams;
366 jvParams[jss::ledger_index] = jss::validated;
367 jvParams[jss::owner] = owner.human();
368 jvParams[jss::seq] = "foobar";
369 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
370 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badSeqMessage);
371 }
372
373 {
374 testcase("RPC vault_info json invalid sequence");
375 json::Value jvParams;
376 jvParams[jss::ledger_index] = jss::validated;
377 jvParams[jss::owner] = owner.human();
378 jvParams[jss::seq] = 0;
379 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
380 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badSeqMessage);
381 }
382
383 {
384 testcase("RPC vault_info json negative sequence");
385 json::Value jvParams;
386 jvParams[jss::ledger_index] = jss::validated;
387 jvParams[jss::owner] = owner.human();
388 jvParams[jss::seq] = -1;
389 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
390 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badSeqMessage);
391 }
392
393 {
394 testcase("RPC vault_info json oversized sequence");
395 json::Value jvParams;
396 jvParams[jss::ledger_index] = jss::validated;
397 jvParams[jss::owner] = owner.human();
398 jvParams[jss::seq] = 1e20;
399 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
400 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badSeqMessage);
401 }
402
403 {
404 testcase("RPC vault_info json bool sequence");
405 json::Value jvParams;
406 jvParams[jss::ledger_index] = jss::validated;
407 jvParams[jss::owner] = owner.human();
408 jvParams[jss::seq] = true;
409 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
410 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badSeqMessage);
411 }
412
413 {
414 testcase("RPC vault_info json malformed owner");
415 json::Value jvParams;
416 jvParams[jss::ledger_index] = jss::validated;
417 jvParams[jss::owner] = "foobar";
418 jvParams[jss::seq] = sequence;
419 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
420 checkError(
421 jv[jss::result],
422 "actMalformed",
424 "Invalid field 'owner', not AccountID.");
425 }
426
427 {
428 testcase("RPC vault_info json array owner");
429 json::Value jvParams;
430 jvParams[jss::ledger_index] = jss::validated;
431 jvParams[jss::owner] = json::Value(json::ValueType::Array);
432 jvParams[jss::seq] = sequence;
433 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
434 checkError(
435 jv[jss::result],
436 "actMalformed",
438 "Invalid field 'owner', not AccountID.");
439 }
440
441 {
442 testcase("RPC vault_info json invalid combination only owner");
443 json::Value jvParams;
444 jvParams[jss::ledger_index] = jss::validated;
445 jvParams[jss::owner] = owner.human();
446 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
447 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
448 }
449
450 {
451 testcase("RPC vault_info json invalid combination only seq");
452 json::Value jvParams;
453 jvParams[jss::ledger_index] = jss::validated;
454 jvParams[jss::seq] = sequence;
455 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
456 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
457 }
458
459 {
460 testcase("RPC vault_info json invalid combination seq vault_id");
461 json::Value jvParams;
462 jvParams[jss::ledger_index] = jss::validated;
463 jvParams[jss::vault_id] = strHex(keylet.key);
464 jvParams[jss::seq] = sequence;
465 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
466 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
467 }
468
469 {
470 testcase("RPC vault_info json invalid combination owner vault_id");
471 json::Value jvParams;
472 jvParams[jss::ledger_index] = jss::validated;
473 jvParams[jss::vault_id] = strHex(keylet.key);
474 jvParams[jss::owner] = owner.human();
475 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
476 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
477 }
478
479 {
480 testcase(
481 "RPC vault_info json invalid combination owner seq "
482 "vault_id");
483 json::Value jvParams;
484 jvParams[jss::ledger_index] = jss::validated;
485 jvParams[jss::vault_id] = strHex(keylet.key);
486 jvParams[jss::seq] = sequence;
487 jvParams[jss::owner] = owner.human();
488 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
489 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
490 }
491
492 {
493 testcase("RPC vault_info json no input");
494 json::Value jvParams;
495 jvParams[jss::ledger_index] = jss::validated;
496 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
497 checkError(jv[jss::result], "invalidParams", RpcInvalidParams, badFieldsMessage);
498 }
499
500 {
501 testcase("RPC vault_info command line invalid index");
502 json::Value jv = env.rpc("vault_info", "foobar", "validated");
503 BEAST_EXPECT(jv[jss::error].asString() == "invalidParams");
504 }
505
506 {
507 testcase("RPC vault_info command line zero index");
508 json::Value jv = env.rpc("vault_info", "0", "validated");
509 checkError(jv[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
510 }
511
512 {
513 testcase("RPC vault_info command line unknown index");
514 json::Value jv = env.rpc("vault_info", strHex(UInt256(42)), "validated");
515 checkError(jv[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
516 }
517
518 {
519 testcase("RPC vault_info command line invalid ledger");
520 json::Value jv = env.rpc("vault_info", strHex(keylet.key), "0");
521 BEAST_EXPECT(jv[jss::result][jss::error].asString() == "lgrNotFound");
522 }
523 }
524
525 // RPC coverage: closed-ended vaults must return VaultKind, SubscriptionDate and RedemptionDate
526 // in both vault_info and ledger_entry responses. Open-ended vaults must not.
527 void
529 {
530 using namespace test::jtx;
531
532 testcase("RPC closed-ended vault fields");
533 Env env{*this, testableAmendments()};
534 Account const owner{"owner"};
535 Account const owner2{"owner2"};
536 env.fund(XRP(1000), owner, owner2);
537 env.close();
538
539 auto const closedEnded = std::to_underlying(VaultKind::ClosedEnded);
540 Asset const asset = xrpIssue();
541 auto const sub = env.now().time_since_epoch().count() + 60;
542 auto const red = sub + kMinInvestmentPeriod;
543
544 Vault const vault{env};
545 auto [tx, keylet] = vault.create(
546 {.owner = owner,
547 .asset = asset,
548 .vaultKind = closedEnded,
549 .subscriptionDate = sub,
550 .redemptionDate = red});
551 env(tx);
552 env.close();
553
554 auto [tx2, keylet2] = vault.create({.owner = owner2, .asset = asset});
555 env(tx2);
556 env.close();
557
558 auto const asUInt = [](json::Value const& jv) -> json::UInt {
559 return jv.isUInt() ? jv.asUInt() : json::UInt(jv.asInt());
560 };
561 auto const checkClosedEnded = [&](json::Value const& v) {
562 BEAST_EXPECT(v.isObject());
563 BEAST_EXPECT(v.isMember(sfVaultKind.fieldName));
564 BEAST_EXPECT(asUInt(v[sfVaultKind.fieldName]) == json::UInt(closedEnded));
565 BEAST_EXPECT(v.isMember(sfSubscriptionDate.fieldName));
566 BEAST_EXPECT(asUInt(v[sfSubscriptionDate.fieldName]) == json::UInt(sub));
567 BEAST_EXPECT(v.isMember(sfRedemptionDate.fieldName));
568 BEAST_EXPECT(asUInt(v[sfRedemptionDate.fieldName]) == json::UInt(red));
569 };
570 auto const checkOpenEnded = [&](json::Value const& v) {
571 BEAST_EXPECT(v.isObject());
572 BEAST_EXPECT(!v.isMember(sfVaultKind.fieldName));
573 BEAST_EXPECT(!v.isMember(sfSubscriptionDate.fieldName));
574 BEAST_EXPECT(!v.isMember(sfRedemptionDate.fieldName));
575 };
576
577 {
578 json::Value jvParams;
579 jvParams[jss::vault_id] = strHex(keylet.key);
580 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
581 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
582 checkClosedEnded(jv[jss::result][jss::vault]);
583 }
584 {
585 json::Value jvParams;
586 jvParams[jss::ledger_index] = jss::validated;
587 jvParams[jss::vault] = strHex(keylet.key);
588 auto jv = env.rpc("json", "ledger_entry", to_string(jvParams));
589 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
590 checkClosedEnded(jv[jss::result][jss::node]);
591 }
592 {
593 json::Value jvParams;
594 jvParams[jss::vault_id] = strHex(keylet2.key);
595 auto jv = env.rpc("json", "vault_info", to_string(jvParams));
596 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
597 checkOpenEnded(jv[jss::result][jss::vault]);
598 }
599 {
600 json::Value jvParams;
601 jvParams[jss::ledger_index] = jss::validated;
602 jvParams[jss::vault] = strHex(keylet2.key);
603 auto jv = env.rpc("json", "ledger_entry", to_string(jvParams));
604 BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
605 checkOpenEnded(jv[jss::result][jss::node]);
606 }
607 }
608
609public:
610 void
611 run() override
612 {
613 testRPC();
615 }
616};
617
619
620} // namespace xrpl
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Represents a JSON value.
Definition json_value.h:117
Identifies fields.
Definition SField.h:132
void run() override
Runs the suite.
Shared base for the Vault*_test family under src/test/app/vault/.
test::jtx::PrettyAsset PrettyAsset
constexpr Zero kZero
Definition Zero.h:30
int Int
unsigned int UInt
@ Array
array value (ordered list)
Definition json_value.h:28
@ Object
object value (collection of name/value pairs).
Definition json_value.h:29
@ Null
'null' value
Definition json_value.h:22
Keylet computation functions.
Definition Indexes.h:40
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:108
ErrorCodeI
Definition ErrorCodes.h:23
@ RpcEntryNotFound
Definition ErrorCodes.h:144
@ RpcActMalformed
Definition ErrorCodes.h:73
@ RpcInvalidParams
Definition ErrorCodes.h:67
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:13
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
json::Value toJson(Asset const &asset)
Definition Asset.h:168
BaseUInt< 256 > UInt256
Definition base_uint.h:580
constexpr std::uint8_t kVaultStrategyFirstComeFirstServe
Vault withdrawal policies.
Definition Protocol.h:308
constexpr std::uint32_t kMinInvestmentPeriod
Bounds on the length of a closed-ended vault's Investment phase (RedemptionDate - SubscriptionDate).
Definition Protocol.h:369
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)