50 Env env{*
this, testableAmendments()};
53 Account const depositor{
"depositor"};
54 Account const charlie{
"charlie"};
55 Account const pdOwner{
"pdOwner"};
56 Account const credIssuer1{
"credIssuer1"};
57 Account const credIssuer2{
"credIssuer2"};
59 Vault const vault{env};
60 env.fund(XRP(1000), issuer, owner, depositor, charlie, pdOwner, credIssuer1, credIssuer2);
62 env(fset(issuer, asfAllowTrustLineClawback));
64 env.require(Flags(issuer, asfAllowTrustLineClawback));
67 env.trust(asset(1000), owner);
68 env(pay(issuer, owner, asset(500)));
69 env.trust(asset(1000), depositor);
70 env(pay(issuer, depositor, asset(500)));
71 env.trust(asset(1000), charlie);
72 env(pay(issuer, charlie, asset(5)));
75 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
78 BEAST_EXPECT(env.le(
keylet));
81 testcase(
"private vault owner can deposit");
82 auto tx = vault.deposit({.depositor = owner, .id =
keylet.key, .amount = asset(50)});
87 testcase(
"private vault depositor not authorized yet");
89 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
94 testcase(
"private vault cannot set non-existing domain");
95 auto tx = vault.set({.owner = owner, .id =
keylet.key});
101 testcase(
"private vault set domainId");
104 pdomain::Credentials
const credentials1{
105 {.issuer = credIssuer1, .credType = credType}};
107 env(pdomain::setTx(pdOwner, credentials1));
108 auto const domainId1 = [&]() {
110 return pdomain::getNewDomain(env.meta());
113 auto tx = vault.set({.owner = owner, .id =
keylet.key});
125 {.issuer = credIssuer1, .credType = credType},
126 {.issuer = credIssuer2, .credType = credType}};
129 auto const domainId = [&]() {
131 return pdomain::getNewDomain(env.meta());
134 auto tx = vault.set({.owner = owner, .id =
keylet.key});
140 tx = vault.set({.owner = owner, .id =
keylet.key});
148 testcase(
"private vault depositor still not authorized");
150 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
155 auto const credKeylet = credentials::keylet(depositor, credIssuer1, credType);
157 testcase(
"private vault depositor now authorized");
158 env(credentials::create(depositor, credIssuer1, credType));
159 env(credentials::accept(depositor, credIssuer1, credType));
160 env(credentials::create(charlie, credIssuer1, credType));
163 auto credSle = env.le(credKeylet);
164 BEAST_EXPECT(credSle !=
nullptr);
167 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
171 tx = vault.deposit({.depositor = charlie, .id =
keylet.key, .amount = asset(50)});
177 testcase(
"private vault depositor lost authorization");
178 env(credentials::deleteCred(credIssuer1, depositor, credIssuer1, credType));
179 env(credentials::deleteCred(credIssuer1, charlie, credIssuer1, credType));
181 auto credSle = env.le(credKeylet);
182 BEAST_EXPECT(credSle ==
nullptr);
185 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
191 auto const vault = env.le(
keylet);
192 BEAST_EXPECT(vault !=
nullptr);
193 return MPTIssue(vault->at(sfShareMPTID));
197 testcase(
"private vault expired authorization");
198 uint32_t
const closeTime =
199 env.current()->header().parentCloseTime.time_since_epoch().count();
201 auto tx0 = credentials::create(depositor, credIssuer2, credType);
202 tx0[sfExpiration] = closeTime + 20;
204 tx0 = credentials::create(charlie, credIssuer2, credType);
205 tx0[sfExpiration] = closeTime + 20;
209 env(credentials::accept(depositor, credIssuer2, credType));
210 env(credentials::accept(charlie, credIssuer2, credType));
216 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
220 auto const tokenKeylet =
222 BEAST_EXPECT(env.le(tokenKeylet) !=
nullptr);
231 auto const credsKeylet = credentials::keylet(depositor, credIssuer2, credType);
232 BEAST_EXPECT(env.le(credsKeylet) !=
nullptr);
235 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(1)});
239 BEAST_EXPECT(env.le(credsKeylet) ==
nullptr);
243 auto const credsKeylet = credentials::keylet(charlie, credIssuer2, credType);
244 BEAST_EXPECT(env.le(credsKeylet) !=
nullptr);
245 auto const tokenKeylet =
247 BEAST_EXPECT(env.le(tokenKeylet) ==
nullptr);
250 vault.deposit({.depositor = charlie, .id =
keylet.key, .amount = asset(2)});
254 BEAST_EXPECT(env.le(credsKeylet) ==
nullptr);
255 BEAST_EXPECT(env.le(tokenKeylet) ==
nullptr);
260 testcase(
"private vault reset domainId");
261 auto tx = vault.set({.owner = owner, .id =
keylet.key});
262 tx[sfDomainID] =
"0";
266 tx = vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
270 tx = vault.withdraw({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
275 {.issuer = issuer, .id =
keylet.key, .holder = depositor, .amount = asset(0)});
279 {.issuer = issuer, .id =
keylet.key, .holder = owner, .amount = asset(0)});
296 testcase(
"private vault share transfer after depositor loses domain");
312 Env env{*
this, testableAmendments()};
313 Account const issuer{
"issuer"};
315 Account const depositor{
"depositor"};
317 Account const pdOwner{
"pdOwner"};
318 Account const credIssuer{
"credIssuer"};
320 Vault const vault{env};
321 env.fund(XRP(1000), issuer, owner, depositor, bob, pdOwner, credIssuer);
325 env.trust(asset(1000), owner);
326 env(pay(issuer, owner, asset(500)));
327 env.trust(asset(1000), depositor);
328 env(pay(issuer, depositor, asset(500)));
329 env.trust(asset(1000), bob);
330 env(pay(issuer, bob, asset(500)));
335 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
339 pdomain::Credentials
const credentials{{.issuer = credIssuer, .credType = credType}};
341 auto const domainId = [&]() {
343 return pdomain::getNewDomain(env.meta());
346 auto domainTx = vault.set({.owner = owner, .id =
keylet.key});
347 domainTx[sfDomainID] =
to_string(domainId);
354 env(credentials::create(depositor, credIssuer, credType));
355 env(credentials::accept(depositor, credIssuer, credType));
356 env(credentials::create(bob, credIssuer, credType));
357 env(credentials::accept(bob, credIssuer, credType));
360 env(vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}));
361 env(vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)}));
365 auto const sle = env.le(
keylet);
366 BEAST_EXPECT(sle !=
nullptr);
367 return MPTIssue(sle->at(sfShareMPTID));
371 auto const credKeylet = credentials::keylet(depositor, credIssuer, credType);
372 env(credentials::deleteCred(credIssuer, depositor, credIssuer, credType));
374 BEAST_EXPECT(env.le(credKeylet) ==
nullptr);
380 Account const charlie{
"charlie"};
381 env.fund(XRP(1000), charlie);
384 vault.deposit({.depositor = charlie, .id =
keylet.key, .amount = asset(1)});
390 env(pay(depositor, bob, shares(1)), Ter{
tecNO_AUTH});
398 BEAST_EXPECT(expectOffers(env, depositor, 0));
406 testcase(
"private vault share purchase via DEX requires buyer domain membership");
412 Env env{*
this, testableAmendments()};
413 Account const issuer{
"issuer"};
416 Account const charlie{
"charlie"};
417 Account const pdOwner{
"pdOwner"};
418 Account const credIssuer{
"credIssuer"};
420 Vault const vault{env};
421 env.fund(XRP(1000), issuer, owner, bob, charlie, pdOwner, credIssuer);
425 env.trust(asset(1000), owner);
426 env(pay(issuer, owner, asset(500)));
427 env.trust(asset(1000), bob);
428 env(pay(issuer, bob, asset(500)));
431 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
435 pdomain::Credentials
const credentials{{.issuer = credIssuer, .credType = credType}};
437 auto const domainId = [&]() {
439 return pdomain::getNewDomain(env.meta());
442 auto domainTx = vault.set({.owner = owner, .id =
keylet.key});
443 domainTx[sfDomainID] =
to_string(domainId);
449 env(credentials::create(bob, credIssuer, credType));
450 env(credentials::accept(bob, credIssuer, credType));
452 env(vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)}));
456 auto const sle = env.le(
keylet);
457 BEAST_EXPECT(sle !=
nullptr);
458 return MPTIssue(sle->at(sfShareMPTID));
462 env(offer(bob, XRP(1), shares(1)));
464 BEAST_EXPECT(expectOffers(env, bob, 1));
471 env(offer(charlie, shares(1), XRP(1)), Ter{
tecNO_AUTH});
473 BEAST_EXPECT(expectOffers(env, bob, 1));
474 BEAST_EXPECT(expectOffers(env, charlie, 0));
484 Env env{*
this, testableAmendments()};
486 Account const depositor{
"depositor"};
487 Account const alice{
"charlie"};
489 Vault const vault{env};
490 env.fund(XRP(100000), owner, depositor, alice);
494 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
498 auto const [vaultAccount, issuanceId] =
500 auto const vault = env.le(
keylet);
501 BEAST_EXPECT(vault !=
nullptr);
502 return {vault->at(sfAccount), vault->at(sfShareMPTID)};
509 testcase(
"private XRP vault owner can deposit");
510 auto tx = vault.deposit({.depositor = owner, .id =
keylet.key, .amount = asset(50)});
516 testcase(
"private XRP vault cannot pay shares to depositor yet");
517 env(pay(owner, depositor, shares(1)), Ter{
tecNO_AUTH});
521 testcase(
"private XRP vault depositor not authorized yet");
523 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
528 testcase(
"private XRP vault set DomainID");
529 pdomain::Credentials
const credentials{{.issuer = owner, .credType = credType}};
532 auto const domainId = [&]() {
534 return pdomain::getNewDomain(env.meta());
537 auto tx = vault.set({.owner = owner, .id =
keylet.key});
543 auto const credKeylet = credentials::keylet(depositor, owner, credType);
545 testcase(
"private XRP vault depositor now authorized");
546 env(credentials::create(depositor, owner, credType));
547 env(credentials::accept(depositor, owner, credType));
550 BEAST_EXPECT(env.le(credKeylet));
552 vault.deposit({.depositor = depositor, .id =
keylet.key, .amount = asset(50)});
558 testcase(
"private XRP vault can pay shares to depositor");
559 env(pay(owner, depositor, shares(1)));
563 testcase(
"private XRP vault cannot pay shares to 3rd party");
565 jv[sfAccount] = alice.human();
566 jv[sfTransactionType] = jss::MPTokenAuthorize;
567 jv[sfMPTokenIssuanceID] =
to_string(issuanceId);
571 env(pay(owner, alice, shares(1)), Ter{
tecNO_AUTH});
585 bool const withFix = features[fixCleanup3_4_0];
587 std::string{
"VaultWithdraw private vault destination domain check"} +
588 (withFix ?
" (fixCleanup3_4_0)" :
" (pre-fix)"));
590 Account const issuer{
"issuer"};
592 Account const depositor{
"depositor"};
593 Account const beneficiary{
"beneficiary"};
594 Account const outsider{
"outsider"};
595 Account const pdOwner{
"pdOwner"};
596 Account const credIssuer{
"credIssuer"};
599 Env env{*
this, features};
600 Vault const vault{env};
603 XRP(100'000), issuer, owner, depositor, beneficiary, outsider, pdOwner, credIssuer);
609 for (
auto const& account : {owner, depositor, beneficiary, outsider})
611 env.trust(asset(1'000'000), account);
612 env(pay(issuer, account, asset(10'000)));
616 auto const domainId = [&]() {
617 pdomain::Credentials
const credentials{{.issuer = credIssuer, .credType = credType}};
620 return pdomain::getNewDomain(env.meta());
623 auto const joinDomain = [&](
Account const& account) {
624 env(credentials::create(account, credIssuer, credType));
625 env(credentials::accept(account, credIssuer, credType));
628 joinDomain(depositor);
629 joinDomain(beneficiary);
632 vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
637 auto tx = vault.set({.owner = owner, .id =
keylet.key});
643 env(vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(1'000)}));
648 vault.withdraw({.depositor = depositor, .id =
keylet.key, .amount = asset(1)});
649 tx[sfDestination] = destination.human();
655 env(withdrawTo(beneficiary));
668 env(withdrawTo(issuer));
681 env(vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1)}));
687 env(withdrawTo(depositor));
693 std::string{
"VaultWithdraw private vault submitter lost vault access"} +
694 (withFix ?
" (fixCleanup3_4_0)" :
" (pre-fix)"));
696 env(credentials::deleteCred(credIssuer, depositor, credIssuer, credType));
701 env(vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1)}));
710 env(withdrawTo(issuer));
716 std::string{
"VaultWithdraw private vault with no domain set"} +
717 (withFix ?
" (fixCleanup3_4_0)" :
" (pre-fix)"));
721 env(credentials::create(depositor, credIssuer, credType));
722 env(credentials::accept(depositor, credIssuer, credType));
725 auto tx = vault.set({.owner = owner, .id =
keylet.key});
726 tx[sfDomainID] =
"0";
737 env(vault.withdraw({.depositor = depositor, .id = keylet.key, .amount = asset(1)}));
740 env(withdrawTo(issuer));
746 std::string{
"VaultWithdraw public vault destination unaffected"} +
747 (withFix ?
" (fixCleanup3_4_0)" :
" (pre-fix)"));
749 auto [publicTx, publicKeylet] = vault.create({.owner = owner, .asset = asset});
753 env(vault.deposit({.depositor = owner, .id = publicKeylet.key, .amount = asset(100)}));
757 vault.withdraw({.depositor = owner, .id = publicKeylet.key, .amount = asset(1)});
758 tx[sfDestination] = outsider.human();
768 "withdraw with credential-based deposit preauth " +
769 std::string{features[fixCleanup3_4_0] ?
"post-fix" :
"pre-fix"});
771 using namespace std::chrono_literals;
773 bool const fixEnabled = features[fixCleanup3_4_0];
775 Env env{*
this, features};
778 Account const depositor{
"depositor"};
780 Account const credIssuer{
"credIssuer"};
781 char const credType[] =
"abcde";
783 env.fund(XRP(1000), owner, depositor, dest, credIssuer);
784 env(fset(dest, asfDepositAuth));
789 auto [tx,
keylet] = vault.create({.owner = owner, .asset = asset});
793 env(vault.deposit({.depositor = depositor, .id = keylet.key, .amount = asset(100)}));
796 auto withdrawToDest = [&]() {
798 vault.withdraw({.depositor = depositor, .id =
keylet.key, .amount = asset(10)});
799 wtx[sfDestination] = dest.human();
808 auto jv = credentials::create(depositor, credIssuer, credType);
810 env.current()->header().parentCloseTime.time_since_epoch().count() + 100;
811 jv[sfExpiration.jsonName] = expiration;
813 env(credentials::accept(depositor, credIssuer, credType));
816 auto const credKeylet = credentials::keylet(depositor, credIssuer, credType);
818 credentials::ledgerEntry(env, depositor, credIssuer, credType)[jss::result][jss::index]
822 env(deposit::authCredentials(dest, {{.issuer = credIssuer, .credType = credType}}));
832 env(withdrawToDest(), credentials::Ids({credIdx}), Ter{
temDISABLED});
838 env(withdrawToDest(), credentials::Ids({credIdx}));
843 "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E01E034";
848 env(withdrawToDest(), credentials::Ids({credIdx, credIdx}), Ter{
temMALFORMED});
852 char const credType2[] =
"fghij";
853 env(credentials::create(depositor, credIssuer, credType2));
854 env(credentials::accept(depositor, credIssuer, credType2));
856 auto const credIdx2 =
857 credentials::ledgerEntry(env, depositor, credIssuer, credType2)[jss::result][jss::index]
864 BEAST_EXPECT(env.le(credKeylet));
865 env(withdrawToDest(), credentials::Ids({credIdx}), Ter{
tecEXPIRED});
867 BEAST_EXPECT(!env.le(credKeylet));