65 Account const dpIssuer(
"dpIssuer");
66 char const credType[] =
"KYC_VERIFIED";
70 env(credentials::create(subject, dpIssuer, credType));
72 env(credentials::accept(subject, dpIssuer, credType));
74 auto const jv = credentials::ledgerEntry(env, subject, dpIssuer, credType);
75 return jv[jss::result][jss::index].asString();
80 Env env(*
this, features);
84 {{.account = bob, .payAmount = 100, .convertAmount = 50},
85 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
86 auto& mpt = confEnv.
mpt;
87 env(fset(bob, asfDepositAuth));
99 env(deposit::auth(bob, carol));
113 env(deposit::unauth(bob, carol));
127 Env env(*
this, features);
128 env.fund(XRP(50000), dpIssuer);
134 {{.account = bob, .payAmount = 100, .convertAmount = 50},
135 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
136 auto& mpt = confEnv.
mpt;
137 env(fset(bob, asfDepositAuth));
140 auto const credIdx = createCredential(env, carol);
147 .credentials = {{credIdx}},
152 env(deposit::authCredentials(bob, {{.issuer = dpIssuer, .credType = credType}}));
164 mpt.send({.account = carol, .dest = bob, .amt = 10, .credentials = {{credIdx}}});
172 Env env(*
this, features);
173 env.fund(XRP(50000), dpIssuer);
179 {{.account = bob, .payAmount = 100, .convertAmount = 50},
180 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
181 auto& mpt = confEnv.
mpt;
182 env(fset(bob, asfDepositAuth));
185 auto const credIdx = createCredential(env, carol);
188 env(deposit::auth(bob, carol));
202 mpt.send({.account = carol, .dest = bob, .amt = 10, .credentials = {{credIdx}}});
208 env(deposit::unauth(bob, carol));
224 .credentials = {{credIdx}},
229 env(deposit::authCredentials(bob, {{.issuer = dpIssuer, .credType = credType}}));
233 mpt.send({.account = carol, .dest = bob, .amt = 10, .credentials = {{credIdx}}});
236 auto const expireTime = 30;
240 auto createExpiringCredential = [&](Env& env,
Account const& subject) ->
std::string {
241 auto jv = credentials::create(subject, dpIssuer, credType);
243 env.current()->header().parentCloseTime.time_since_epoch().count() + expireTime;
244 jv[sfExpiration.jsonName] = expiry;
247 env(credentials::accept(subject, dpIssuer, credType));
249 auto const credentials = credentials::ledgerEntry(env, subject, dpIssuer, credType);
250 return credentials[jss::result][jss::index].asString();
253 auto credentialDeleted = [&](Env& env,
Account const& subject) ->
bool {
254 auto const credentials = credentials::ledgerEntry(env, subject, dpIssuer, credType);
255 return credentials[jss::result].isMember(jss::error) &&
256 credentials[jss::result][jss::error] ==
"entryNotFound";
265 Env env(*
this, features);
266 env.fund(XRP(50000), dpIssuer);
272 {{.account = bob, .payAmount = 100, .convertAmount = 50},
273 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
274 auto& mpt = confEnv.
mpt;
275 env(fset(bob, asfDepositAuth));
278 auto const credIdx = createExpiringCredential(env, carol);
281 env(deposit::authCredentials(bob, {{.issuer = dpIssuer, .credType = credType}}));
292 .credentials = {{credIdx}},
297 BEAST_EXPECT(credentialDeleted(env, carol));
306 Env env(*
this, features);
307 env.fund(XRP(50000), dpIssuer);
313 {{.account = bob, .payAmount = 100, .convertAmount = 50},
314 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
315 auto& mpt = confEnv.
mpt;
317 auto const credIdx = createExpiringCredential(env, carol);
327 .credentials = {{credIdx}},
332 BEAST_EXPECT(credentialDeleted(env, carol));
347 Env env(*
this, features);
348 env.fund(XRP(50000), dpIssuer);
354 {{.account = bob, .payAmount = 100, .convertAmount = 50},
355 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
356 auto& mpt = confEnv.
mpt;
357 env(fset(bob, asfDepositAuth));
360 auto const credIdx = createExpiringCredential(env, carol);
370 .credentials = {{credIdx}},
376 BEAST_EXPECT(!credentialDeleted(env, carol));
383 testcase(
"Send credential validation");
402 Account const dpIssuer(
"dpIssuer");
403 char const credType[] =
"KYC";
407 Env env(*
this, features);
411 {{.account = bob, .payAmount = 100, .convertAmount = 50},
412 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
413 auto& mpt = confEnv.
mpt;
426 Env env(*
this, features);
430 {{.account = bob, .payAmount = 100, .convertAmount = 50},
431 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
432 auto& mpt = confEnv.
mpt;
436 for (
int i = 0; i < 9; ++i)
443 .credentials = tooManyCredentials,
450 Env env(*
this, features);
451 env.fund(XRP(50000), dpIssuer);
456 {{.account = bob, .payAmount = 100, .convertAmount = 50},
457 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
458 auto& mpt = confEnv.
mpt;
460 env(credentials::create(carol, dpIssuer, credType));
462 env(credentials::accept(carol, dpIssuer, credType));
465 auto const jv = credentials::ledgerEntry(env, carol, dpIssuer, credType);
466 std::string const credIdx = jv[jss::result][jss::index].asString();
472 .credentials = {{credIdx, credIdx}},
479 Env env(*
this, features);
483 {{.account = bob, .payAmount = 100, .convertAmount = 50},
484 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
485 auto& mpt = confEnv.
mpt;
492 .credentials = {{fakeCredIdx}},
499 Env env(*
this, features);
500 env.fund(XRP(50000), dpIssuer);
505 {{.account = bob, .payAmount = 100, .convertAmount = 50},
506 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
507 auto& mpt = confEnv.
mpt;
510 env(credentials::create(bob, dpIssuer, credType));
512 env(credentials::accept(bob, dpIssuer, credType));
515 auto const jv = credentials::ledgerEntry(env, bob, dpIssuer, credType);
516 std::string const credIdx = jv[jss::result][jss::index].asString();
522 .credentials = {{credIdx}},
529 Env env(*
this, features);
530 env.fund(XRP(50000), dpIssuer);
535 {{.account = bob, .payAmount = 100, .convertAmount = 50},
536 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
537 auto& mpt = confEnv.
mpt;
540 env(credentials::create(carol, dpIssuer, credType));
543 auto const jv = credentials::ledgerEntry(env, carol, dpIssuer, credType);
544 std::string const credIdx = jv[jss::result][jss::index].asString();
550 .credentials = {{credIdx}},
560 Env env(*
this, features - featureCredentials);
564 {{.account = bob, .payAmount = 100, .convertAmount = 50},
565 {.account = carol, .payAmount = 100, .convertAmount = 50}}};
566 auto& mpt = confEnv.
mpt;
568 auto constexpr kCredIdx =
569 "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4";
575 .credentials = {{kCredIdx}},
591 testcase(
"AMM holder cannot have confidential state");
597 for (
bool const enablePseudoAccount : {
false,
true})
601 enablePseudoAccount ? features | featureSingleAssetVault
602 : features - featureSingleAssetVault};
604 MPTTester mptAlice(env, alice, {.holders = {bob}});
607 .flags = kMptDexFlags | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance,
609 mptAlice.authorize({.account = bob});
610 mptAlice.pay(alice, bob, 1'000);
612 mptAlice.generateKeyPair(alice);
613 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
615 AMM
const amm(env, bob, XRP(100), mptAlice(100));
616 Account const ammHolder(
"amm", amm.ammAccount());
619 BEAST_EXPECT(ammSle && ammSle->isFieldPresent(sfAMMID));
620 BEAST_EXPECT(mptAlice.getBalance(ammHolder) == 100);
622 BEAST_EXPECT(!mptAlice.getEncryptedBalance(ammHolder, MPTTester::holderEncryptedInbox));
624 !mptAlice.getEncryptedBalance(ammHolder, MPTTester::holderEncryptedSpending));
626 !mptAlice.getEncryptedBalance(ammHolder, MPTTester::issuerEncryptedBalance));
628 !mptAlice.getEncryptedBalance(ammHolder, MPTTester::auditorEncryptedBalance));
630 mptAlice.confidentialClaw({
646 testcase(
"Confidential transfer with tickets");
649 Env env{*
this, features};
653 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
657 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
659 mptAlice.authorize({.account = bob});
660 mptAlice.authorize({.account = carol});
661 mptAlice.pay(alice, bob, 100);
662 mptAlice.pay(alice, carol, 100);
664 mptAlice.generateKeyPair(alice);
665 mptAlice.generateKeyPair(bob);
666 mptAlice.generateKeyPair(carol);
671 env(ticket::create(alice, 1));
672 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice), .ticketSeq = ticketSeq});
678 env(ticket::create(bob, 1));
682 .holderPubKey = mptAlice.getPubKey(bob),
683 .ticketSeq = ticketSeq,
685 env.require(MptBalance(mptAlice, bob, 50));
691 env(ticket::create(bob, 1));
692 mptAlice.convert({.account = bob, .amt = 20, .ticketSeq = ticketSeq});
693 env.require(MptBalance(mptAlice, bob, 30));
699 env(ticket::create(bob, 1));
700 mptAlice.mergeInbox({.account = bob, .ticketSeq = ticketSeq});
703 mptAlice.convert({.account = carol, .amt = 50, .holderPubKey = mptAlice.getPubKey(carol)});
704 mptAlice.mergeInbox({.account = carol});
709 env(ticket::create(bob, 1));
710 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .ticketSeq = ticketSeq});
714 mptAlice.mergeInbox({.account = carol});
720 env(ticket::create(carol, 1));
721 mptAlice.convertBack({.account = carol, .amt = 10, .ticketSeq = ticketSeq});
723 env.require(MptBalance(mptAlice, carol, 60));
733 testcase(
"Convert proof binds to ticket sequence");
736 Env env{*
this, features};
739 MPTTester mptAlice(env, alice, {.holders = {bob}});
744 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
746 mptAlice.authorize({.account = bob});
747 mptAlice.pay(alice, bob, 100);
749 mptAlice.generateKeyPair(alice);
750 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
751 mptAlice.generateKeyPair(bob);
753 uint64_t
const amt = 30;
755 Buffer const holderCt = mptAlice.encryptAmount(bob, amt, bf);
756 Buffer const issuerCt = mptAlice.encryptAmount(alice, amt, bf);
759 env(ticket::create(bob, 1));
764 BEAST_EXPECT(env.seq(bob) != ticketSeq1);
768 mptAlice.getSchnorrProof(bob, badCtxHash),
"Missing Schnorr Proof.");
773 .proof =
strHex(badProof),
774 .holderPubKey = mptAlice.getPubKey(bob),
775 .holderEncryptedAmt = holderCt,
776 .issuerEncryptedAmt = issuerCt,
777 .blindingFactor = bf,
778 .ticketSeq = ticketSeq1,
784 env(ticket::create(bob, 1));
790 .holderPubKey = mptAlice.getPubKey(bob),
791 .holderEncryptedAmt = holderCt,
792 .issuerEncryptedAmt = issuerCt,
793 .blindingFactor = bf,
794 .ticketSeq = ticketSeq2,
796 env.require(MptBalance(mptAlice, bob, 70));
909 testcase(
"Batch confidential send - merge inbox dependency");
913 Env env{*
this, features};
919 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
927 auto const bobSeq = env.seq(bob);
928 auto const carolSeq = env.seq(carol);
930 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 3);
932 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 100}, bobSeq + 1);
933 auto const jv2 = mpt.mergeInboxJV({.account = carol});
934 auto const jv3 = mpt.sendJV({.account = carol, .dest = dave, .amt = 50}, carolSeq + 1);
936 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
937 batch::Inner(jv1, bobSeq + 1),
938 batch::Inner(jv2, carolSeq),
939 batch::Inner(jv3, carolSeq + 1),
946 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
947 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
955 Env env{*
this, features};
961 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
966 auto const bobSeq = env.seq(bob);
967 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
969 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
970 auto const jv2 = mpt.sendJV({.account = bob, .dest = dave, .amt = 60}, bobSeq + 2);
972 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
973 batch::Inner(jv1, bobSeq + 1),
974 batch::Inner(jv2, bobSeq + 2),
980 mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 150);
981 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
982 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
987 auto const bobSeq = env.seq(bob);
988 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
990 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
991 auto const jv2 = mpt.sendJV({.account = bob, .dest = dave, .amt = 60}, bobSeq + 2);
993 env(batch::outer(bob, bobSeq, batchFee, tfIndependent),
994 batch::Inner(jv1, bobSeq + 1),
995 batch::Inner(jv2, bobSeq + 2),
1001 mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1002 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 50);
1004 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
1013 Env env{*
this, features};
1019 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1023 auto const bobSeq = env.seq(bob);
1024 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1028 mpt.sendJV({.account = bob, .dest = carol, .amt = 100}, bobSeq + 1);
1031 auto const chain1 = mpt.chainAfterSend(bob, 100, jv1);
1035 mpt.sendJV({.account = bob, .dest = dave, .amt = 100}, bobSeq + 2, chain1);
1037 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1038 batch::Inner(jv1, bobSeq + 1),
1039 batch::Inner(jv2, bobSeq + 2),
1044 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 0);
1046 mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 100);
1047 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 100);
1053 Env env2{*
this, features};
1054 Account const alice2(
"alice");
1056 Account const carol2(
"carol");
1059 MPTTester mpt2(env2, alice2, {.holders = {bob2, carol2, dave2}});
1062 auto const bobSeq = env2.seq(bob2);
1063 auto const batchFee = batch::calcConfidentialBatchFee(env2, 0, 2);
1066 mpt2.sendJV({.account = bob2, .dest = carol2, .amt = 100}, bobSeq + 1);
1067 auto const chain1 = mpt2.chainAfterSend(bob2, 100, jv1);
1070 mpt2.sendJV({.account = bob2, .dest = dave2, .amt = 100}, bobSeq + 2, chain1);
1073 batch::outer(bob2, bobSeq, batchFee, tfAllOrNothing),
1074 batch::Inner(jv1, bobSeq + 1),
1075 batch::Inner(jv2, bobSeq + 2),
1081 mpt2.getDecryptedBalance(bob2, MPTTester::holderEncryptedSpending) == 150);
1083 mpt2.getDecryptedBalance(carol2, MPTTester::holderEncryptedInbox) == 0);
1084 BEAST_EXPECT(mpt2.getDecryptedBalance(dave2, MPTTester::holderEncryptedInbox) == 0);
1091 testcase(
"Batch confidential convert and convertBack");
1103 Env env{*
this, features};
1109 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1113 mpt.pay(alice, bob, 50);
1115 auto const bobSeq = env.seq(bob);
1116 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1119 auto const jv1 = mpt.convertJV({.account = bob, .amt = 50}, bobSeq + 1);
1121 auto const jv2 = mpt.convertBackJV({.account = bob, .amt = 30}, bobSeq + 2);
1123 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1124 batch::Inner(jv1, bobSeq + 1),
1125 batch::Inner(jv2, bobSeq + 2),
1132 env.require(MptBalance(mpt, bob, 30));
1133 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 70);
1134 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedInbox) == 50);
1146 Env env{*
this, features};
1152 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1154 mpt.pay(alice, bob, 50);
1156 auto const bobSeq = env.seq(bob);
1157 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 3);
1159 auto const jv1 = mpt.convertJV({.account = bob, .amt = 50}, bobSeq + 1);
1160 auto const jv2 = mpt.mergeInboxJV({.account = bob});
1162 auto const jv3 = mpt.convertBackJV({.account = bob, .amt = 30}, bobSeq + 3);
1164 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1165 batch::Inner(jv1, bobSeq + 1),
1166 batch::Inner(jv2, bobSeq + 2),
1167 batch::Inner(jv3, bobSeq + 3),
1172 env.require(MptBalance(mpt, bob, 50));
1173 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1174 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedInbox) == 0);
1183 testcase(
"Batch confidential mixed operations");
1199 Env env{*
this, features};
1205 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1210 mpt.pay(alice, carol, 50);
1212 mpt.pay(alice, dave, 50);
1213 mpt.convert({.account = dave, .amt = 50});
1214 mpt.mergeInbox({.account = dave});
1216 auto const bobSeq = env.seq(bob);
1217 auto const carolSeq = env.seq(carol);
1218 auto const daveSeq = env.seq(dave);
1220 auto const batchFee = batch::calcConfidentialBatchFee(env, 2, 4);
1223 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 30}, bobSeq + 1);
1225 auto const jv2 = mpt.convertJV({.account = carol, .amt = 50}, carolSeq);
1227 auto const jv3 = mpt.convertBackJV({.account = dave, .amt = 20}, daveSeq);
1230 auto const jv4 = mpt.mergeInboxJV({.account = carol});
1232 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1233 batch::Inner(jv1, bobSeq + 1),
1234 batch::Inner(jv2, carolSeq),
1235 batch::Inner(jv3, daveSeq),
1236 batch::Inner(jv4, carolSeq + 1),
1237 batch::Sig(carol, dave),
1242 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 70);
1244 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 80);
1245 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
1247 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedSpending) == 30);
1248 env.require(MptBalance(mpt, dave, 20));
1257 Env env{*
this, features};
1263 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1266 auto const bobSeq = env.seq(bob);
1267 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1270 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 30}, bobSeq + 1);
1272 auto const jv2 = mpt.convertBackJV({.account = bob, .amt = 40}, bobSeq + 2);
1274 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1275 batch::Inner(jv1, bobSeq + 1),
1276 batch::Inner(jv2, bobSeq + 2),
1281 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1282 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
1291 testcase(
"Batch confidential MPT - all or nothing");
1294 Env env{*
this, features};
1300 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1306 auto const bobSeq = env.seq(bob);
1307 auto const carolSeq = env.seq(carol);
1308 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1310 auto const jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 10}, bobSeq + 1);
1311 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 5}, carolSeq);
1313 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1314 batch::Inner(jv1, bobSeq + 1),
1315 batch::Inner(jv2, carolSeq),
1321 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 90);
1322 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 55);
1323 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 15);
1330 testcase(
"Batch confidential MPT - only one");
1333 Env env{*
this, features};
1339 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1345 auto const bobSeq = env.seq(bob);
1346 auto const carolSeq = env.seq(carol);
1347 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1350 auto const jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 200}, bobSeq + 1);
1351 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 300}, carolSeq);
1353 env(batch::outer(bob, bobSeq, batchFee, tfOnlyOne),
1354 batch::Inner(jv1, bobSeq + 1),
1355 batch::Inner(jv2, carolSeq),
1361 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1362 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
1363 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
1368 auto const bobSeq = env.seq(bob);
1369 auto const carolSeq = env.seq(carol);
1370 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1372 auto jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 200}, bobSeq + 1);
1373 auto jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 5}, carolSeq);
1375 env(batch::outer(bob, bobSeq, batchFee, tfOnlyOne),
1376 batch::Inner(jv1, bobSeq + 1),
1377 batch::Inner(jv2, carolSeq),
1383 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1384 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 55);
1385 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 5);
1392 testcase(
"Batch confidential MPT - until failure");
1395 Env env{*
this, features};
1401 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1408 auto const bobSeq = env.seq(bob);
1409 auto const carolSeq = env.seq(carol);
1410 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1412 auto const jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 200}, bobSeq + 1);
1413 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 5}, carolSeq);
1415 env(batch::outer(bob, bobSeq, batchFee, tfUntilFailure),
1416 batch::Inner(jv1, bobSeq + 1),
1417 batch::Inner(jv2, carolSeq),
1422 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1423 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
1428 auto const bobSeq = env.seq(bob);
1429 auto const carolSeq = env.seq(carol);
1430 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1432 auto const jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 10}, bobSeq + 1);
1433 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 5}, carolSeq);
1435 env(batch::outer(bob, bobSeq, batchFee, tfUntilFailure),
1436 batch::Inner(jv1, bobSeq + 1),
1437 batch::Inner(jv2, carolSeq),
1443 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 90);
1444 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 55);
1445 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 15);
1452 testcase(
"Batch confidential MPT - independent");
1455 Env env{*
this, features};
1461 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1469 auto const bobSeq = env.seq(bob);
1470 auto const carolSeq = env.seq(carol);
1471 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 3);
1473 auto const jv1 = mpt.sendJV({.account = bob, .dest = dave, .amt = 10}, bobSeq + 1);
1476 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 300}, carolSeq);
1477 auto const jv3 = mpt.sendJV({.account = carol, .dest = dave, .amt = 5}, carolSeq + 1);
1479 env(batch::outer(bob, bobSeq, batchFee, tfIndependent),
1480 batch::Inner(jv1, bobSeq + 1),
1481 batch::Inner(jv2, carolSeq),
1482 batch::Inner(jv3, carolSeq + 1),
1488 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 90);
1490 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 55);
1492 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 15);
1504 testcase(
"Batch confidential MPT with tickets");
1510 Env env{*
this, features};
1516 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1521 env(ticket::create(bob, 1));
1524 auto const bobSeq = env.seq(bob);
1526 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1530 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq);
1531 auto const chain1 = mpt.chainAfterSend(bob, 40, jv1);
1533 mpt.sendJV({.account = bob, .dest = dave, .amt = 20}, bobSeq + 1, chain1);
1535 env(batch::outer(bob, 0, batchFee, tfAllOrNothing),
1536 batch::Inner(jv1, bobSeq),
1537 batch::Inner(jv2, bobSeq + 1),
1538 ticket::Use(outerTicketSeq),
1543 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 40);
1544 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 40);
1545 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 20);
1552 Env env{*
this, features};
1558 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1564 env(ticket::create(bob, 2));
1567 auto const bobSeq = env.seq(bob);
1568 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1571 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, ticketSeq1);
1573 auto const chain1 = mpt.chainAfterSend(bob, 40, jv1);
1575 mpt.sendJV({.account = bob, .dest = dave, .amt = 30}, ticketSeq2, chain1);
1577 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1578 batch::Inner(jv1, 0, ticketSeq1),
1579 batch::Inner(jv2, 0, ticketSeq2),
1584 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 30);
1585 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 40);
1586 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 30);
1591 Env env{*
this, features};
1597 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1601 env(ticket::create(bob, 1));
1604 auto const bobSeq = env.seq(bob);
1605 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1608 auto const badJV = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq + 1);
1609 auto const jv2 = mpt.mergeInboxJV({.account = bob});
1611 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1612 batch::Inner(badJV, 0, ticketSeq),
1613 batch::Inner(jv2, bobSeq + 1),
1617 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1618 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
1628 testcase(
"Confidential transfers through delegation");
1631 Env env{*
this, features};
1637 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1638 env.fund(XRP(10000), dave);
1643 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback |
1644 tfMPTCanHoldConfidentialBalance,
1646 mptAlice.authorize({.account = bob});
1647 mptAlice.authorize({.account = carol});
1648 mptAlice.pay(alice, bob, 200);
1649 mptAlice.pay(alice, carol, 100);
1651 mptAlice.generateKeyPair(alice);
1652 mptAlice.generateKeyPair(bob);
1653 mptAlice.generateKeyPair(carol);
1654 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
1658 env(delegate::set(bob, dave, {
"ConfidentialMPTConvert"}), Ter(
temMALFORMED));
1662 env(delegate::set(bob, dave, {
"ConfidentialMPTMergeInbox"}));
1670 .holderPubKey = mptAlice.getPubKey(bob),
1679 .holderPubKey = mptAlice.getPubKey(bob),
1681 env.require(MptBalance(mptAlice, bob, 100));
1684 mptAlice.convert({.account = bob, .amt = 50});
1687 mptAlice.mergeInbox({.account = bob, .delegate = dave});
1693 .holderPubKey = mptAlice.getPubKey(carol),
1695 mptAlice.mergeInbox({.account = carol});
1706 env(delegate::set(bob, dave, {
"ConfidentialMPTMergeInbox",
"ConfidentialMPTSend"}));
1710 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = dave});
1711 mptAlice.mergeInbox({.account = carol});
1714 mptAlice.convertBack(
1721 {
"ConfidentialMPTMergeInbox",
"ConfidentialMPTSend",
"ConfidentialMPTConvertBack"}));
1725 mptAlice.convertBack({.account = bob, .amt = 10, .delegate = dave});
1728 mptAlice.confidentialClaw(
1732 env(delegate::set(alice, dave, {
"ConfidentialMPTClawback"}));
1736 mptAlice.confidentialClaw({.holder = bob, .amt = 130, .delegate = dave});
1743 testcase(
"Confidential delegation revocation");
1746 Env env{*
this, features};
1751 MPTTester mptAlice(env, alice, {.holders = {bob}});
1752 env.fund(XRP(10000), carol);
1757 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
1759 mptAlice.authorize({.account = bob});
1760 mptAlice.pay(alice, bob, 100);
1762 mptAlice.generateKeyPair(alice);
1763 mptAlice.generateKeyPair(bob);
1764 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
1767 auto const bobOwnersBefore =
ownerCount(env, bob);
1768 env(delegate::set(bob, carol, {
"ConfidentialMPTMergeInbox"}));
1770 env.require(Owners(bob, bobOwnersBefore + 1));
1776 .holderPubKey = mptAlice.getPubKey(bob),
1778 mptAlice.mergeInbox({.account = bob, .delegate = carol});
1783 env.require(Owners(bob, bobOwnersBefore));
1786 mptAlice.convert({.account = bob, .amt = 30});
1789 mptAlice.mergeInbox({
1796 mptAlice.mergeInbox({.account = bob});
1804 testcase(
"Confidential delegation with auditor");
1807 Env env{*
this, features};
1812 Account const auditor{
"auditor"};
1814 MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor});
1815 env.fund(XRP(10000), dave);
1820 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
1822 mptAlice.authorize({.account = bob});
1823 mptAlice.authorize({.account = carol});
1824 mptAlice.pay(alice, bob, 100);
1825 mptAlice.pay(alice, carol, 100);
1827 mptAlice.generateKeyPair(alice);
1828 mptAlice.generateKeyPair(bob);
1829 mptAlice.generateKeyPair(carol);
1830 mptAlice.generateKeyPair(auditor);
1832 .issuerPubKey = mptAlice.getPubKey(alice),
1833 .auditorPubKey = mptAlice.getPubKey(auditor),
1837 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
1844 .holderPubKey = mptAlice.getPubKey(bob),
1846 mptAlice.mergeInbox({.account = bob});
1851 .holderPubKey = mptAlice.getPubKey(carol),
1853 mptAlice.mergeInbox({.account = carol});
1856 mptAlice.send({.account = bob, .dest = carol, .amt = 20, .delegate = dave});
1857 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = dave});
1860 env(delegate::set(bob, auditor, {
"ConfidentialMPTSend",
"ConfidentialMPTConvertBack"}));
1864 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = auditor});
1865 mptAlice.convertBack({.account = bob, .amt = 10, .delegate = auditor});
1928 testcase(
"Batch ConfidentialMPTSend with delegation");
1934 Env env{*
this, features};
1940 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1943 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
1946 auto const bobSeq = env.seq(bob);
1947 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1950 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 60}, bobSeq + 1);
1951 jv1[jss::Delegate] = dave.human();
1953 auto jv2 = mpt.sendJV({.account = bob, .dest = dave, .amt = 60}, bobSeq + 2);
1954 jv2[jss::Delegate] = dave.human();
1956 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1957 batch::Inner(jv1, bobSeq + 1),
1958 batch::Inner(jv2, bobSeq + 2),
1964 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
1965 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
1966 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
1971 Env env{*
this, features};
1977 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1980 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
1983 auto const bobSeq = env.seq(bob);
1984 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
1987 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq + 1);
1988 jv1[jss::Delegate] = dave.human();
1989 auto const chain1 = mpt.chainAfterSend(bob, 40, jv1);
1991 auto jv2 = mpt.sendJV({.account = bob, .dest = dave, .amt = 40}, bobSeq + 2, chain1);
1992 jv2[jss::Delegate] = dave.human();
1994 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1995 batch::Inner(jv1, bobSeq + 1),
1996 batch::Inner(jv2, bobSeq + 2),
2002 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 20);
2003 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 40);
2004 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 40);
2012 testcase(
"Batch delegation missing permission");
2018 Env env{*
this, features};
2024 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2028 env(delegate::set(bob, dave, {
"ConfidentialMPTMergeInbox"}));
2031 auto const bobSeq = env.seq(bob);
2032 auto const carolSeq = env.seq(carol);
2033 auto const batchFee = batch::calcConfidentialBatchFee(env, 2, 2);
2036 auto const jv1 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2038 auto jv2 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
2039 jv2[jss::Delegate] = dave.human();
2041 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
2042 batch::Inner(jv1, carolSeq),
2043 batch::Inner(jv2, bobSeq + 1),
2044 batch::Sig(carol, dave),
2050 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2051 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
2052 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2058 Env env{*
this, features};
2064 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2068 auto const bobSeq = env.seq(bob);
2069 auto const carolSeq = env.seq(carol);
2070 auto const batchFee = batch::calcConfidentialBatchFee(env, 2, 2);
2072 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
2073 jv1[jss::Delegate] = dave.human();
2074 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2076 env(batch::outer(bob, bobSeq, batchFee, tfIndependent),
2077 batch::Inner(jv1, bobSeq + 1),
2078 batch::Inner(jv2, carolSeq),
2079 batch::Sig(carol, dave),
2084 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2085 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 30);
2086 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 30);
2094 testcase(
"Test batch delegated send with delegate as outer account");
2101 Env env{*
this, features};
2107 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2110 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
2113 auto const daveSeq = env.seq(dave);
2114 auto const bobSeq = env.seq(bob);
2115 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
2117 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq);
2118 jv1[jss::Delegate] = dave.human();
2119 auto const jv2 = mpt.mergeInboxJV({.account = dave});
2121 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2122 batch::Inner(jv1, bobSeq),
2123 batch::Inner(jv2, daveSeq + 1),
2127 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 60);
2128 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 40);
2134 Env env{*
this, features};
2140 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2143 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
2146 auto const daveSeq = env.seq(dave);
2147 auto const bobSeq = env.seq(bob);
2148 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
2150 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq);
2151 auto const chain1 = mpt.chainAfterSend(bob, 40, jv1);
2152 auto jv2 = mpt.sendJV({.account = bob, .dest = carol, .amt = 30}, bobSeq + 1, chain1);
2153 jv2[jss::Delegate] = dave.human();
2156 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2157 batch::Inner(jv1, bobSeq),
2158 batch::Inner(jv2, bobSeq + 1),
2164 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 30);
2165 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 70);
2173 Env env{*
this, features};
2179 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2183 auto const daveSeq = env.seq(dave);
2184 auto const bobSeq = env.seq(bob);
2185 auto const carolSeq = env.seq(carol);
2186 auto const batchFee = batch::calcConfidentialBatchFee(env, 2, 2);
2188 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq);
2189 jv1[jss::Delegate] = dave.human();
2190 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2192 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2193 batch::Inner(jv1, bobSeq),
2194 batch::Inner(jv2, carolSeq),
2195 batch::Sig(bob, carol),
2200 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2201 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
2202 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2210 testcase(
"Batch delegated confidential multiple operations");
2213 Env env{*
this, features};
2221 MPTTester mpt(env, alice, {.holders = {bob, carol, dave, frank}});
2223 mpt.pay(alice, bob, 50);
2224 env.fund(XRP(10000), erin);
2227 mpt.authorize({.account = frank});
2228 mpt.pay(alice, frank, 40);
2229 mpt.generateKeyPair(frank);
2231 env(delegate::set(bob, dave, {
"ConfidentialMPTConvertBack"}));
2232 env(delegate::set(carol, erin, {
"ConfidentialMPTSend"}));
2233 env(delegate::set(bob, erin, {
"ConfidentialMPTMergeInbox"}));
2236 auto const daveSeq = env.seq(dave);
2237 auto const bobSeq = env.seq(bob);
2238 auto const carolSeq = env.seq(carol);
2239 auto const frankSeq = env.seq(frank);
2240 auto const batchFee = batch::calcConfidentialBatchFee(env, 4, 6);
2246 auto jv1 = mpt.convertBackJV({.account = bob, .amt = 30}, bobSeq);
2247 jv1[jss::Delegate] = dave.human();
2248 auto const jv2 = mpt.convertJV({.account = bob, .amt = 20}, bobSeq + 1);
2249 auto jv3 = mpt.sendJV({.account = carol, .dest = bob, .amt = 15}, carolSeq);
2250 jv3[jss::Delegate] = erin.human();
2251 auto const jv4 = mpt.convertJV(
2252 {.account = frank, .amt = 25, .holderPubKey = mpt.getPubKey(frank)}, frankSeq);
2253 auto const jv5 = mpt.mergeInboxJV({.account = frank});
2254 auto jv6 = mpt.mergeInboxJV({.account = bob});
2255 jv6[jss::Delegate] = erin.human();
2257 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2258 batch::Inner(jv1, bobSeq),
2259 batch::Inner(jv2, bobSeq + 1),
2260 batch::Inner(jv3, carolSeq),
2261 batch::Inner(jv4, frankSeq),
2262 batch::Inner(jv5, frankSeq + 1),
2263 batch::Inner(jv6, bobSeq + 2),
2264 batch::Sig(erin, frank, bob),
2268 env.require(MptBalance(mpt, bob, 60));
2269 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 105);
2270 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedInbox) == 0);
2271 env.require(MptBalance(mpt, carol, 0));
2272 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 45);
2273 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
2274 env.require(MptBalance(mpt, frank, 15));
2275 BEAST_EXPECT(mpt.getDecryptedBalance(frank, MPTTester::holderEncryptedSpending) == 25);
2276 BEAST_EXPECT(mpt.getDecryptedBalance(frank, MPTTester::holderEncryptedInbox) == 0);
2277 env.require(MptBalance(mpt, dave, 0));
2278 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedSpending) == 0);
2279 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2280 auto const outstandingBalance = mpt.getIssuanceOutstandingBalance();
2281 BEAST_EXPECT(outstandingBalance && *outstandingBalance == 250);
2282 BEAST_EXPECT(mpt.getIssuanceConfidentialBalance() == 175);
2292 testcase(
"Invalid cases for delegation with tickets");
2295 Env env{*
this, features};
2299 MPTTester mptAlice(env, alice, {.holders = {bob}});
2300 env.fund(XRP(10000), carol);
2305 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback,
2307 mptAlice.authorize({.account = bob});
2308 mptAlice.pay(alice, bob, 200);
2310 mptAlice.generateKeyPair(alice);
2311 mptAlice.generateKeyPair(bob);
2312 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
2315 mptAlice.convert({.account = bob, .amt = 100, .holderPubKey = mptAlice.getPubKey(bob)});
2316 mptAlice.mergeInbox({.account = bob});
2319 env(delegate::set(bob, carol, {
"ConfidentialMPTConvertBack"}));
2322 uint64_t
const amt = 10;
2327 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
2328 "Missing spending balance.");
2330 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
2331 "Missing encrypted spending balance.");
2332 auto const version = mptAlice.getMPTokenVersion(bob);
2334 auto const pc = mptAlice.getPedersenCommitment(spendingBalance, pcBf);
2338 return mptAlice.getConvertBackProof(
2343 .pedersenCommitment = pc,
2344 .amt = spendingBalance,
2345 .encryptedAmt = encSpending,
2346 .blindingFactor = pcBf,
2352 auto const ticketSeq = env.seq(bob) + 1;
2353 env(ticket::create(bob, 1));
2355 mptAlice.convertBack({
2358 .proof = proofForSeq(ticketSeq + 1),
2359 .pedersenCommitment = pc,
2361 .ticketSeq = ticketSeq,
2368 auto const ticketSeq = env.seq(bob) + 1;
2369 env(ticket::create(bob, 1));
2371 mptAlice.convertBack({
2374 .proof = proofForSeq(env.seq(bob)),
2375 .pedersenCommitment = pc,
2377 .ticketSeq = ticketSeq,
2384 mptAlice.convertBack({
2388 .ticketSeq = env.seq(bob) + 100,
2395 mptAlice.convertBack({
2407 auto const carolTicketSeq = env.seq(carol) + 1;
2408 env(ticket::create(carol, 1));
2410 mptAlice.convertBack({
2414 .ticketSeq = carolTicketSeq,
2422 auto const ticketSeq = env.seq(bob) + 1;
2423 env(ticket::create(bob, 1));
2426 mptAlice.convertBack({
2429 .proof = proofForSeq(ticketSeq),
2430 .pedersenCommitment = pc,
2440 auto const ticketSeq = env.seq(bob) + 1;
2441 env(ticket::create(bob, 1));
2443 mptAlice.convertBack({
2447 .ticketSeq = ticketSeq,
2458 testcase(
"Confidential delegation with tickets");
2461 Env env{*
this, features};
2466 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
2467 env.fund(XRP(10000), dave);
2472 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback,
2474 mptAlice.authorize({.account = bob});
2475 mptAlice.authorize({.account = carol});
2476 mptAlice.pay(alice, bob, 200);
2477 mptAlice.pay(alice, carol, 100);
2479 mptAlice.generateKeyPair(alice);
2480 mptAlice.generateKeyPair(bob);
2481 mptAlice.generateKeyPair(carol);
2482 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
2488 {
"ConfidentialMPTMergeInbox",
"ConfidentialMPTSend",
"ConfidentialMPTConvertBack"}));
2490 env(delegate::set(alice, dave, {
"ConfidentialMPTClawback"}));
2494 auto ticketSeq = env.seq(bob) + 1;
2495 env(ticket::create(bob, 1));
2496 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2500 .holderPubKey = mptAlice.getPubKey(bob),
2501 .ticketSeq = ticketSeq,
2503 env.require(MptBalance(mptAlice, bob, 100));
2506 ticketSeq = env.seq(bob) + 1;
2507 env(ticket::create(bob, 1));
2508 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2509 mptAlice.mergeInbox({.account = bob, .delegate = dave, .ticketSeq = ticketSeq});
2515 .holderPubKey = mptAlice.getPubKey(carol),
2517 mptAlice.mergeInbox({.account = carol});
2520 ticketSeq = env.seq(bob) + 1;
2521 env(ticket::create(bob, 1));
2522 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2528 .ticketSeq = ticketSeq,
2532 ticketSeq = env.seq(bob) + 1;
2533 env(ticket::create(bob, 1));
2534 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2535 mptAlice.convertBack({
2539 .ticketSeq = ticketSeq,
2543 ticketSeq = env.seq(alice) + 1;
2544 env(ticket::create(alice, 1));
2545 BEAST_EXPECT(env.seq(alice) != ticketSeq);
2546 mptAlice.confidentialClaw({
2550 .ticketSeq = ticketSeq,