43 Env env{*
this, testableAmendments()};
46 Vault const vault{env};
47 env.fund(XRP(1000), issuer, owner);
51 env.trust(asset(1000), owner);
52 env(pay(issuer, owner, asset(200)));
55 auto const sequence = env.seq(owner);
56 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset});
62 auto tx1 = vault.deposit({.depositor = owner, .id =
keylet.key, .amount = asset(50)});
65 auto tx2 = vault.set({.owner = owner, .id =
keylet.key});
66 tx2[sfAssetsMaximum] = asset(1000).number();
72 auto const vault = env.le(
keylet);
73 BEAST_EXPECT(vault !=
nullptr);
77 auto const check = [&,
keylet =
keylet, sle = sleVault,
this](
80 BEAST_EXPECT(vault.isObject());
82 static constexpr auto kCheckString =
84 return node.isMember(field.fieldName) && node[field.fieldName].isString() &&
85 node[field.fieldName] == v;
87 static constexpr auto kCheckObject =
89 return node.isMember(field.fieldName) && node[field.fieldName].isObject() &&
90 node[field.fieldName] == v;
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)));
98 BEAST_EXPECT(vault[
"LedgerEntryType"].asString() ==
"Vault");
99 BEAST_EXPECT(vault[jss::index].asString() ==
strHex(
keylet.key));
100 BEAST_EXPECT(kCheckInt(vault, sfFlags, 0));
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()));
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));
116 if (issuance.isObject())
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"));
129 auto const checkError = [
this](
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);
139 std::string const badSeqMessage =
"Invalid field 'seq', not a positive 32-bit integer.";
141 "Must specify either 'vault_id' or both 'owner' and 'seq'.";
144 testcase(
"RPC ledger_entry selected by key");
146 jvParams[jss::ledger_index] = jss::validated;
148 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
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]);
156 testcase(
"RPC ledger_entry selected by owner and seq");
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));
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]);
169 testcase(
"RPC ledger_entry cannot find vault by key");
171 jvParams[jss::ledger_index] = jss::validated;
173 auto jvVault = env.rpc(
"json",
"ledger_entry",
to_string(jvParams));
174 BEAST_EXPECT(jvVault[jss::result][jss::error].asString() ==
"entryNotFound");
178 testcase(
"RPC ledger_entry cannot find vault by owner and seq");
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");
188 testcase(
"RPC ledger_entry malformed key");
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");
197 testcase(
"RPC ledger_entry malformed owner");
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");
207 testcase(
"RPC ledger_entry malformed seq");
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");
217 testcase(
"RPC ledger_entry negative seq");
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");
227 testcase(
"RPC ledger_entry oversized seq");
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");
237 testcase(
"RPC ledger_entry bool seq");
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");
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];
254 BEAST_EXPECT(jv[jss::account_objects].size() == 1);
255 check(jv[jss::account_objects][0u]);
262 jvParams[jss::ledger_index] = jss::validated;
263 jvParams[jss::binary] =
false;
264 jvParams[jss::type] = jss::vault;
266 BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
267 check(jv[jss::result][jss::state][0u]);
271 testcase(
"RPC vault_info command line");
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]);
282 jvParams[jss::ledger_index] = jss::validated;
284 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
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]);
292 testcase(
"RPC vault_info invalid vault_id");
294 jvParams[jss::ledger_index] = jss::validated;
295 jvParams[jss::vault_id] =
"foobar";
296 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
301 "Invalid field 'vault_id', not hex string.");
305 testcase(
"RPC vault_info json numeric vault_id");
307 jvParams[jss::ledger_index] = jss::validated;
308 jvParams[jss::vault_id] = 0;
309 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
314 "Invalid field 'vault_id', not hex string.");
318 testcase(
"RPC vault_info json object vault_id");
320 jvParams[jss::ledger_index] = jss::validated;
322 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
327 "Invalid field 'vault_id', not hex string.");
333 testcase(
"RPC vault_info json all zero vault_id");
335 jvParams[jss::ledger_index] = jss::validated;
337 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
338 checkError(jv[jss::result],
"entryNotFound",
RpcEntryNotFound,
"Entry not found.");
342 testcase(
"RPC vault_info json short zero vault_id");
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.");
351 testcase(
"RPC vault_info json by owner and sequence");
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));
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]);
364 testcase(
"RPC vault_info json malformed sequence");
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);
374 testcase(
"RPC vault_info json invalid sequence");
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);
384 testcase(
"RPC vault_info json negative sequence");
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);
394 testcase(
"RPC vault_info json oversized sequence");
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);
404 testcase(
"RPC vault_info json bool sequence");
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);
414 testcase(
"RPC vault_info json malformed owner");
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));
424 "Invalid field 'owner', not AccountID.");
428 testcase(
"RPC vault_info json array owner");
430 jvParams[jss::ledger_index] = jss::validated;
432 jvParams[jss::seq] = sequence;
433 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
438 "Invalid field 'owner', not AccountID.");
442 testcase(
"RPC vault_info json invalid combination only owner");
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);
451 testcase(
"RPC vault_info json invalid combination only seq");
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);
460 testcase(
"RPC vault_info json invalid combination seq vault_id");
462 jvParams[jss::ledger_index] = jss::validated;
464 jvParams[jss::seq] = sequence;
465 auto jv = env.rpc(
"json",
"vault_info",
to_string(jvParams));
466 checkError(jv[jss::result],
"invalidParams",
RpcInvalidParams, badFieldsMessage);
470 testcase(
"RPC vault_info json invalid combination owner vault_id");
472 jvParams[jss::ledger_index] = jss::validated;
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);
481 "RPC vault_info json invalid combination owner seq "
484 jvParams[jss::ledger_index] = jss::validated;
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);
493 testcase(
"RPC vault_info json no input");
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);
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");
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.");
513 testcase(
"RPC vault_info command line unknown index");
515 checkError(jv[jss::result],
"entryNotFound",
RpcEntryNotFound,
"Entry not found.");
519 testcase(
"RPC vault_info command line invalid ledger");
521 BEAST_EXPECT(jv[jss::result][jss::error].asString() ==
"lgrNotFound");