mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-25 16:10:57 +00:00
test: Add more tests for sponsor edge cases (#7746)
This commit is contained in:
@@ -2608,6 +2608,76 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
||||
|
||||
// the newly-created trust line carries the sponsor on
|
||||
// bob's side, and no sponsor on the counterparty side
|
||||
bool const bobLow = bob.id() < gw.id();
|
||||
auto const lineSle = env.le(keylet::trustLine(bob, gw, usd.currency));
|
||||
BEAST_EXPECT(lineSle);
|
||||
if (lineSle)
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
lineSle->getAccountID(bobLow ? sfLowSponsor : sfHighSponsor) ==
|
||||
sponsor.id());
|
||||
BEAST_EXPECT(
|
||||
!lineSle->isFieldPresent(bobLow ? sfHighSponsor : sfLowSponsor));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// MPT sponsor: cashing an MPT check creates a sponsored MPToken for
|
||||
// the casher. Unlike the trust-line path, this returns
|
||||
// tecINSUFFICIENT_RESERVE (not tecNO_LINE_INSUF_RESERVE) on shortfall.
|
||||
{
|
||||
Env env{*this, testableAmendments()};
|
||||
env.fund(XRP(10000), bob, sponsor, sponsor2);
|
||||
env.close();
|
||||
|
||||
MPTTester mptGw(env, gw, {.holders = {alice}});
|
||||
mptGw.create({.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});
|
||||
mptGw.authorize({.account = alice});
|
||||
auto const mpt = mptGw["MPT"];
|
||||
env(pay(gw, alice, mpt(10'000)));
|
||||
env.close();
|
||||
|
||||
// CheckCreate (alice -> bob) paying the MPT
|
||||
uint32_t seq2 = 0;
|
||||
testEachSponsorship(
|
||||
env,
|
||||
cosigning,
|
||||
sponsor,
|
||||
alice,
|
||||
1,
|
||||
1,
|
||||
tecINSUFFICIENT_RESERVE,
|
||||
[&](Env& env, auto const& submit) {
|
||||
seq2 = env.seq(alice);
|
||||
submit(check::create(alice, bob, mpt(1)));
|
||||
});
|
||||
|
||||
auto const checkKeylet = keylet::check(alice, seq2);
|
||||
BEAST_EXPECT(env.le(checkKeylet)->getAccountID(sfSponsor) == sponsor.id());
|
||||
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
||||
|
||||
// CheckCash by bob (no MPToken yet) creates a sponsored MPToken
|
||||
testEachSponsorship(
|
||||
env,
|
||||
cosigning,
|
||||
sponsor,
|
||||
bob,
|
||||
1,
|
||||
1,
|
||||
tecINSUFFICIENT_RESERVE,
|
||||
[&](Env& env, auto const& submit) {
|
||||
submit(check::cash(bob, checkKeylet.key, mpt(1)));
|
||||
},
|
||||
[&]() {
|
||||
BEAST_EXPECT(ownerCount(env, bob) == 1); // MPToken
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
||||
BEAST_EXPECT(
|
||||
env.le(keylet::mptoken(mptGw.issuanceID(), bob))->getAccountID(sfSponsor) ==
|
||||
sponsor.id());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2640,8 +2710,11 @@ public:
|
||||
submit(delegate::set(alice, bob, {"Payment"}));
|
||||
});
|
||||
|
||||
// transfer sponsor
|
||||
// the created Delegate object carries the sponsor
|
||||
auto const keylet = keylet::delegate(alice, bob);
|
||||
BEAST_EXPECT(env.le(keylet)->getAccountID(sfSponsor) == sponsor.id());
|
||||
|
||||
// transfer sponsor
|
||||
if (cosigning)
|
||||
{
|
||||
env(sponsor::transfer(alice, tfSponsorshipReassign, keylet.key),
|
||||
@@ -2663,6 +2736,7 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
||||
BEAST_EXPECT(env.le(keylet)->getAccountID(sfSponsor) == sponsor2.id());
|
||||
|
||||
// delete
|
||||
env(delegate::set(alice, bob, {}));
|
||||
@@ -2700,8 +2774,11 @@ public:
|
||||
tecINSUFFICIENT_RESERVE,
|
||||
[&](Env& env, auto const& submit) { submit(deposit::auth(alice, sponsor)); });
|
||||
|
||||
// transfer sponsor
|
||||
// the created DepositPreauth object carries the sponsor
|
||||
auto const keylet = keylet::depositPreauth(alice, sponsor);
|
||||
BEAST_EXPECT(env.le(keylet)->getAccountID(sfSponsor) == sponsor.id());
|
||||
|
||||
// transfer sponsor
|
||||
if (cosigning)
|
||||
{
|
||||
env(sponsor::transfer(alice, tfSponsorshipReassign, keylet.key),
|
||||
@@ -2732,6 +2809,7 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
||||
BEAST_EXPECT(env.le(keylet)->getAccountID(sfSponsor) == sponsor2.id());
|
||||
|
||||
// DepositPreauthDelete
|
||||
env(deposit::unauth(alice, sponsor));
|
||||
@@ -2769,6 +2847,7 @@ public:
|
||||
|
||||
// Cover sfUnauthorizeCredentials cleanup for a sponsored preauth object.
|
||||
BEAST_EXPECT(env.le(preauthKeylet));
|
||||
BEAST_EXPECT(env.le(preauthKeylet)->getAccountID(sfSponsor) == sponsor.id());
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
||||
@@ -3162,6 +3241,80 @@ public:
|
||||
env.le(keylet::trustLine(bob, gw, usd.currency))->getAccountID(sfHighSponsor) ==
|
||||
sponsor2.id());
|
||||
}
|
||||
{
|
||||
// IOU Escrow cancel re-creates the owner's trust line, and the
|
||||
// cancel transaction's sponsor can cover that new line's reserve.
|
||||
// Creating an IOU escrow moves the sender's balance to the issuer,
|
||||
// so the sender can delete their now-zero trust line while the
|
||||
// escrow is pending. Cancelling returns the funds, re-creating the
|
||||
// line.
|
||||
Env env{*this, testableAmendments()};
|
||||
|
||||
env.fund(XRP(1000000), alice, bob, gw, sponsor, sponsor2);
|
||||
env.close();
|
||||
|
||||
env(fset(gw, asfAllowTrustLineLocking));
|
||||
env.close();
|
||||
|
||||
env.trust(usd(1000000), alice);
|
||||
env.close();
|
||||
env(pay(gw, alice, usd(10000)));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
||||
|
||||
// alice escrows her entire balance so the trust line can be removed
|
||||
auto const cancelAfter = env.now() + 100s;
|
||||
auto const seq = env.seq(alice);
|
||||
env(escrow::create(alice, bob, usd(10000)),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kCancelTime(cancelAfter));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 2); // trust line + escrow
|
||||
|
||||
// alice deletes her now-zero trust line while the escrow is pending
|
||||
env(trust(alice, usd(0)));
|
||||
env.close();
|
||||
BEAST_EXPECT(!env.le(keylet::trustLine(alice, gw, usd.currency)));
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 1); // just the escrow
|
||||
|
||||
// advance the ledger past the cancel time
|
||||
for (; env.now() < cancelAfter; env.close())
|
||||
{
|
||||
}
|
||||
|
||||
// EscrowCancel by alice re-creates her trust line; the sponsor
|
||||
// covers the new line's reserve. On the insufficient-reserve
|
||||
// attempt the whole transaction rolls back, leaving the escrow
|
||||
// intact to be cancelled on the success attempt.
|
||||
bool const aliceLow = alice.id() < gw.id();
|
||||
testEachSponsorship(
|
||||
env,
|
||||
cosigning,
|
||||
sponsor,
|
||||
alice,
|
||||
1,
|
||||
1,
|
||||
tecNO_LINE_INSUF_RESERVE,
|
||||
[&](Env& env, auto const& submit) { submit(escrow::cancel(alice, alice, seq)); },
|
||||
[&]() {
|
||||
BEAST_EXPECT(!env.le(keylet::escrow(alice, seq)));
|
||||
auto const trustSle = env.le(keylet::trustLine(alice, gw, usd.currency));
|
||||
BEAST_EXPECT(trustSle);
|
||||
if (trustSle)
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
trustSle->getAccountID(aliceLow ? sfLowSponsor : sfHighSponsor) ==
|
||||
sponsor.id());
|
||||
BEAST_EXPECT(
|
||||
!trustSle->isFieldPresent(aliceLow ? sfHighSponsor : sfLowSponsor));
|
||||
}
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 1); // re-created trust line
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
||||
});
|
||||
}
|
||||
{
|
||||
// MPT Escrow
|
||||
Env env{*this, testableAmendments()};
|
||||
@@ -3187,19 +3340,33 @@ public:
|
||||
BEAST_EXPECT(ownerCount(env, bob) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
|
||||
// finish Escrow
|
||||
env(escrow::finish(bob, alice, seq),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFulfillment(escrow::kFb1),
|
||||
sponsor::As(sponsor, spfSponsorReserve),
|
||||
Sig(sfSponsorSignature, sponsor),
|
||||
Fee(XRP(1)));
|
||||
env.close();
|
||||
// finish Escrow: bob has no MPToken, so finishing creates one and
|
||||
// the finish transaction's sponsor covers its reserve. The MPT
|
||||
// create-token path returns tecINSUFFICIENT_RESERVE (not
|
||||
// tecNO_LINE_INSUF_RESERVE) when the sponsor is underfunded.
|
||||
testEachSponsorship(
|
||||
env,
|
||||
cosigning,
|
||||
sponsor,
|
||||
bob,
|
||||
1,
|
||||
1,
|
||||
tecINSUFFICIENT_RESERVE,
|
||||
[&](Env& env, auto const& submit) {
|
||||
submit(
|
||||
escrow::finish(bob, alice, seq),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFulfillment(escrow::kFb1),
|
||||
Fee(XRP(1)));
|
||||
});
|
||||
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(ownerCount(env, bob) == 1);
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1);
|
||||
BEAST_EXPECT(
|
||||
env.le(keylet::mptoken(mptGw.issuanceID(), bob))->getAccountID(sfSponsor) ==
|
||||
sponsor.id());
|
||||
}
|
||||
|
||||
// A sponsored EscrowCreate must still verify that the source
|
||||
@@ -3478,6 +3645,9 @@ public:
|
||||
submit(paychan::create(alice, bob, XRP(100), settleDelay, pk));
|
||||
});
|
||||
|
||||
// the created PayChannel object carries the sponsor
|
||||
BEAST_EXPECT(env.le(Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) == sponsor.id());
|
||||
|
||||
// transfer sponsor
|
||||
if (cosigning)
|
||||
{
|
||||
@@ -3500,6 +3670,7 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
||||
BEAST_EXPECT(env.le(Keylet(ltPAYCHAN, chan))->getAccountID(sfSponsor) == sponsor2.id());
|
||||
|
||||
env.close(env.now() + settleDelay);
|
||||
// PayChanClaim (delete PayChan)
|
||||
@@ -3580,6 +3751,9 @@ public:
|
||||
tecINSUFFICIENT_RESERVE,
|
||||
[&](Env& env, auto const& submit) { submit(signers(alice, 1, {{bob, 1}})); });
|
||||
|
||||
// the created SignerList object carries the sponsor
|
||||
BEAST_EXPECT(env.le(keylet::signerList(alice))->getAccountID(sfSponsor) == sponsor.id());
|
||||
|
||||
// transfer sponsor
|
||||
if (cosigning)
|
||||
{
|
||||
@@ -3615,6 +3789,7 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1);
|
||||
BEAST_EXPECT(env.le(keylet::signerList(alice))->getAccountID(sfSponsor) == sponsor2.id());
|
||||
|
||||
// Delete
|
||||
env(signers(alice, NoneT()));
|
||||
|
||||
Reference in New Issue
Block a user