mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add convenience functions to MPT test-framework. (#5870)
This commit is contained in:
committed by
GitHub
parent
d576e9d214
commit
f35d0dc829
@@ -1171,7 +1171,7 @@ class MPToken_test : public beast::unit_test::suite
|
||||
env(credentials::accept(bob, credIssuer1, credType));
|
||||
env.close();
|
||||
|
||||
MPTTester mptAlice(env, alice, {});
|
||||
MPTTester mptAlice(env, alice);
|
||||
env.close();
|
||||
|
||||
mptAlice.create({
|
||||
@@ -1213,7 +1213,7 @@ class MPToken_test : public beast::unit_test::suite
|
||||
env(credentials::accept(bob, credIssuer1, credType));
|
||||
env.close();
|
||||
|
||||
MPTTester mptAlice(env, alice, {});
|
||||
MPTTester mptAlice(env, alice);
|
||||
env.close();
|
||||
|
||||
mptAlice.create({
|
||||
@@ -1293,7 +1293,7 @@ class MPToken_test : public beast::unit_test::suite
|
||||
env(credentials::accept(carol, credIssuer2, credType));
|
||||
env.close();
|
||||
|
||||
MPTTester mptAlice(env, alice, {});
|
||||
MPTTester mptAlice(env, alice);
|
||||
env.close();
|
||||
|
||||
mptAlice.create({
|
||||
|
||||
@@ -232,6 +232,13 @@ public:
|
||||
{
|
||||
return {asset_};
|
||||
}
|
||||
|
||||
template <ValidIssueType TIss>
|
||||
bool
|
||||
holds() const
|
||||
{
|
||||
return asset_.holds<TIss>();
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -81,17 +81,67 @@ MPTTester::MPTTester(Env& env, Account const& issuer, MPTInit const& arg)
|
||||
env_.require(owners(it.second, 0));
|
||||
}
|
||||
}
|
||||
if (arg.create)
|
||||
create(*arg.create);
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::create(MPTCreate const& arg)
|
||||
MPTTester::MPTTester(
|
||||
Env& env,
|
||||
Account const& issuer,
|
||||
MPTID const& id,
|
||||
std::vector<Account> const& holders,
|
||||
bool close)
|
||||
: env_(env)
|
||||
, issuer_(issuer)
|
||||
, holders_(makeHolders(holders))
|
||||
, id_(id)
|
||||
, close_(close)
|
||||
{
|
||||
if (id_)
|
||||
Throw<std::runtime_error>("MPT can't be reused");
|
||||
id_ = makeMptID(env_.seq(issuer_), issuer_);
|
||||
}
|
||||
|
||||
static MPTCreate
|
||||
makeMPTCreate(MPTInitDef const& arg)
|
||||
{
|
||||
if (arg.pay)
|
||||
return {
|
||||
.maxAmt = arg.maxAmt,
|
||||
.transferFee = arg.transferFee,
|
||||
.pay = {{arg.holders, *arg.pay}},
|
||||
.flags = arg.flags,
|
||||
.authHolder = arg.authHolder};
|
||||
return {
|
||||
.maxAmt = arg.maxAmt,
|
||||
.transferFee = arg.transferFee,
|
||||
.authorize = arg.holders,
|
||||
.flags = arg.flags,
|
||||
.authHolder = arg.authHolder};
|
||||
}
|
||||
|
||||
MPTTester::MPTTester(MPTInitDef const& arg)
|
||||
: MPTTester{
|
||||
arg.env,
|
||||
arg.issuer,
|
||||
MPTInit{
|
||||
.fund = arg.fund,
|
||||
.close = arg.close,
|
||||
.create = makeMPTCreate(arg)}}
|
||||
{
|
||||
}
|
||||
|
||||
MPTTester::operator MPT() const
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
return MPT("", *id_);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
MPTTester::createjv(MPTCreate const& arg)
|
||||
{
|
||||
if (!arg.issuer)
|
||||
Throw<std::runtime_error>("MPTTester::createjv: issuer is not set");
|
||||
Json::Value jv;
|
||||
jv[sfAccount] = issuer_.human();
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
|
||||
jv[sfAccount] = arg.issuer->human();
|
||||
if (arg.assetScale)
|
||||
jv[sfAssetScale] = *arg.assetScale;
|
||||
if (arg.transferFee)
|
||||
@@ -104,6 +154,25 @@ MPTTester::create(MPTCreate const& arg)
|
||||
jv[sfDomainID] = to_string(*arg.domainID);
|
||||
if (arg.mutableFlags)
|
||||
jv[sfMutableFlags] = *arg.mutableFlags;
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::create(MPTCreate const& arg)
|
||||
{
|
||||
if (id_)
|
||||
Throw<std::runtime_error>("MPT can't be reused");
|
||||
id_ = makeMptID(env_.seq(issuer_), issuer_);
|
||||
Json::Value jv = createjv(
|
||||
{.issuer = issuer_,
|
||||
.maxAmt = arg.maxAmt,
|
||||
.assetScale = arg.assetScale,
|
||||
.transferFee = arg.transferFee,
|
||||
.metadata = arg.metadata,
|
||||
.mutableFlags = arg.mutableFlags,
|
||||
.domainID = arg.domainID});
|
||||
if (submit(arg, jv) != tesSUCCESS)
|
||||
{
|
||||
// Verify issuance doesn't exist
|
||||
@@ -114,26 +183,62 @@ MPTTester::create(MPTCreate const& arg)
|
||||
id_.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
env_.require(mptflags(*this, arg.flags.value_or(0)));
|
||||
auto authAndPay = [&](auto const& accts, auto const&& getAcct) {
|
||||
for (auto const& it : accts)
|
||||
{
|
||||
authorize({.account = getAcct(it)});
|
||||
if ((arg.flags.value_or(0) & tfMPTRequireAuth) &&
|
||||
arg.authHolder)
|
||||
authorize({.account = issuer_, .holder = getAcct(it)});
|
||||
if (arg.pay && arg.pay->first.empty())
|
||||
pay(issuer_, getAcct(it), arg.pay->second);
|
||||
}
|
||||
if (arg.pay)
|
||||
{
|
||||
for (auto const& p : arg.pay->first)
|
||||
pay(issuer_, p, arg.pay->second);
|
||||
}
|
||||
};
|
||||
if (arg.authorize)
|
||||
{
|
||||
if (arg.authorize->empty())
|
||||
authAndPay(holders_, [](auto const& it) { return it.second; });
|
||||
else
|
||||
authAndPay(*arg.authorize, [](auto const& it) { return it; });
|
||||
}
|
||||
else if (arg.pay)
|
||||
{
|
||||
if (arg.pay->first.empty())
|
||||
authAndPay(holders_, [](auto const& it) { return it.second; });
|
||||
else
|
||||
authAndPay(arg.pay->first, [](auto const& it) { return it; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value
|
||||
MPTTester::destroyjv(MPTDestroy const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (!arg.issuer || !arg.id)
|
||||
Throw<std::runtime_error>("MPTTester::destroyjv: issuer/id is not set");
|
||||
jv[sfAccount] = arg.issuer->human();
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::destroy(MPTDestroy const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (arg.issuer)
|
||||
jv[sfAccount] = arg.issuer->human();
|
||||
else
|
||||
jv[sfAccount] = issuer_.human();
|
||||
if (arg.id)
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
else
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
jv[sfMPTokenIssuanceID] = to_string(*id_);
|
||||
}
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
|
||||
if (!arg.id && !id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
Json::Value jv = destroyjv(
|
||||
{.issuer = arg.issuer ? arg.issuer : issuer_,
|
||||
.id = arg.id ? arg.id : id_});
|
||||
submit(arg, jv);
|
||||
}
|
||||
|
||||
@@ -146,25 +251,32 @@ MPTTester::holder(std::string const& holder_) const
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
MPTTester::authorizejv(MPTAuthorize const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (!arg.account || !arg.id)
|
||||
Throw<std::runtime_error>(
|
||||
"MPTTester::authorizejv: issuer/id is not set");
|
||||
jv[sfAccount] = arg.account->human();
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
if (arg.holder)
|
||||
jv[sfHolder] = arg.holder->human();
|
||||
jv[sfTransactionType] = jss::MPTokenAuthorize;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::authorize(MPTAuthorize const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (arg.account)
|
||||
jv[sfAccount] = arg.account->human();
|
||||
else
|
||||
jv[sfAccount] = issuer_.human();
|
||||
jv[sfTransactionType] = jss::MPTokenAuthorize;
|
||||
if (arg.id)
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
else
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
jv[sfMPTokenIssuanceID] = to_string(*id_);
|
||||
}
|
||||
if (arg.holder)
|
||||
jv[sfHolder] = arg.holder->human();
|
||||
if (!arg.id && !id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
Json::Value jv = authorizejv({
|
||||
.account = arg.account ? arg.account : issuer_,
|
||||
.holder = arg.holder,
|
||||
.id = arg.id ? arg.id : id_,
|
||||
});
|
||||
if (auto const result = submit(arg, jv); result == tesSUCCESS)
|
||||
{
|
||||
// Issuer authorizes
|
||||
@@ -220,24 +332,34 @@ MPTTester::authorize(MPTAuthorize const& arg)
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::set(MPTSet const& arg)
|
||||
MPTTester::authorizeHolders(Holders const& holders)
|
||||
{
|
||||
for (auto const& holder : holders)
|
||||
{
|
||||
authorize({.account = holder});
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value
|
||||
MPTTester::setjv(MPTSet const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (arg.account)
|
||||
jv[sfAccount] = arg.account->human();
|
||||
else
|
||||
jv[sfAccount] = issuer_.human();
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceSet;
|
||||
if (arg.id)
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
else
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
jv[sfMPTokenIssuanceID] = to_string(*id_);
|
||||
}
|
||||
if (!arg.account || !arg.id)
|
||||
Throw<std::runtime_error>("MPTTester::setjv: issuer/id is not set");
|
||||
jv[sfAccount] = arg.account->human();
|
||||
jv[sfMPTokenIssuanceID] = to_string(*arg.id);
|
||||
if (arg.holder)
|
||||
jv[sfHolder] = arg.holder->human();
|
||||
{
|
||||
std::visit(
|
||||
[&jv]<typename T>(T const& holder) {
|
||||
if constexpr (std::is_same_v<T, Account>)
|
||||
jv[sfHolder] = holder.human();
|
||||
else if constexpr (std::is_same_v<T, AccountID>)
|
||||
jv[sfHolder] = toBase58(holder);
|
||||
},
|
||||
*arg.holder);
|
||||
}
|
||||
|
||||
if (arg.delegate)
|
||||
jv[sfDelegate] = arg.delegate->human();
|
||||
if (arg.domainID)
|
||||
@@ -248,7 +370,27 @@ MPTTester::set(MPTSet const& arg)
|
||||
jv[sfTransferFee] = *arg.transferFee;
|
||||
if (arg.metadata)
|
||||
jv[sfMPTokenMetadata] = strHex(*arg.metadata);
|
||||
if (submit(arg, jv) == tesSUCCESS && (arg.flags || arg.mutableFlags))
|
||||
jv[sfTransactionType] = jss::MPTokenIssuanceSet;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
MPTTester::set(MPTSet const& arg)
|
||||
{
|
||||
if (!arg.id && !id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
Json::Value jv = setjv(
|
||||
{.account = arg.account ? arg.account : issuer_,
|
||||
.holder = arg.holder,
|
||||
.id = arg.id ? arg.id : id_,
|
||||
.mutableFlags = arg.mutableFlags,
|
||||
.transferFee = arg.transferFee,
|
||||
.metadata = arg.metadata,
|
||||
.delegate = arg.delegate,
|
||||
.domainID = arg.domainID});
|
||||
if (submit(arg, jv) == tesSUCCESS &&
|
||||
(arg.flags.value_or(0) || arg.mutableFlags))
|
||||
{
|
||||
auto require = [&](std::optional<Account> const& holder,
|
||||
bool unchanged) {
|
||||
@@ -300,8 +442,9 @@ MPTTester::set(MPTSet const& arg)
|
||||
};
|
||||
if (arg.account)
|
||||
require(std::nullopt, arg.holder.has_value());
|
||||
if (arg.holder)
|
||||
require(*arg.holder, false);
|
||||
if (auto const account =
|
||||
(arg.holder ? std::get_if<Account>(&(*arg.holder)) : nullptr))
|
||||
require(*account, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,6 +617,13 @@ MPTTester::mpt(std::int64_t amount) const
|
||||
return ripple::test::jtx::MPT(issuer_.name(), *id_)(amount);
|
||||
}
|
||||
|
||||
MPTTester::operator Asset() const
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
return Asset(*id_);
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
MPTTester::getBalance(Account const& account) const
|
||||
{
|
||||
@@ -507,11 +657,17 @@ MPTTester::getFlags(std::optional<Account> const& holder) const
|
||||
}
|
||||
|
||||
MPT
|
||||
MPTTester::operator[](std::string const& name) const
|
||||
MPTTester::operator[](std::string const& name)
|
||||
{
|
||||
return MPT(name, issuanceID());
|
||||
}
|
||||
|
||||
PrettyAmount
|
||||
MPTTester::operator()(std::uint64_t amount) const
|
||||
{
|
||||
return MPT("", issuanceID())(amount);
|
||||
}
|
||||
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace jtx {
|
||||
|
||||
class MPTTester;
|
||||
|
||||
auto const MPTDEXFlags = tfMPTCanTrade | tfMPTCanTransfer;
|
||||
|
||||
// Check flags settings on MPT create
|
||||
class mptflags
|
||||
{
|
||||
@@ -86,31 +88,59 @@ public:
|
||||
operator()(Env& env) const;
|
||||
};
|
||||
|
||||
struct MPTInit
|
||||
{
|
||||
std::vector<Account> holders = {};
|
||||
PrettyAmount const xrp = XRP(10'000);
|
||||
PrettyAmount const xrpHolders = XRP(10'000);
|
||||
bool fund = true;
|
||||
bool close = true;
|
||||
};
|
||||
static MPTInit const mptInitNoFund{.fund = false};
|
||||
using Holders = std::vector<Account>;
|
||||
|
||||
struct MPTCreate
|
||||
{
|
||||
static inline std::vector<Account> AllHolders = {};
|
||||
std::optional<Account> issuer = std::nullopt;
|
||||
std::optional<std::uint64_t> maxAmt = std::nullopt;
|
||||
std::optional<std::uint8_t> assetScale = std::nullopt;
|
||||
std::optional<std::uint16_t> transferFee = std::nullopt;
|
||||
std::optional<std::string> metadata = std::nullopt;
|
||||
std::optional<std::uint32_t> ownerCount = std::nullopt;
|
||||
std::optional<std::uint32_t> holderCount = std::nullopt;
|
||||
bool fund = true;
|
||||
// authorize if seated.
|
||||
// if empty vector then authorize all holders
|
||||
std::optional<std::vector<Account>> authorize = std::nullopt;
|
||||
// pay if seated. if authorize is not seated then authorize.
|
||||
// if empty vector then pay to either authorize or all holders.
|
||||
std::optional<std::pair<std::vector<Account>, std::uint64_t>> pay =
|
||||
std::nullopt;
|
||||
std::optional<std::uint32_t> flags = {0};
|
||||
std::optional<std::uint32_t> mutableFlags = std::nullopt;
|
||||
bool authHolder = false;
|
||||
std::optional<uint256> domainID = std::nullopt;
|
||||
std::optional<TER> err = std::nullopt;
|
||||
};
|
||||
|
||||
struct MPTInit
|
||||
{
|
||||
Holders holders = {};
|
||||
PrettyAmount const xrp = XRP(10'000);
|
||||
PrettyAmount const xrpHolders = XRP(10'000);
|
||||
bool fund = true;
|
||||
bool close = true;
|
||||
// create MPTIssuanceID if seated and follow rules for MPTCreate args
|
||||
std::optional<MPTCreate> create = std::nullopt;
|
||||
};
|
||||
static MPTInit const mptInitNoFund{.fund = false};
|
||||
|
||||
struct MPTInitDef
|
||||
{
|
||||
Env& env;
|
||||
Account issuer;
|
||||
Holders holders = {};
|
||||
std::uint16_t transferFee = 0;
|
||||
std::optional<std::uint64_t> pay = std::nullopt;
|
||||
std::uint32_t flags = MPTDEXFlags;
|
||||
bool authHolder = false;
|
||||
bool fund = false;
|
||||
bool close = true;
|
||||
std::optional<std::uint64_t> maxAmt = std::nullopt;
|
||||
std::optional<TER> err = std::nullopt;
|
||||
};
|
||||
|
||||
struct MPTDestroy
|
||||
{
|
||||
std::optional<Account> issuer = std::nullopt;
|
||||
@@ -135,7 +165,7 @@ struct MPTAuthorize
|
||||
struct MPTSet
|
||||
{
|
||||
std::optional<Account> account = std::nullopt;
|
||||
std::optional<Account> holder = std::nullopt;
|
||||
std::optional<std::variant<Account, AccountID>> holder = std::nullopt;
|
||||
std::optional<MPTID> id = std::nullopt;
|
||||
std::optional<std::uint32_t> ownerCount = std::nullopt;
|
||||
std::optional<std::uint32_t> holderCount = std::nullopt;
|
||||
@@ -151,26 +181,49 @@ struct MPTSet
|
||||
class MPTTester
|
||||
{
|
||||
Env& env_;
|
||||
Account const& issuer_;
|
||||
Account const issuer_;
|
||||
std::unordered_map<std::string, Account> const holders_;
|
||||
std::optional<MPTID> id_;
|
||||
bool close_;
|
||||
|
||||
public:
|
||||
MPTTester(Env& env, Account const& issuer, MPTInit const& constr = {});
|
||||
MPTTester(MPTInitDef const& constr);
|
||||
MPTTester(
|
||||
Env& env,
|
||||
Account const& issuer,
|
||||
MPTID const& id,
|
||||
std::vector<Account> const& holders = {},
|
||||
bool close = true);
|
||||
operator MPT() const;
|
||||
|
||||
void
|
||||
create(MPTCreate const& arg = MPTCreate{});
|
||||
|
||||
static Json::Value
|
||||
createjv(MPTCreate const& arg = MPTCreate{});
|
||||
|
||||
void
|
||||
destroy(MPTDestroy const& arg = MPTDestroy{});
|
||||
|
||||
static Json::Value
|
||||
destroyjv(MPTDestroy const& arg = MPTDestroy{});
|
||||
|
||||
void
|
||||
authorize(MPTAuthorize const& arg = MPTAuthorize{});
|
||||
|
||||
static Json::Value
|
||||
authorizejv(MPTAuthorize const& arg = MPTAuthorize{});
|
||||
|
||||
void
|
||||
authorizeHolders(Holders const& holders);
|
||||
|
||||
void
|
||||
set(MPTSet const& set = {});
|
||||
|
||||
static Json::Value
|
||||
setjv(MPTSet const& set = {});
|
||||
|
||||
[[nodiscard]] bool
|
||||
checkDomainID(std::optional<uint256> expected) const;
|
||||
|
||||
@@ -235,7 +288,12 @@ public:
|
||||
getBalance(Account const& account) const;
|
||||
|
||||
MPT
|
||||
operator[](std::string const& name) const;
|
||||
operator[](std::string const& name);
|
||||
|
||||
PrettyAmount
|
||||
operator()(std::uint64_t amount) const;
|
||||
|
||||
operator Asset() const;
|
||||
|
||||
private:
|
||||
using SLEP = std::shared_ptr<SLE const>;
|
||||
|
||||
Reference in New Issue
Block a user