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)});
1657 env(delegate::set(bob, dave, {
"ConfidentialMPTConvert",
"ConfidentialMPTMergeInbox"}));
1664 .holderPubKey = mptAlice.getPubKey(bob),
1673 .holderPubKey = mptAlice.getPubKey(bob),
1676 env.require(MptBalance(mptAlice, bob, 100));
1679 mptAlice.convert({.account = bob, .amt = 50, .delegate = dave});
1682 mptAlice.mergeInbox({.account = bob, .delegate = dave});
1688 .holderPubKey = mptAlice.getPubKey(carol),
1690 mptAlice.mergeInbox({.account = carol});
1704 {
"ConfidentialMPTConvert",
"ConfidentialMPTMergeInbox",
"ConfidentialMPTSend"}));
1708 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = dave});
1709 mptAlice.mergeInbox({.account = carol});
1712 mptAlice.convertBack(
1719 {
"ConfidentialMPTConvert",
1720 "ConfidentialMPTMergeInbox",
1721 "ConfidentialMPTSend",
1722 "ConfidentialMPTConvertBack"}));
1726 mptAlice.convertBack({.account = bob, .amt = 10, .delegate = dave});
1729 mptAlice.confidentialClaw(
1733 env(delegate::set(alice, dave, {
"ConfidentialMPTClawback"}));
1737 mptAlice.confidentialClaw({.holder = bob, .amt = 130, .delegate = dave});
1744 testcase(
"Confidential delegation revocation");
1747 Env env{*
this, features};
1752 MPTTester mptAlice(env, alice, {.holders = {bob}});
1753 env.fund(XRP(10000), carol);
1758 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
1760 mptAlice.authorize({.account = bob});
1761 mptAlice.pay(alice, bob, 100);
1763 mptAlice.generateKeyPair(alice);
1764 mptAlice.generateKeyPair(bob);
1765 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
1768 auto const bobOwnersBefore = ownerCount(env, bob);
1769 env(delegate::set(bob, carol, {
"ConfidentialMPTConvert",
"ConfidentialMPTMergeInbox"}));
1771 env.require(Owners(bob, bobOwnersBefore + 1));
1777 .holderPubKey = mptAlice.getPubKey(bob),
1780 mptAlice.mergeInbox({.account = bob, .delegate = carol});
1785 env.require(Owners(bob, bobOwnersBefore));
1796 mptAlice.convert({.account = bob, .amt = 30});
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",
"ConfidentialMPTConvert"}));
1844 .holderPubKey = mptAlice.getPubKey(bob),
1847 mptAlice.mergeInbox({.account = bob});
1852 .holderPubKey = mptAlice.getPubKey(carol),
1854 mptAlice.mergeInbox({.account = carol});
1857 mptAlice.send({.account = bob, .dest = carol, .amt = 20, .delegate = dave});
1858 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = dave});
1861 env(delegate::set(bob, auditor, {
"ConfidentialMPTSend",
"ConfidentialMPTConvertBack"}));
1865 mptAlice.send({.account = bob, .dest = carol, .amt = 10, .delegate = auditor});
1866 mptAlice.convertBack({.account = bob, .amt = 10, .delegate = auditor});
1929 testcase(
"Batch ConfidentialMPTSend with delegation");
1935 Env env{*
this, features};
1941 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
1944 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
1947 auto const bobSeq = env.seq(bob);
1948 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
1951 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 60}, bobSeq + 1);
1952 jv1[jss::Delegate] = dave.human();
1954 auto jv2 = mpt.sendJV({.account = bob, .dest = dave, .amt = 60}, bobSeq + 2);
1955 jv2[jss::Delegate] = dave.human();
1957 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
1958 batch::Inner(jv1, bobSeq + 1),
1959 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, 0, 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),
2001 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 20);
2002 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 40);
2003 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 40);
2011 testcase(
"Batch delegation missing permission");
2017 Env env{*
this, features};
2023 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2027 env(delegate::set(bob, dave, {
"ConfidentialMPTMergeInbox"}));
2030 auto const bobSeq = env.seq(bob);
2031 auto const carolSeq = env.seq(carol);
2032 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
2035 auto const jv1 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2037 auto jv2 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
2038 jv2[jss::Delegate] = dave.human();
2040 env(batch::outer(bob, bobSeq, batchFee, tfAllOrNothing),
2041 batch::Inner(jv1, carolSeq),
2042 batch::Inner(jv2, bobSeq + 1),
2049 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2050 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
2051 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2057 Env env{*
this, features};
2063 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2067 auto const bobSeq = env.seq(bob);
2068 auto const carolSeq = env.seq(carol);
2069 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
2071 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq + 1);
2072 jv1[jss::Delegate] = dave.human();
2073 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2075 env(batch::outer(bob, bobSeq, batchFee, tfIndependent),
2076 batch::Inner(jv1, bobSeq + 1),
2077 batch::Inner(jv2, carolSeq),
2083 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2084 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 30);
2085 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 30);
2093 testcase(
"Test batch delegated send with delegate as outer account");
2099 Env env{*
this, features};
2105 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2108 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
2111 auto const daveSeq = env.seq(dave);
2112 auto const bobSeq = env.seq(bob);
2113 auto const batchFee = batch::calcConfidentialBatchFee(env, 0, 2);
2115 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq);
2116 jv1[jss::Delegate] = dave.human();
2117 auto const jv2 = mpt.mergeInboxJV({.account = dave});
2119 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2120 batch::Inner(jv1, bobSeq),
2121 batch::Inner(jv2, daveSeq + 1),
2125 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2126 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
2132 Env env{*
this, features};
2138 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2141 env(delegate::set(bob, dave, {
"ConfidentialMPTSend"}));
2144 auto const daveSeq = env.seq(dave);
2145 auto const bobSeq = env.seq(bob);
2146 auto const batchFee = batch::calcConfidentialBatchFee(env, 1, 2);
2148 auto const jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 40}, bobSeq);
2149 auto const chain1 = mpt.chainAfterSend(bob, 40, jv1);
2150 auto jv2 = mpt.sendJV({.account = bob, .dest = carol, .amt = 30}, bobSeq + 1, chain1);
2151 jv2[jss::Delegate] = dave.human();
2154 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2155 batch::Inner(jv1, bobSeq),
2156 batch::Inner(jv2, bobSeq + 1),
2162 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 30);
2163 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 70);
2169 Env env{*
this, features};
2175 MPTTester mpt(env, alice, {.holders = {bob, carol, dave}});
2179 auto const daveSeq = env.seq(dave);
2180 auto const bobSeq = env.seq(bob);
2181 auto const carolSeq = env.seq(carol);
2182 auto const batchFee = batch::calcConfidentialBatchFee(env, 2, 2);
2184 auto jv1 = mpt.sendJV({.account = bob, .dest = carol, .amt = 50}, bobSeq);
2185 jv1[jss::Delegate] = dave.human();
2186 auto const jv2 = mpt.sendJV({.account = carol, .dest = dave, .amt = 30}, carolSeq);
2188 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2189 batch::Inner(jv1, bobSeq),
2190 batch::Inner(jv2, carolSeq),
2191 batch::Sig(bob, carol),
2196 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 100);
2197 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 60);
2198 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2206 testcase(
"Batch delegated confidential multiple operations");
2209 Env env{*
this, features};
2217 MPTTester mpt(env, alice, {.holders = {bob, carol, dave, frank}});
2219 mpt.pay(alice, bob, 50);
2220 env.fund(XRP(10000), erin);
2223 mpt.authorize({.account = frank});
2224 mpt.pay(alice, frank, 40);
2225 mpt.generateKeyPair(frank);
2227 env(delegate::set(bob, dave, {
"ConfidentialMPTConvert",
"ConfidentialMPTConvertBack"}));
2228 env(delegate::set(carol, erin, {
"ConfidentialMPTSend"}));
2229 env(delegate::set(bob, erin, {
"ConfidentialMPTMergeInbox"}));
2232 auto const daveSeq = env.seq(dave);
2233 auto const bobSeq = env.seq(bob);
2234 auto const carolSeq = env.seq(carol);
2235 auto const frankSeq = env.seq(frank);
2236 auto const batchFee = batch::calcConfidentialBatchFee(env, 3, 6);
2241 auto jv1 = mpt.convertBackJV({.account = bob, .amt = 30}, bobSeq);
2242 jv1[jss::Delegate] = dave.human();
2243 auto jv2 = mpt.convertJV({.account = bob, .amt = 20}, bobSeq + 1);
2244 jv2[jss::Delegate] = dave.human();
2245 auto jv3 = mpt.sendJV({.account = carol, .dest = bob, .amt = 15}, carolSeq);
2246 jv3[jss::Delegate] = erin.human();
2247 auto const jv4 = mpt.convertJV(
2248 {.account = frank, .amt = 25, .holderPubKey = mpt.getPubKey(frank)}, frankSeq);
2249 auto const jv5 = mpt.mergeInboxJV({.account = frank});
2250 auto jv6 = mpt.mergeInboxJV({.account = bob});
2251 jv6[jss::Delegate] = erin.human();
2253 env(batch::outer(dave, daveSeq, batchFee, tfAllOrNothing),
2254 batch::Inner(jv1, bobSeq),
2255 batch::Inner(jv2, bobSeq + 1),
2256 batch::Inner(jv3, carolSeq),
2257 batch::Inner(jv4, frankSeq),
2258 batch::Inner(jv5, frankSeq + 1),
2259 batch::Inner(jv6, bobSeq + 2),
2260 batch::Sig(bob, carol, frank),
2264 env.require(MptBalance(mpt, bob, 60));
2265 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending) == 105);
2266 BEAST_EXPECT(mpt.getDecryptedBalance(bob, MPTTester::holderEncryptedInbox) == 0);
2267 env.require(MptBalance(mpt, carol, 0));
2268 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedSpending) == 45);
2269 BEAST_EXPECT(mpt.getDecryptedBalance(carol, MPTTester::holderEncryptedInbox) == 0);
2270 env.require(MptBalance(mpt, frank, 15));
2271 BEAST_EXPECT(mpt.getDecryptedBalance(frank, MPTTester::holderEncryptedSpending) == 25);
2272 BEAST_EXPECT(mpt.getDecryptedBalance(frank, MPTTester::holderEncryptedInbox) == 0);
2273 env.require(MptBalance(mpt, dave, 0));
2274 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedSpending) == 0);
2275 BEAST_EXPECT(mpt.getDecryptedBalance(dave, MPTTester::holderEncryptedInbox) == 0);
2276 auto const outstandingBalance = mpt.getIssuanceOutstandingBalance();
2277 BEAST_EXPECT(outstandingBalance && *outstandingBalance == 250);
2278 BEAST_EXPECT(mpt.getIssuanceConfidentialBalance() == 175);
2285 testcase(
"Invalid cases for delegation with tickets");
2288 Env env{*
this, features};
2292 MPTTester mptAlice(env, alice, {.holders = {bob}});
2293 env.fund(XRP(10000), carol);
2298 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback,
2300 mptAlice.authorize({.account = bob});
2301 mptAlice.pay(alice, bob, 200);
2303 mptAlice.generateKeyPair(alice);
2304 mptAlice.generateKeyPair(bob);
2305 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
2308 env(delegate::set(bob, carol, {
"ConfidentialMPTConvert"}));
2311 uint64_t
const amt = 10;
2313 auto const holderCt = mptAlice.encryptAmount(bob, amt, bf);
2314 auto const issuerCt = mptAlice.encryptAmount(alice, amt, bf);
2318 auto const ticketSeq = env.seq(bob) + 1;
2319 env(ticket::create(bob, 1));
2321 auto const badCtxHash =
2324 mptAlice.getSchnorrProof(bob, badCtxHash),
"Missing Schnorr Proof.");
2329 .proof =
strHex(badProof),
2330 .holderPubKey = mptAlice.getPubKey(bob),
2331 .holderEncryptedAmt = holderCt,
2332 .issuerEncryptedAmt = issuerCt,
2333 .blindingFactor = bf,
2335 .ticketSeq = ticketSeq,
2342 auto const ticketSeq = env.seq(bob) + 1;
2343 env(ticket::create(bob, 1));
2346 mptAlice.getSchnorrProof(bob, badCtxHash),
"Missing Schnorr Proof.");
2351 .proof =
strHex(badProof),
2352 .holderPubKey = mptAlice.getPubKey(bob),
2353 .holderEncryptedAmt = holderCt,
2354 .issuerEncryptedAmt = issuerCt,
2355 .blindingFactor = bf,
2357 .ticketSeq = ticketSeq,
2367 .holderPubKey = mptAlice.getPubKey(bob),
2368 .holderEncryptedAmt = holderCt,
2369 .issuerEncryptedAmt = issuerCt,
2370 .blindingFactor = bf,
2372 .ticketSeq = env.seq(bob) + 100,
2382 .holderPubKey = mptAlice.getPubKey(bob),
2383 .holderEncryptedAmt = holderCt,
2384 .issuerEncryptedAmt = issuerCt,
2385 .blindingFactor = bf,
2394 auto const carolTicketSeq = env.seq(carol) + 1;
2395 env(ticket::create(carol, 1));
2400 .holderPubKey = mptAlice.getPubKey(bob),
2401 .holderEncryptedAmt = holderCt,
2402 .issuerEncryptedAmt = issuerCt,
2403 .blindingFactor = bf,
2405 .ticketSeq = carolTicketSeq,
2413 auto const ticketSeq = env.seq(bob) + 1;
2414 env(ticket::create(bob, 1));
2417 auto const ctxHashForTicket =
2420 mptAlice.getSchnorrProof(bob, ctxHashForTicket),
"Missing Schnorr Proof.");
2427 .holderPubKey = mptAlice.getPubKey(bob),
2428 .holderEncryptedAmt = holderCt,
2429 .issuerEncryptedAmt = issuerCt,
2430 .blindingFactor = bf,
2443 testcase(
"Confidential delegation with tickets");
2446 Env env{*
this, features};
2451 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
2452 env.fund(XRP(10000), dave);
2457 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback,
2459 mptAlice.authorize({.account = bob});
2460 mptAlice.authorize({.account = carol});
2461 mptAlice.pay(alice, bob, 200);
2462 mptAlice.pay(alice, carol, 100);
2464 mptAlice.generateKeyPair(alice);
2465 mptAlice.generateKeyPair(bob);
2466 mptAlice.generateKeyPair(carol);
2467 mptAlice.set({.issuerPubKey = mptAlice.getPubKey(alice)});
2473 {
"ConfidentialMPTConvert",
2474 "ConfidentialMPTMergeInbox",
2475 "ConfidentialMPTSend",
2476 "ConfidentialMPTConvertBack"}));
2478 env(delegate::set(alice, dave, {
"ConfidentialMPTClawback"}));
2482 auto ticketSeq = env.seq(bob) + 1;
2483 env(ticket::create(bob, 1));
2484 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2488 .holderPubKey = mptAlice.getPubKey(bob),
2490 .ticketSeq = ticketSeq,
2492 env.require(MptBalance(mptAlice, bob, 100));
2495 ticketSeq = env.seq(bob) + 1;
2496 env(ticket::create(bob, 1));
2497 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2498 mptAlice.mergeInbox({.account = bob, .delegate = dave, .ticketSeq = ticketSeq});
2504 .holderPubKey = mptAlice.getPubKey(carol),
2506 mptAlice.mergeInbox({.account = carol});
2509 ticketSeq = env.seq(bob) + 1;
2510 env(ticket::create(bob, 1));
2511 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2517 .ticketSeq = ticketSeq,
2521 ticketSeq = env.seq(bob) + 1;
2522 env(ticket::create(bob, 1));
2523 BEAST_EXPECT(env.seq(bob) != ticketSeq);
2524 mptAlice.convertBack({
2528 .ticketSeq = ticketSeq,
2532 ticketSeq = env.seq(alice) + 1;
2533 env(ticket::create(alice, 1));
2534 BEAST_EXPECT(env.seq(alice) != ticketSeq);
2535 mptAlice.confidentialClaw({
2539 .ticketSeq = ticketSeq,