2#include <test/jtx/mpt.h>
4#include <test/jtx/Account.h>
5#include <test/jtx/Env.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/credentials.h>
8#include <test/jtx/owners.h>
9#include <test/jtx/pay.h>
10#include <test/jtx/ter.h>
11#include <test/jtx/trust.h>
13#include <xrpl/basics/Slice.h>
14#include <xrpl/basics/StringUtilities.h>
15#include <xrpl/basics/base_uint.h>
16#include <xrpl/basics/contract.h>
17#include <xrpl/basics/strHex.h>
18#include <xrpl/beast/unit_test/suite.h>
19#include <xrpl/json/json_value.h>
20#include <xrpl/ledger/helpers/MPTokenHelpers.h>
21#include <xrpl/protocol/AccountID.h>
22#include <xrpl/protocol/Asset.h>
23#include <xrpl/protocol/ConfidentialTransfer.h>
24#include <xrpl/protocol/Indexes.h>
25#include <xrpl/protocol/LedgerFormats.h>
26#include <xrpl/protocol/Protocol.h>
27#include <xrpl/protocol/Rate.h>
28#include <xrpl/protocol/SField.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/TxFlags.h>
31#include <xrpl/protocol/UintTypes.h>
32#include <xrpl/protocol/jss.h>
33#include <xrpl/tx/transactors/token/MPTokenIssuanceSet.h>
35#include <utility/mpt_utility.h>
37#include <mpt_protocol.h>
39#include <secp256k1_mpt.h>
48#include <source_location>
59constexpr std::uint64_t kElGamalDecryptRangeLow = 0;
60constexpr std::uint64_t kElGamalDecryptRangeHigh = 3000;
75 std::optional<T>
const& opt,
82 std::string(what) +
" must be present (called from " +
83 std::string(loc.function_name()) +
")");
94mpt_pedersen_proof_params
97 mpt_pedersen_proof_params res{};
99 res.pedersen_commitment, params.pedersenCommitment.data(), kMPT_PEDERSEN_COMMIT_SIZE);
100 res.amount = params.amt;
101 std::memcpy(res.ciphertext, params.encryptedAmt.data(), kMPT_ELGAMAL_TOTAL_SIZE);
102 std::memcpy(res.blinding_factor, params.blindingFactor.data(), kMPT_BLINDING_FACTOR_SIZE);
114setAccountField(json::Value& jv, std::optional<Account>
const& account)
116 Account const& act = requireValue(account,
"account");
117 jv[sfAccount] = act.human();
129setDestinationField(json::Value& jv, std::optional<Account>
const& dest)
131 Account const& act = requireValue(dest,
"dest");
132 jv[sfDestination] = act.human();
145setProofOrDummy(json::Value& jv, std::optional<Buffer>
const& proof, std::size_t dummyLen)
158[[nodiscard]] std::optional<Buffer>
160 std::unordered_map<
AccountID, std::vector<Buffer>>
const& keys,
162 std::optional<std::uint32_t> epoch)
164 auto const it = keys.find(account);
165 if (it == keys.end() || it->second.empty())
169 return it->second.back();
171 if (*epoch >= it->second.size())
174 return it->second[*
epoch];
183checkSiteReason(std::source_location
const& checkLoc)
185 return std::string(
"check ") + std::filesystem::path{checkLoc.
file_name()}.filename().string() +
220 for (
auto const& h : holders)
222 if (accounts.
find(h.human()) != accounts.
cend())
224 accounts.
emplace(h.human(), h);
238 env_.fund(arg.xrp, issuer_);
239 for (auto const& it : holders_)
240 env_.fund(arg.xrpHolders, it.second);
243 env_.fund(arg.xrp, *arg.auditor);
249 env_.require(Owners(issuer_, 0));
250 for (auto const& it : holders_)
252 if (issuer_.id() == it.second.id())
253 Throw<std::runtime_error>(
"Issuer can't be holder");
254 env_.require(Owners(it.second, 0));
301 .auditor = arg.auditor,
324 jv[sfAccount] = arg.
issuer->human();
337 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
367 auto authAndPay = [&](
auto const& accts,
auto const&& getAcct) {
368 for (
auto const& it : accts)
370 authorize({.account = getAcct(it)}, loc);
373 if (arg.
pay && arg.
pay->first.empty())
374 pay(
issuer_, getAcct(it), arg.
pay->second, std::nullopt, std::nullopt, loc);
378 for (
auto const& p : arg.
pay->first)
379 pay(
issuer_, p, arg.
pay->second, std::nullopt, std::nullopt, loc);
386 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
390 authAndPay(*arg.
authorize, [](
auto const& it) { return it; });
395 if (arg.
pay->first.empty())
397 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
401 authAndPay(arg.
pay->first, [](
auto const& it) { return it; });
413 jv[sfAccount] = arg.
issuer->human();
415 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
445 jv[sfAccount] = arg.
account->human();
448 jv[sfHolder] = arg.
holder->human();
449 jv[sfTransactionType] = jss::MPTokenAuthorize;
493 [&](
SLEP const& sle) {
527 for (
auto const&
holder : holders)
539 jv[sfAccount] = arg.
account->human();
544 [&jv]<
typename T>(T
const&
holder) {
547 jv[sfHolder] =
holder.human();
558 jv[sfDelegate] = arg.
delegate->human();
571 jv[sfTransactionType] = jss::MPTokenIssuanceSet;
600 if (*arg.
flags & tfMPTLock)
602 flags |= lsfMPTLocked;
604 else if (*arg.
flags & tfMPTUnlock)
606 flags &= ~lsfMPTLocked;
611 if ((*arg.
flags & f.setFlag) != 0u)
613 flags |= f.ledgerFlag;
621 require(std::nullopt, arg.
holder.has_value());
623 require(*account,
false);
636 "MPTTester::set: issuer's pubkey is not set");
639 return strHex((*sle)[sfIssuerEncryptionKey]) ==
strHex(*issuerPubKey);
660 "MPTTester::set: auditor's pubkey is not set");
663 return strHex((*sle)[sfAuditorEncryptionKey]) ==
strHex(*auditorPubKey);
681 if (
auto const sle =
env_.le(key))
690 if (sle->isFieldPresent(sfDomainID))
691 return expected == sle->getFieldH256(sfDomainID);
700 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfMPTAmount]; },
holder);
707 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfOutstandingAmount]; });
714 return expectedAmount == (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
728 if (sle->isFieldPresent(sfMPTokenMetadata))
729 return strHex(sle->getFieldVL(sfMPTokenMetadata)) ==
strHex(metadata);
738 [&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfMPTokenMetadata); });
745 if (sle->isFieldPresent(sfTransferFee))
746 return sle->getFieldU16(sfTransferFee) == transferFee;
754 return forObject([&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfTransferFee); });
762 return sle->getFieldU32(sfImmutableFlags) == expectedFlags;
772 return (*sle)[~sfIssuerKeyEpoch] == issuerKeyEpoch &&
773 (*sle)[~sfAuditorKeyEpoch] == auditorKeyEpoch;
784 [&](
SLEP const& sle) ->
bool {
785 return (*sle)[~sfIssuerKeyMirrorEpoch] == issuerKeyMirrorEpoch &&
786 (*sle)[~sfAuditorKeyMirrorEpoch] == auditorKeyMirrorEpoch;
796 [&](
SLEP const& sle) ->
bool {
797 epoch = (*sle)[~field];
812 return !sle->isFieldPresent(field);
815 return expected && sle->isFieldPresent(field) &&
820 return matches(sle, sfIssuerEncryptionKey, issuerKeyOwner) &&
821 matches(sle, sfAuditorEncryptionKey, auditorKeyOwner);
913operator
Asset()
const
928 return sle->getFieldU64(sfOutstandingAmount);
933 return sle->getFieldU64(sfMPTAmount);
945 return (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
955 UInt256 const& contextHash)
const
963 if (!sleHolder || !sleIssuance)
966 auto const ciphertextBlob = sleHolder->getFieldVL(sfIssuerEncryptedBalance);
970 auto const pubKeyBlob = sleIssuance->getFieldVL(sfIssuerEncryptionKey);
976 if (mpt_get_clawback_proof(
981 ciphertextBlob.data(),
1003 if (mpt_get_convert_proof(
1004 requireValue(pubKey,
"pubKey").data(),
1005 requireValue(privKey,
"privKey").data(),
1008 return std::nullopt;
1018 Slice const& blindingFactor,
1023 auto const pedersenBalanceParams = makePedersenParams(balanceParams);
1026 return std::nullopt;
1028 auto const senderPrivKey =
getPrivKey(sender);
1030 return std::nullopt;
1032 auto const senderPubKey =
getPubKey(sender);
1034 return std::nullopt;
1037 return std::nullopt;
1041 for (
size_t i = 0; i < recipients.
size(); ++i)
1043 auto const& r = recipients[i];
1047 return std::nullopt;
1057 if (mpt_get_confidential_send_proof(
1058 senderPrivKey->data(),
1059 senderPubKey->data(),
1061 participants.
data(),
1063 blindingFactor.
data(),
1066 &pedersenBalanceParams,
1069 return std::nullopt;
1094 if (mpt_get_pedersen_commitment(amount, pedersenBlindingFactor.
data(), buf.
data()) != 0)
1111 if (!sleMptoken || !sleMptoken->isFieldPresent(sfConfidentialBalanceSpending))
1112 return std::nullopt;
1117 if (!holderPubKey || !holderPrivKey)
1118 return std::nullopt;
1120 auto const pedersenParams = makePedersenParams(pcParams);
1121 Buffer proof(kExpectedProofLength);
1123 if (mpt_get_convert_back_proof(
1124 holderPrivKey->data(),
1125 holderPubKey->data(),
1130 return std::nullopt;
1145 SField const* field =
nullptr;
1149 field = &sfConfidentialBalanceInbox;
1152 field = &sfConfidentialBalanceSpending;
1155 field = &sfIssuerEncryptedBalance;
1158 field = &sfAuditorEncryptedBalance;
1162 if (field ==
nullptr || !sle->isFieldPresent(*field))
1165 auto const blob = sle->getFieldVL(*field);
1166 return Buffer(blob.data(), blob.size());
1174 [&](
SLEP const& sle) {
1175 flags = sle->getFlags();
1188 jv[sfMPTokenIssuanceID] =
to_string(*
id);
1207 return env_.seq(requireValue(account,
"account"));
1222template <
typename T>
1230 Buffer const blindingFactor =
1232 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
1235 Buffer const holderCiphertext = arg.holderEncryptedAmt
1236 ? *arg.holderEncryptedAmt
1239 jv[sfHolderEncryptedAmount.jsonName] =
strHex(holderCiphertext);
1242 Buffer const issuerCiphertext = arg.issuerEncryptedAmt
1243 ? *arg.issuerEncryptedAmt
1246 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(issuerCiphertext);
1250 if (arg.auditorEncryptedAmt)
1252 auditorCiphertext = *arg.auditorEncryptedAmt;
1254 else if (
auditor_.has_value() && arg.fillAuditorEncryptedAmt.value_or(
false))
1261 if (auditorCiphertext)
1262 jv[sfAuditorEncryptedAmount.jsonName] =
strHex(*auditorCiphertext);
1271 auto const amt = requireValue(arg.
amt,
"amt");
1280 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
1285 bool const hasAuditorAmt =
1292 if (!prevAuditorBalance)
1305 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
1310 return prevConfidentialOutstanding + amt == postConfidentialOutstanding;
1334 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
1341 if (!postAuditorBalance)
1352 [&]() ->
bool {
return *prevAuditorBalance + amt == *postAuditorBalance; }, loc));
1356 [&]() ->
bool {
return *postSpendingBalance == *prevSpendingBalance; }, loc));
1360 [&]() ->
bool {
return *prevIssuerBalance + amt == *postIssuerBalance; }, loc));
1364 [&]() ->
bool {
return *prevInboxBalance + amt == *postInboxBalance; }, loc));
1370 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
1379 [&](
SLEP const& sle) ->
bool {
1382 auto const holderPubKey =
getPubKey(account);
1386 "MPTTester::convert: holder's pubkey is "
1390 return strHex((*sle)[sfHolderEncryptionKey]) ==
1408 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
1411 auto const amt = requireValue(arg.
amt,
"amt");
1420 jv[sfZKProof.jsonName] = *arg.
proof;
1437 Account const& dest = requireValue(arg.
dest,
"dest");
1438 auto const amt = requireValue(arg.
amt,
"amt");
1448 if (!prevSenderInbox || !prevSenderSpending || !prevSenderIssuer)
1455 if (!prevSenderAuditor)
1463 if (!prevDestInbox || !prevDestSpending || !prevDestIssuer)
1470 if (!prevDestAuditor)
1474 auto const senderPubAmt =
getBalance(account);
1489 if (!postSenderInbox || !postSenderSpending || !postSenderIssuer)
1497 if (!postDestInbox || !postDestSpending || !postDestIssuer)
1506 RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }, loc));
1507 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }, loc));
1512 return *prevSenderSpending >= amt &&
1513 *postSenderSpending == *prevSenderSpending - amt;
1516 env_.require(
RequireAny([&]() ->
bool {
return postSenderInbox == prevSenderInbox; }, loc));
1519 return *prevSenderIssuer >= amt && *postSenderIssuer == *prevSenderIssuer - amt;
1525 RequireAny([&]() ->
bool {
return *postDestInbox == *prevDestInbox + amt; }, loc));
1527 RequireAny([&]() ->
bool {
return *postDestSpending == *prevDestSpending; }, loc));
1529 RequireAny([&]() ->
bool {
return *postDestIssuer == *prevDestIssuer + amt; }, loc));
1533 [&]() ->
bool {
return *postSenderInbox + *postSenderSpending == *postSenderIssuer; },
1536 [&]() ->
bool {
return *postDestInbox + *postDestSpending == *postDestIssuer; }, loc));
1540 [&]() ->
bool {
return getMPTokenVersion(account) == prevSenderVersion + 1; }, loc));
1548 if (!postSenderAuditor || !postDestAuditor)
1553 return *postSenderAuditor == *postSenderIssuer &&
1554 *postDestAuditor == *postDestIssuer;
1561 return *prevSenderAuditor >= amt &&
1562 *postSenderAuditor == *prevSenderAuditor - amt;
1568 [&]() ->
bool {
return *postDestAuditor == *prevDestAuditor + amt; }, loc));
1580 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
1583 Account const& dest = setDestinationField(jv, arg.
dest);
1584 auto const amt = requireValue(arg.
amt,
"amt");
1588 Buffer const blindingFactor =
1593 auto const destAmt =
1608 jv[sfSenderEncryptedAmount] =
strHex(senderAmt);
1609 jv[sfDestinationEncryptedAmount] =
strHex(destAmt);
1610 jv[sfIssuerEncryptedAmount] =
strHex(issuerAmt);
1612 jv[sfAuditorEncryptedAmount] =
strHex(*auditorAmt);
1626 prevSenderSpending = chain->spending;
1627 prevEncryptedSenderSpending = chain->encSpending;
1628 version = chain->version;
1633 if (!ledgerSpending)
1635 prevSenderSpending = *ledgerSpending;
1642 Buffer amountCommitment, balanceCommitment;
1652 jv[sfAmountCommitment] =
strHex(amountCommitment);
1664 jv[sfBalanceCommitment] =
strHex(balanceCommitment);
1668 jv[sfZKProof.jsonName] = *arg.
proof;
1672 auto const ctxHash =
1677 auto const senderPubKey =
getPubKey(account);
1678 auto const destPubKey =
getPubKey(dest);
1684 .publicKey =
Slice(*senderPubKey),
1685 .encryptedAmount = senderAmt,
1691 .publicKey =
Slice(*destPubKey),
1692 .encryptedAmount = destAmt,
1698 .publicKey =
Slice(*issuerPubKey),
1699 .encryptedAmount = issuerAmt,
1712 .publicKey =
Slice(*auditorPubKey),
1713 .encryptedAmount = *auditorAmt,
1721 if (prevEncryptedSenderSpending && prevSenderSpending > 0)
1730 .pedersenCommitment = amountCommitment,
1732 .encryptedAmt = senderAmt,
1733 .blindingFactor = blindingFactor,
1736 .pedersenCommitment = balanceCommitment,
1737 .amt = prevSenderSpending,
1738 .encryptedAmt = *prevEncryptedSenderSpending,
1739 .blindingFactor = balanceBlindingFactor,
1752 auto const hexStr = jv[sfSenderEncryptedAmount.jsonName].
asString();
1753 auto const bytes =
strUnHex(hexStr);
1756 return Buffer(bytes->data(), bytes->size());
1766 if (!prevSpending || !prevEncSpending)
1771 *prevSpending,
Slice(*prevEncSpending), prevVersion, sendAmt,
Slice(senderEncAmt));
1774 return std::move(*chain);
1780 Slice const& currentEncSpending,
1783 Slice const& senderEncAmt)
1785 if (sendAmt > currentSpending)
1786 return std::nullopt;
1789 if (!newEncSpending)
1790 return std::nullopt;
1793 .spending = currentSpending - sendAmt,
1794 .encSpending = std::move(*newEncSpending),
1795 .version = currentVersion + 1,
1804 jv[sfAccount] = account.human();
1807 jv[sfHolder] =
holder.human();
1809 jv[jss::TransactionType] = jss::ConfidentialMPTClawback;
1812 auto const amt = requireValue(arg.
amt,
"amt");
1817 jv[sfZKProof] = *arg.
proof;
1822 auto const contextHash =
1851 RequireAny([&]() ->
bool {
return prevCOA >= amt && postCOA == prevCOA - amt; }, loc));
1854 return prevOA && postOA && *prevOA >= amt && *postOA == *prevOA - amt;
1872 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }, loc));
1880 secp256k1_pubkey pubKey;
1881 if (secp256k1_elgamal_generate_keypair(
secp256k1Context(), privKey, &pubKey) == 0)
1887 if (secp256k1_ec_pubkey_serialize(
1888 secp256k1Context(), compressedPubKey, &outLen, &pubKey, SECP256K1_EC_COMPRESSED) != 1 ||
1894 auto& pubKeyEpochs =
pubKeys_[account.id()];
1904 return keyAtEpoch(
pubKeys_, account.id(), epoch);
1910 return keyAtEpoch(
privKeys_, account.id(), epoch);
1917 if (
auto const pubKey =
getPubKey(account))
1935 return std::nullopt;
1939 return std::nullopt;
1941 auto const privKey =
getPrivKey(account, epoch);
1943 return std::nullopt;
1945 uint64_t decryptedAmt = 0;
1946 if (secp256k1_elgamal_decrypt(
1952 kElGamalDecryptRangeLow,
1953 kElGamalDecryptRangeHigh) == 0)
1955 return std::nullopt;
1958 return decryptedAmt;
1985 return std::nullopt;
1997 setAccountField(jv, arg.
account);
1999 jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox;
2009 auto const holderPubAmt =
getBalance(account);
2019 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2034 if (!postInboxBalance || !postSpendingBalance || !postIssuerBalance ||
2035 !prevIssuerEncrypted || !postInboxEncrypted || !postIssuerEncrypted)
2040 RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }, loc));
2041 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }, loc));
2045 return *postSpendingBalance == *prevInboxBalance + *prevSpendingBalance &&
2046 *postInboxBalance == 0;
2051 RequireAny([&]() ->
bool {
return *prevIssuerBalance == *postIssuerBalance; }, loc));
2053 auto const holderPubKey =
getPubKey(account);
2058 requireValue(holderPubKey,
"holderPubKey"), account.id(),
issuanceID());
2063 RequireAny([&]() ->
bool {
return *postInboxEncrypted == *expectedInbox; }, loc));
2065 [&]() ->
bool {
return *postIssuerEncrypted == *prevIssuerEncrypted; }, loc));
2068 return postAuditorEncrypted.has_value() == prevAuditorEncrypted.has_value() &&
2069 (!postAuditorEncrypted || *postAuditorEncrypted == *prevAuditorEncrypted);
2072 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }, loc));
2076 return *postSpendingBalance + *postInboxBalance == *postIssuerBalance;
2086 return std::nullopt;
2091 return std::nullopt;
2093 return (*sle)[sfOutstandingAmount];
2109 return (*sle)[~sfConfidentialBalanceVersion].value_or(0);
2118 auto const amt = requireValue(arg.
amt,
"amt");
2124 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2134 if (!prevAuditorBalance)
2149 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
2154 return prevConfidentialOutstanding - amt == postConfidentialOutstanding;
2162 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
2169 if (!postAuditorBalance)
2174 [&]() ->
bool {
return *prevAuditorBalance - amt == *postAuditorBalance; }, loc));
2179 RequireAny([&]() ->
bool {
return *postInboxBalance == *prevInboxBalance; }, loc));
2183 [&]() ->
bool {
return *prevIssuerBalance - amt == *postIssuerBalance; }, loc));
2187 [&]() ->
bool {
return *prevSpendingBalance - amt == *postSpendingBalance; }, loc));
2190 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }, loc));
2196 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
2208 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
2211 auto const amt = requireValue(arg.
amt,
"amt");
2217 if (!prevSpendingBalance)
2220 Buffer pedersenCommitment;
2231 jv[sfBalanceCommitment] =
strHex(pedersenCommitment);
2241 auto const contextHash =
2245 if (prevEncSpending)
2252 .pedersenCommitment = pedersenCommitment,
2253 .amt = *prevSpendingBalance,
2254 .encryptedAmt = *prevEncSpending,
2255 .blindingFactor = pcBlindingFactor,
2269 jv[jss::TransactionType] = jss::ConfidentialMPTMirrorUpdate;
2271 setAccountField(jv, arg.
account);
2275 jv[sfHolder] = arg.
holder->human();
2298 jv[jss::TransactionType] = jss::ConfidentialMPTHolderKeyUpdate;
2300 setAccountField(jv, arg.
account);
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
std::string asString() const
Returns the unquoted string value.
Like std::vector<char> but better.
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
constexpr value_type value() const
Returns the underlying value.
static constexpr std::array< FlagMapping, 7 > flagMapping
An immutable linear range of bytes.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
beast::unit_test::Suite & test
std::unordered_map< AccountID, std::vector< Buffer > > pubKeys_
static constexpr auto holderEncryptedInbox
void mirrorUpdate(MPTMirrorUpdate const &arg=MPTMirrorUpdate{}, std::source_location const &loc=std::source_location::current())
std::optional< std::uint32_t > getMirrorEpoch(Account const &holder, SF_UINT32 const &field) const
std::unordered_map< std::string, Account > const holders_
Buffer encryptAmount(Account const &account, uint64_t const amt, Buffer const &blindingFactor) const
bool forObject(std::function< bool(SLEP const &sle)> const &cb, std::optional< Account > const &holder=std::nullopt) const
void mergeInbox(MPTMergeInbox const &arg=MPTMergeInbox{}, std::source_location const &loc=std::source_location::current())
bool checkMPTokenAmount(Account const &holder, std::int64_t expectedAmount) const
std::optional< MPTID > id_
json::Value convertJV(MPTConvert const &arg, std::uint32_t seq)
Build a confidential convert JV without submitting it.
static Buffer getPedersenCommitment(std::uint64_t const amount, Buffer const &pedersenBlindingFactor)
static json::Value destroyJV(MPTDestroy const &arg=MPTDestroy{})
void setIssuanceIdField(json::Value &jv, std::optional< MPTID > const &id) const
Sets sfMPTokenIssuanceID on jv, falling back to id_ if arg's id is not set.
std::optional< Buffer > getEncryptedBalance(Account const &account, EncryptedBalanceType option=holderEncryptedInbox) const
void convertBack(MPTConvertBack const &arg=MPTConvertBack{}, std::source_location const &loc=std::source_location::current())
std::optional< uint64_t > getDecryptedBalance(Account const &account, EncryptedBalanceType balanceType) const
bool checkMirrorEpochs(Account const &holder, std::optional< std::uint32_t > issuerKeyMirrorEpoch, std::optional< std::uint32_t > auditorKeyMirrorEpoch) const
Account const & holder(std::string const &h) const
static json::Value authorizeJV(MPTAuthorize const &arg=MPTAuthorize{})
bool isTransferFeePresent() const
std::optional< Buffer > getClawbackProof(Account const &holder, std::uint64_t amount, Buffer const &privateKey, UInt256 const &txHash) const
bool checkMetadata(std::string const &metadata) const
std::uint32_t generateKeyPair(Account const &account)
bool checkFlags(uint32_t const expectedFlags, std::optional< Account > const &holder=std::nullopt) const
bool isMetadataPresent() const
MPT operator[](std::string const &name) const
void holderKeyUpdate(MPTHolderKeyUpdate const &arg=MPTHolderKeyUpdate{}, std::source_location const &loc=std::source_location::current())
std::optional< Buffer > getSchnorrProof(Account const &account, UInt256 const &ctxHash) const
static constexpr auto issuerEncryptedBalance
bool checkDomainID(std::optional< UInt256 > expected) const
std::uint32_t getMPTokenVersion(Account const account) const
Account const & issuer() const
std::optional< std::int64_t > getIssuanceOutstandingBalance() const
static json::Value createJV(MPTCreate const &arg=MPTCreate{})
MPTTester(Env &env, Account issuer, MPTInit const &constr={}, std::source_location const &loc=std::source_location::current())
json::Value sendJV(MPTConfidentialSend const &arg, std::uint32_t seq, std::optional< ConfidentialSendChainState > chain=std::nullopt)
Build a confidential send JV.
ConfidentialSendChainState chainAfterSend(Account const &sender, std::uint64_t sendAmt, json::Value const &jv) const
Compute the projected sender state after a confidential send in a batch.
static json::Value setJV(MPTSet const &set={})
MPTID const & issuanceID() const
static constexpr auto holderEncryptedSpending
std::optional< uint64_t > decryptAmount(Account const &account, Buffer const &amt, std::optional< std::uint32_t > epoch=std::nullopt) const
void send(MPTConfidentialSend const &arg=MPTConfidentialSend{}, std::source_location const &loc=std::source_location::current())
bool checkEncryptionKeys(std::optional< Account > const &issuerKeyOwner, std::optional< Account > const &auditorKeyOwner) const
bool checkImmutableFlags(std::uint32_t expectedFlags) const
std::int64_t getBalance(Account const &account) const
TER submit(A const &arg, WithSourceLocation< json::Value > jv)
void fillConversionCiphertexts(T const &arg, json::Value &jv, Account const &account, std::uint64_t const amount) const
std::optional< Buffer > getConfidentialSendProof(Account const &sender, std::uint64_t const amount, std::vector< ConfidentialRecipient > const &recipients, Slice const &blindingFactor, UInt256 const &contextHash, PedersenProofParams const &amountParams, PedersenProofParams const &balanceParams) const
std::optional< Buffer > getPubKey(Account const &account, std::optional< std::uint32_t > epoch=std::nullopt) const
std::optional< Account > const auditor_
json::Value mergeInboxJV(MPTMergeInbox const &arg=MPTMergeInbox{}) const
void authorizeHolders(Holders const &holders, std::source_location const &loc=std::source_location::current())
static constexpr auto auditorEncryptedBalance
void pay(Account const &src, Account const &dest, std::int64_t amount, std::optional< TER > err=std::nullopt, std::optional< std::vector< std::string > > credentials=std::nullopt, std::source_location const &loc=std::source_location::current())
std::unordered_map< AccountID, std::vector< Buffer > > privKeys_
void claw(Account const &issuer, Account const &holder, std::int64_t amount, std::optional< TER > err=std::nullopt, std::source_location const &loc=std::source_location::current())
void confidentialClaw(MPTConfidentialClawback const &arg=MPTConfidentialClawback{}, std::source_location const &loc=std::source_location::current())
PrettyAmount mpt(std::int64_t amount) const
void create(MPTCreate const &arg=MPTCreate{}, std::source_location const &loc=std::source_location::current())
void set(MPTSet const &set={}, std::source_location const &loc=std::source_location::current())
std::int64_t getIssuanceConfidentialBalance() const
std::uint32_t ticketOrSeq(std::optional< std::uint32_t > const &ticketSeq, std::optional< Account > const &account) const
bool checkTransferFee(std::uint16_t transferFee) const
bool checkIssuanceConfidentialBalance(std::int64_t expectedAmount) const
void authorize(MPTAuthorize const &arg=MPTAuthorize{}, std::source_location const &loc=std::source_location::current())
PrettyAmount operator()(std::int64_t amount) const
std::uint32_t getFlags(std::optional< Account > const &holder) const
bool checkKeyEpochs(std::optional< std::uint32_t > issuerKeyEpoch, std::optional< std::uint32_t > auditorKeyEpoch) const
static std::unordered_map< std::string, Account > makeHolders(std::vector< Account > const &holders)
bool checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const
void convert(MPTConvert const &arg=MPTConvert{}, std::source_location const &loc=std::source_location::current())
std::optional< Buffer > getPrivKey(Account const &account, std::optional< std::uint32_t > epoch=std::nullopt) const
void destroy(MPTDestroy const &arg=MPTDestroy{}, std::source_location const &loc=std::source_location::current())
std::optional< Buffer > getConvertBackProof(Account const &holder, std::uint64_t const amount, UInt256 const &contextHash, PedersenProofParams const &pcParams) const
json::Value convertBackJV(MPTConvertBack const &arg, std::uint32_t seq)
Build a confidential convertBack JV without submitting it.
Converts to MPT Issue or STAmount.
Test helper that checks MPT issuance or holder balances.
std::source_location testLoc_
MPTTester const & tester_
std::int64_t const amount_
void operator()(Env &env) const
std::source_location checkLoc_
Test helper that checks MPT flag settings after creation.
std::source_location checkLoc_
void operator()(Env &env) const
std::optional< Account > holder_
std::source_location testLoc_
Match the number of items in the account's owner directory.
Test helper that accepts any condition supplied by a callback.
std::function< bool()> cb_
std::source_location testLoc_
void operator()(Env &env) const
std::source_location checkLoc_
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ Array
array value (ordered list)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
json::Value claw(Account const &account, STAmount const &amount, std::optional< Account > const &mptHolder)
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::vector< STAmount > fund(jtx::Env &env, jtx::Account const &gw, std::vector< jtx::Account > const &accounts, std::vector< STAmount > const &amts, Fund how)
static MPTCreate makeMPTCreate(MPTInitDef const &arg)
Buffer gMakeZeroBuffer(std::size_t size)
Create a zero-initialized buffer for malformed cryptography test inputs.
std::vector< Account > Holders
std::optional< ConfidentialSendChainState > computeNextSendChainState(std::uint64_t currentSpending, Slice const ¤tEncSpending, std::uint32_t currentVersion, std::uint64_t sendAmt, Slice const &senderEncAmt)
Use this when building a second (or later) confidential send from the same account in the same batch.
static Buffer parseSenderEncAmt(json::Value const &jv)
constexpr std::size_t kEcPubKeyLength
Length of EC public key (compressed).
constexpr std::uint8_t kEcCompressedPrefixEvenY
Compressed EC point prefix for even y-coordinate.
constexpr std::size_t kEcBlindingFactorLength
Length of the EC blinding factor in bytes.
std::optional< Buffer > encryptCanonicalZeroAmount(Slice const &pubKeySlice, AccountID const &account, MPTID const &mptId)
Generates the canonical zero encryption for a specific MPToken.
UInt256 getConvertContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence)
Generates the context hash for ConfidentialMPTConvert transactions.
std::string strHex(FwdIt begin, FwdIt end)
UInt256 getSendContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence, AccountID const &destination, std::uint32_t version)
Generates the context hash for ConfidentialMPTSend transactions.
UInt256 getConvertBackContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence, std::uint32_t version)
Generates the context hash for ConfidentialMPTConvertBack transactions.
constexpr std::size_t kEcClawbackProofLength
Length of the ZKProof for ConfidentialMPTClawback.
std::optional< Buffer > encryptAmount(uint64_t const amt, Slice const &pubKeySlice, Slice const &blindingFactor)
Encrypts an amount using ElGamal encryption.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
constexpr std::size_t kEcSchnorrProofLength
Length of Schnorr ZKProof for public key registration (compact form) in bytes.
std::optional< EcPair > makeEcPair(Slice const &buffer)
Parses an ElGamal ciphertext into two secp256k1 public key components.
bool matches(char const *string, char const *regex)
Return true if the string loosely matches the regex.
constexpr std::size_t kEcGamalEncryptedTotalLength
EC ElGamal ciphertext length: two compressed EC points concatenated.
TypedField< STInteger< std::uint32_t > > SF_UINT32
std::string to_string(BaseUInt< Bits, Tag > const &a)
constexpr std::size_t kEcConvertBackProofLength
128 bytes compact sigma proof + 688 bytes single bulletproof.
constexpr std::size_t kEcPedersenCommitmentLength
Length of Pedersen Commitment (compressed).
std::optional< Buffer > homomorphicSubtract(Slice const &a, Slice const &b)
Homomorphically subtracts two ElGamal ciphertexts.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
TypedField< STBlob > SF_VL
secp256k1_context const * secp256k1Context()
constexpr std::size_t kEcEqualityProofLength
Length of compact equality proof.
UInt256 getClawbackContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence, AccountID const &holder)
Generates the context hash for ConfidentialMPTClawback transactions.
Buffer generateBlindingFactor()
Generates a cryptographically secure blinding factor (size=xrpl::kEcBlindingFactorLength).
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
constexpr std::size_t kEcSendProofLength
192 bytes compact sigma proof + 754 bytes double bulletproof.
bool isTesSuccess(TER x) noexcept
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
constexpr std::size_t kEcPrivKeyLength
Length of EC private key in bytes.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
When building multiple confidential sends from the same account inside a single batch transaction,...
Arguments for building an MPTokenAuthorize test transaction.
std::optional< Account > holder
std::optional< Account > account
std::optional< MPTID > id
std::optional< std::uint32_t > flags
Arguments for building a ConfidentialMPTClawback test transaction.
std::optional< std::uint32_t > ticketSeq
std::optional< std::string > proof
std::optional< std::uint64_t > amt
std::optional< MPTID > id
std::optional< Account > account
std::optional< Account > holder
Arguments for building a ConfidentialMPTSend test transaction.
std::optional< std::vector< std::string > > credentials
std::optional< Buffer > balanceCommitment
std::optional< MPTID > id
std::optional< std::uint32_t > ticketSeq
std::optional< std::uint64_t > amt
std::optional< bool > fillAuditorEncryptedAmt
std::optional< Account > account
std::optional< Buffer > auditorEncryptedAmt
std::optional< Account > dest
std::optional< Buffer > blindingFactor
std::optional< Buffer > amountCommitment
std::optional< std::string > proof
std::optional< Buffer > senderEncryptedAmt
std::optional< Buffer > destEncryptedAmt
std::optional< Buffer > issuerEncryptedAmt
Arguments for building a ConfidentialMPTConvertBack test transaction.
std::optional< Buffer > auditorEncryptedAmt
std::optional< MPTID > id
std::optional< std::uint64_t > amt
std::optional< Account > account
std::optional< std::uint32_t > ticketSeq
std::optional< Buffer > proof
std::optional< Buffer > pedersenCommitment
Arguments for building a ConfidentialMPTConvert test transaction.
std::optional< bool > fillAuditorEncryptedAmt
std::optional< MPTID > id
std::optional< std::uint64_t > amt
std::optional< Buffer > auditorEncryptedAmt
std::optional< bool > fillSchnorrProof
std::optional< Buffer > holderPubKey
std::optional< Account > account
std::optional< std::string > proof
std::optional< std::uint32_t > ticketSeq
Arguments for building an MPTokenIssuanceCreate test transaction.
std::optional< std::uint8_t > assetScale
std::optional< std::uint32_t > immutableFlags
std::optional< std::string > metadata
std::optional< std::uint32_t > flags
std::optional< std::uint64_t > maxAmt
std::optional< UInt256 > domainID
std::optional< Account > issuer
std::optional< std::pair< std::vector< Account >, std::uint64_t > > pay
std::optional< std::uint16_t > transferFee
std::optional< std::vector< Account > > authorize
Arguments for building an MPTokenIssuanceDestroy test transaction.
std::optional< Account > issuer
std::optional< MPTID > id
Arguments for building a ConfidentialMPTHolderKeyUpdate test transaction.
std::optional< Account > account
std::optional< Buffer > inboxCiphertext
std::optional< Buffer > proof
std::optional< MPTID > id
std::optional< Buffer > spendingCiphertext
std::optional< Buffer > holderPubKey
Full constructor arguments for MPTTester initialization.
std::uint16_t transferFee
std::optional< std::uint64_t > maxAmt
std::optional< std::uint32_t > immutableFlags
std::optional< std::uint64_t > pay
Arguments for initializing funded MPT test accounts and issuance.
std::optional< Account > auditor
Arguments for building a ConfidentialMPTMergeInbox test transaction.
std::optional< MPTID > id
std::optional< Account > account
Arguments for building a ConfidentialMPTMirrorUpdate test transaction.
std::optional< Buffer > auditorEncryptedAmount
std::optional< Account > holder
std::optional< Account > account
std::optional< Buffer > zkProof
std::optional< MPTID > id
std::optional< Buffer > issuerEncryptedAmount
Arguments for building an MPTokenIssuanceSet test transaction.
std::optional< Account > account
std::optional< Buffer > auditorPubKey
std::optional< MPTID > id
std::optional< std::uint32_t > immutableFlags
std::optional< std::uint16_t > transferFee
std::optional< std::uint32_t > flags
std::optional< std::variant< Account, AccountID > > holder
std::optional< std::string > metadata
std::optional< Buffer > issuerPubKey
std::optional< UInt256 > domainID
std::optional< Account > delegate
Stores the parameters that are exclusively used to generate a Pedersen linkage proof.
Buffer const pedersenCommitment
The Pedersen commitment used by the proof.
Represents an XRP, IOU, or MPT quantity This customizes the string conversion and supports XRP conver...
Wrapper that captures std::source_location when implicitly constructed.