add tests

This commit is contained in:
tequ
2025-09-19 01:36:45 +09:00
parent a43ae9a3ce
commit 89af81745b
7 changed files with 624 additions and 38 deletions

View File

@@ -3665,7 +3665,7 @@ private:
auto const settleDelay = 100s;
NetClock::time_point const cancelAfter =
env.current()->info().parentCloseTime + 200s;
env(create(
env(paychan::create(
carol,
ammAlice.ammAccount(),
XRP(1'000),

View File

@@ -31,6 +31,8 @@
namespace ripple {
namespace test {
using namespace jtx::paychan;
struct PayChan_test : public beast::unit_test::suite
{
FeatureBitset const disallowIncoming{featureDisallowIncoming};

View File

@@ -807,13 +807,14 @@ public:
Account const bob("bob");
Account const gw("gw");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
auto const USD = gw["USD"];
auto const reserve = env.current()->fees().reserve;
auto const increment = env.current()->fees().increment;
env.fund(XRP(10000), alice, bob, gw);
env.fund(XRP(10000), alice, bob, gw, sponsor2);
env.fund(drops(reserve) + drops(increment) - drops(1), sponsor);
env.close();
@@ -859,14 +860,30 @@ public:
BEAST_EXPECT(
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor.id());
env(check::cancel(alice, keylet.key),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
// transfer sponsor
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 2); // RippleState + Check
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
BEAST_EXPECT(
env.le(keylet)->getAccountID(sfSponsorAccount) ==
sponsor2.id());
// CheckCancel
env(check::cancel(alice, keylet.key));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1); // RippleState
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
{
@@ -900,9 +917,9 @@ public:
env(pay(env.master, sponsor, drops(env.current()->fees().increment)));
env.close();
// RippleState sponsor
// RippleState sponsor (CheckCashMakesTrustLine)
{
// CheckCreate -> CheckCash(CheckCashMakesTrustLine)
// CheckCreate -> CheckCash
auto const seq2 = env.seq(alice);
env(check::create(alice, bob, USD(1)),
sponsor::as(sponsor, tfSponsorReserve),
@@ -950,7 +967,7 @@ public:
{
Env env{*this, testable_amendments()};
env.fund(XRP(10000), alice, gw, sponsor1);
env.fund(XRP(10000), alice, gw, sponsor1, sponsor2);
env.close();
// OfferCreate
@@ -965,6 +982,22 @@ public:
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 1);
// transfer sponsor
auto const keylet = keylet::offer(alice, seq);
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
BEAST_EXPECT(
env.le(keylet)->getAccountID(sfSponsorAccount) ==
sponsor2.id());
// OfferCancel
env(offer_cancel(alice, seq));
env.close();
@@ -973,6 +1006,7 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor1) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
// test Offer Execution doesn't sponsor new trustline
@@ -1035,8 +1069,9 @@ public:
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const sponsor("master");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, sponsor);
env.fund(XRP(1000000), alice, sponsor, sponsor2);
env.close();
// TicketCreate
@@ -1051,13 +1086,32 @@ public:
BEAST_EXPECT(sponsoringOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 250);
auto const keylet = keylet::ticket(alice, ticketSeq);
BEAST_EXPECT(
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor.id());
// transfer sponsor
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 250);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 250);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 249);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
BEAST_EXPECT(
env.le(keylet)->getAccountID(sfSponsorAccount) == sponsor2.id());
// use a Ticket
env(noop(alice), ticket::use(ticketSeq + 1));
env(noop(alice), ticket::use(ticketSeq));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 249);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 249);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 249);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
@@ -1069,12 +1123,15 @@ public:
Account const issuer("issuer");
Account const subject("subject");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), issuer, subject, sponsor);
env.fund(XRP(1000000), issuer, subject, sponsor, sponsor2);
env.close();
auto const credType = std::string("credType");
// CredentialsCreate
env(credentials::create(subject, issuer, "credType"),
env(credentials::create(subject, issuer, credType),
credentials::uri("uri"),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
@@ -1086,8 +1143,23 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const keylet = keylet::credential(
subject, issuer, Slice(credType.data(), credType.size()));
env(sponsor::transfer(issuer, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, issuer) == 1);
BEAST_EXPECT(ownerCount(env, subject) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// CredentialsAccept
env(credentials::accept(subject, issuer, "credType"),
env(credentials::accept(subject, issuer, credType),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
@@ -1097,9 +1169,10 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
// CredentialsDelete
env(credentials::deleteCred(subject, subject, issuer, "credType"));
env(credentials::deleteCred(subject, subject, issuer, credType));
env.close();
BEAST_EXPECT(ownerCount(env, issuer) == 0);
@@ -1107,6 +1180,10 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, issuer) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, subject) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
// TODO: Accept Sponsored Credentials without sponsoring
// TODO: Self Accept Sponsored Credentials
}
void
@@ -1118,8 +1195,9 @@ public:
Account const alice("alice");
Account const bob("bob");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, bob, sponsor);
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
env.close();
// DelegateSet
@@ -1132,6 +1210,18 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const keylet = keylet::delegate(alice, bob);
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// delete
env(delegate::set(alice, bob, {}));
env.close();
@@ -1144,6 +1234,46 @@ public:
void
testDepositPreauth()
{
testcase("DepositPreauth");
using namespace test::jtx;
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, sponsor, sponsor2);
env.close();
// DepositPreauthSet
env(deposit::auth(alice, sponsor),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const keylet = keylet::depositPreauth(alice, sponsor);
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// DepositPreauthDelete
env(deposit::unauth(alice, sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
@@ -1154,8 +1284,9 @@ public:
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, sponsor);
env.fund(XRP(1000000), alice, sponsor, sponsor2);
env.close();
// DIDSet
@@ -1169,6 +1300,18 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const keylet = keylet::did(alice);
env(sponsor::transfer(alice, keylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// DIDDelete
env(did::del(alice));
env.close();
@@ -1176,6 +1319,7 @@ public:
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
@@ -1196,14 +1340,14 @@ public:
Env env{*this, testable_amendments()};
auto const baseFee = env.current()->fees().base;
env.fund(XRP(1000000), alice, bob, sponsor);
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
env.close();
// EscrowCreate
auto const seq = env.seq(alice);
env(escrow::create(alice, bob, XRP(100)),
escrow::condition(escrow::cb1),
escrow::cancel_time(env.now() + 10s),
escrow::cancel_time(env.now() + 100s),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
@@ -1216,6 +1360,21 @@ public:
env.le(keylet::escrow(alice, seq))
->getAccountID(sfSponsorAccount) == sponsor.id());
// transfer sponsor
env(sponsor::transfer(alice, keylet::escrow(alice, seq).key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
BEAST_EXPECT(
env.le(keylet::escrow(alice, seq))
->getAccountID(sfSponsorAccount) == sponsor2.id());
// EscrowFinish
env(escrow::finish(bob, alice, seq),
escrow::condition(escrow::cb1),
@@ -1226,6 +1385,7 @@ public:
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
{
@@ -1289,26 +1449,413 @@ public:
void
testMPToken()
{
testcase("MPToken");
using namespace test::jtx;
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const bob("bob");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
env.close();
// MPTokenIssuanceCreate
Json::Value jv = {};
jv[sfAccount] = alice.human();
jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
auto const mptid = makeMptID(env.seq(alice), alice.id());
env(jv, sponsor::as(sponsor, tfSponsorReserve), sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const mptIssuanceKeylet = keylet::mptIssuance(mptid);
env(sponsor::transfer(alice, mptIssuanceKeylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// MPTokenAuthorize
jv = {};
jv[sfTransactionType] = jss::MPTokenAuthorize;
jv[sfAccount] = bob.human();
jv[sfMPTokenIssuanceID] = to_string(mptid);
env(jv, sponsor::as(sponsor, tfSponsorReserve), sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
auto const mptTokenKeylet = keylet::mptoken(mptid, bob);
env(sponsor::transfer(alice, mptTokenKeylet.key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 2);
// MPTokenAuthorize Unauthorize
jv = {};
jv[sfTransactionType] = jss::MPTokenAuthorize;
jv[sfAccount] = bob.human();
jv[sfMPTokenIssuanceID] = to_string(mptid);
jv[sfFlags] = tfMPTUnauthorize;
env(jv);
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(ownerCount(env, bob) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// MPTokenIssuanceDestroy
jv = {};
jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
jv[sfAccount] = alice.human();
jv[sfMPTokenIssuanceID] = to_string(mptid);
env(jv);
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
testNFToken()
{
// testcase("NFToken");
// using namespace test::jtx;
// Env env{*this, testable_amendments()};
// Account const alice("alice");
// Account const bob("bob");
// Account const sponsor("sponsor");
// Account const sponsor2("sponsor2");
// env.fund(XRP(1000000), alice, bob, sponsor);
// env.close();
// // NFTokenMint
// env(token::mint(alice),
// sponsor::as(sponsor, tfSponsorReserve),
// sponsor::sig(sponsor));
// env.close();
// BEAST_EXPECT(ownerCount(env, alice) == 1);
// BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
// BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
}
void
testNFTokenOffer()
{
testcase("NFTokenOffer");
using namespace test::jtx;
Account const alice("alice");
Account const bob("bob");
Account const broker("broker");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
auto const taxon = 0u;
{
// Mint + CreateOffer + CancelOffer
Env env{*this, testable_amendments()};
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
env.close();
// Mint
uint256 const nftId{
token::getNextID(env, alice, taxon, tfTransferable)};
env(token::mint(alice, taxon), txflags(tfTransferable));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
// NFTokenOfferCreate
uint256 const offerIndex =
keylet::nftoffer(alice, env.seq(alice)).key;
env(token::createOffer(alice, nftId, XRP(1)),
token::destination(bob),
txflags(tfSellNFToken),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 2);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
env(sponsor::transfer(alice, offerIndex),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 2);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// NFTokenOfferCancel
env(token::cancelOffer(alice, {offerIndex}));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
{
// Mint + CreateSellOffer + AcceptSellOffer
Env env{*this, testable_amendments()};
env.fund(XRP(1000000), alice, bob, sponsor);
env.close();
// Mint
uint256 const nftId{
token::getNextID(env, alice, taxon, tfTransferable)};
env(token::mint(alice, taxon), txflags(tfTransferable));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
// NFTokenOfferCreate
uint256 const offerIndex =
keylet::nftoffer(alice, env.seq(alice)).key;
env(token::createOffer(alice, nftId, XRP(1)),
token::destination(bob),
txflags(tfSellNFToken),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 2);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// NFTokenOfferAccept
env(token::acceptSellOffer(bob, offerIndex));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
}
{
// Mint + CreateBuyOffer + AcceptBuyOffer
Env env{*this, testable_amendments()};
env.fund(XRP(1000000), alice, bob, sponsor);
env.close();
// Mint
uint256 const nftId{
token::getNextID(env, alice, taxon, tfTransferable)};
env(token::mint(alice, taxon), txflags(tfTransferable));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
// NFTokenOfferCreate
uint256 const offerIndex = keylet::nftoffer(bob, env.seq(bob)).key;
env(token::createOffer(bob, nftId, XRP(1)),
token::owner(alice),
token::destination(alice),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// NFTokenOfferAccept
env(token::acceptBuyOffer(alice, offerIndex));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
}
{
// Broker
Env env{*this, testable_amendments()};
env.fund(XRP(1000000), alice, bob, broker, sponsor, sponsor2);
env.close();
// Mint
uint256 const nftId{
token::getNextID(env, alice, taxon, tfTransferable)};
env(token::mint(alice, taxon), txflags(tfTransferable));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
// NFTokenOfferCreate (BuyOffer)
uint256 const buyOfferIndex =
keylet::nftoffer(bob, env.seq(bob)).key;
env(token::createOffer(bob, nftId, XRP(1)),
token::owner(alice),
token::destination(broker),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// NFTokenOfferCreate (SellOffer)
uint256 const sellOfferIndex =
keylet::nftoffer(alice, env.seq(alice)).key;
env(token::createOffer(alice, nftId, XRP(1)),
txflags(tfSellNFToken),
token::destination(broker),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 2);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// NFTokenOfferAccept
env(token::brokerOffers(broker, buyOfferIndex, sellOfferIndex));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(ownerCount(env, bob) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
}
void
testPayChan()
{
testcase("PayChan");
using namespace test::jtx;
using namespace std::literals::chrono_literals;
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const bob("bob");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, bob, sponsor, sponsor2);
env.close();
// PayChanCreate
auto const pk = alice.pk();
auto const settleDelay = 10s;
auto const chan = paychan::channel(alice, bob, env.seq(alice));
env(paychan::create(alice, bob, XRP(100), settleDelay, pk),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
env(sponsor::transfer(alice, chan),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
env.close(env.now() + settleDelay);
// PayChanClaim (delete PayChan)
env(paychan::claim(bob, chan), txflags(tfClose));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
testPermissionedDomain()
{
testcase("PermissionedDomain");
using namespace test::jtx;
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, sponsor, sponsor2);
env.close();
// PermissionedDomainSet
auto const seq = env.seq(alice);
pdomain::Credentials credentials{{alice, "first credential"}};
env(pdomain::setTx(alice, credentials),
sponsor::as(sponsor, tfSponsorReserve),
sponsor::sig(sponsor));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// transfer sponsor
env(sponsor::transfer(
alice, keylet::permissionedDomain(alice, seq).key),
sponsor::as(sponsor2, tfSponsorReserve),
sponsor::sig(sponsor2));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 1);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// PermissionedDomainDelete
auto objects = pdomain::getObjects(alice, env);
auto const domain = objects.begin()->first;
env(pdomain::deleteTx(alice, domain));
env.close();
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
@@ -1324,8 +1871,9 @@ public:
Env env{*this, testable_amendments()};
Account const alice("alice");
Account const sponsor("sponsor");
Account const sponsor2("sponsor2");
env.fund(XRP(1000000), alice, sponsor);
env.fund(XRP(1000000), alice, sponsor, sponsor2);
env.close();
Account const bob("bob");
@@ -1340,6 +1888,17 @@ public:
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
// // transfer sponsor
// env(sponsor::transfer(alice, keylet::signers(alice).key),
// sponsor::as(sponsor2, tfSponsorReserve),
// sponsor::sig(sponsor2));
// env.close();
// BEAST_EXPECT(ownerCount(env, alice) == 1);
// BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
// BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
// BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
// Delete
env(signers(alice, none));
env.close();
@@ -1347,6 +1906,7 @@ public:
BEAST_EXPECT(ownerCount(env, alice) == 0);
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0);
}
void
@@ -1397,6 +1957,7 @@ public:
BEAST_EXPECT(!env.le(keylet::line(user, issuer, USD.currency)));
}
// TODO: transfer sponsor
}
void
@@ -1620,14 +2181,14 @@ public:
testTicket();
testCredentials();
testDelegate();
// testDepositPreauth();
testDepositPreauth();
testDID();
testEscrow();
// testMPToken();
testMPToken();
// testNFToken();
// testNFTokenOffer();
// testPayChan();
// testPermissionedDomain();
testNFTokenOffer();
testPayChan();
testPermissionedDomain();
// testOracle();
testSignerList();
testTrustSet();

View File

@@ -254,6 +254,8 @@ expectLedgerEntryRoot(
/* Payment Channel */
/******************************************************************************/
namespace paychan {
Json::Value
create(
AccountID const& account,
@@ -312,6 +314,8 @@ channelBalance(ReadView const& view, uint256 const& chan);
bool
channelExists(ReadView const& view, uint256 const& chan);
} // namespace paychan
/* Crossing Limits */
/******************************************************************************/

View File

@@ -231,6 +231,8 @@ expectLedgerEntryRoot(
/* Payment Channel */
/******************************************************************************/
namespace paychan {
Json::Value
create(
AccountID const& account,
@@ -322,6 +324,8 @@ channelExists(ReadView const& view, uint256 const& chan)
return bool(slep);
}
} // namespace paychan
/* Crossing Limits */
/******************************************************************************/

View File

@@ -370,15 +370,16 @@ CredentialAccept::doApply()
if (!sleSubject || !sleIssuer)
return tefINTERNAL;
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
auto const newSponsor = getTxReserveSponsor(view(), ctx_.tx);
if (auto const ret = checkInsufficientReserve(
view(), sleSubject, mPriorBalance, sponsor, 1);
view(), sleSubject, mPriorBalance, newSponsor, 1);
!isTesSuccess(ret))
return ret;
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(account_, issuer, credType);
auto const sleCred = view().peek(credentialKey); // Checked in preclaim()
auto const currentSponsor = getLedgerEntryReserveSponsor(view(), sleCred);
if (checkExpired(sleCred, view().info().parentCloseTime))
{
@@ -391,8 +392,8 @@ CredentialAccept::doApply()
sleCred->setFieldU32(sfFlags, lsfAccepted);
view().update(sleCred);
adjustOwnerCount(view(), sleIssuer, sponsor, -1, j_);
auto const newSponsor = getTxReserveSponsor(view(), ctx_.tx);
adjustOwnerCount(view(), sleIssuer, currentSponsor, -1, j_);
removeSponsorFromLedgerEntry(sleCred);
adjustOwnerCount(view(), sleSubject, newSponsor, 1, j_);
addSponsorToLedgerEntry(sleCred, newSponsor);

View File

@@ -79,17 +79,22 @@ getLedgerEntryOwner(
auto const signerList = view.read(keylet::signers(account));
if (!signerList)
return std::nullopt;
if (signerList->getFieldH256(sfObjectID) ==
sle->getFieldH256(sfObjectID))
if (signerList->getFieldH256(sfLedgerIndex) ==
sle->getFieldH256(sfLedgerIndex))
return account;
return std::nullopt;
}
case ltCREDENTIAL: {
if (sle->getFlags() & lsfAccepted)
if (sle->isFlag(lsfAccepted))
return sle->getAccountID(sfSubject);
return sle->getAccountID(sfIssuer);
}
// case ltNFTOKEN_PAGE:
case ltNFTOKEN_PAGE: {
// the upper 20 bytes of the index of ltNFTokenPage are the Owner's
// AccountID
uint256 const& key = sle->key();
return AccountID::fromVoid(key.data());
}
// case ltRIPPLE_STATE:
case ltACCOUNT_ROOT: {
// AccountRoot is not supported for object sponsorship
@@ -229,9 +234,14 @@ SponsorshipTransfer::doApply()
if (auto const oldSponsorSle =
view().peek(keylet::account(oldSponsor)))
{
oldSponsorSle->setFieldU32(
sfSponsoringOwnerCount,
oldSponsorSle->getFieldU32(sfSponsoringOwnerCount) - 1);
auto const newCount =
oldSponsorSle->getFieldU32(sfSponsoringOwnerCount) - 1;
if (newCount == 0)
oldSponsorSle->makeFieldAbsent(sfSponsoringOwnerCount);
else
oldSponsorSle->setFieldU32(
sfSponsoringOwnerCount, newCount);
view().update(oldSponsorSle);
}
else
@@ -257,9 +267,13 @@ SponsorshipTransfer::doApply()
// dissolve object sponsor
auto const oldSponsor = objSle->getAccountID(sfSponsorAccount);
// decrement sponsored count
accSle->setFieldU32(
sfSponsoredOwnerCount,
accSle->getFieldU32(sfSponsoredOwnerCount) - 1);
auto const newCount =
accSle->getFieldU32(sfSponsoredOwnerCount) - 1;
if (newCount == 0)
accSle->makeFieldAbsent(sfSponsoredOwnerCount);
else
accSle->setFieldU32(sfSponsoredOwnerCount, newCount);
view().update(accSle);
// decrement old sponsoring count
if (auto const oldSponsorSle =