mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-30 10:30:22 +00:00
Fix sponsor reserve accounting edge cases (#7575)
This commit is contained in:
@@ -1048,6 +1048,10 @@ ValidVault::finalize(
|
||||
// TBD
|
||||
return true;
|
||||
}
|
||||
case ttSPONSORSHIP_TRANSFER: {
|
||||
// SponsorshipTransfer may update a vault's sfSponsor
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
// LCOV_EXCL_START
|
||||
|
||||
@@ -205,6 +205,9 @@ getLedgerEntryOwnerCount(T const& sle)
|
||||
case ltORACLE: {
|
||||
return OracleSet::calculateOracleReserve(sle->getFieldArray(sfPriceDataSeries).size());
|
||||
}
|
||||
// Vaults require 2 owner counts (the vault and a pseudo-account)
|
||||
case ltVAULT:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -132,6 +132,9 @@ Payment::preflight(PreflightContext const& ctx)
|
||||
if (tx.isFlag(tfNoRippleDirect) || tx.isFlag(tfPartialPayment) || tx.isFlag(tfLimitQuality))
|
||||
return temINVALID_FLAG;
|
||||
|
||||
if (tx.isFieldPresent(sfSendMax) || tx.isFieldPresent(sfPaths))
|
||||
return temINVALID;
|
||||
|
||||
if (!dstAmount.native())
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
#include <test/jtx/multisign.h>
|
||||
#include <test/jtx/noop.h>
|
||||
#include <test/jtx/offer.h>
|
||||
#include <test/jtx/paths.h>
|
||||
#include <test/jtx/pay.h>
|
||||
#include <test/jtx/permissioned_domains.h>
|
||||
#include <test/jtx/sendmax.h>
|
||||
#include <test/jtx/seq.h>
|
||||
#include <test/jtx/sig.h>
|
||||
#include <test/jtx/sponsor.h>
|
||||
@@ -1856,6 +1858,20 @@ public:
|
||||
env(pay(alice, bob, usd(100)), Txflags(tfSponsorCreatedAccount), Ter(temBAD_AMOUNT));
|
||||
env.close();
|
||||
|
||||
// Sponsored account creation is reserve sponsorship and is only supported for direct XRP
|
||||
// payments.
|
||||
env(pay(alice, bob, drops(1)),
|
||||
Txflags(tfSponsorCreatedAccount),
|
||||
Sendmax(usd(2)),
|
||||
Ter(temINVALID));
|
||||
env.close();
|
||||
|
||||
env(pay(alice, bob, drops(1)),
|
||||
Txflags(tfSponsorCreatedAccount),
|
||||
Path(~XRP),
|
||||
Ter(temINVALID));
|
||||
env.close();
|
||||
|
||||
// Account is not sponsored by normal Sponsor specification
|
||||
{
|
||||
env(pay(alice, bob, drops(baseAccountReserve(*env.current(), 0))),
|
||||
@@ -4994,6 +5010,61 @@ public:
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
}
|
||||
// SponsorshipTransfer
|
||||
{
|
||||
Env env{*this, testableAmendments()};
|
||||
env.fund(XRP(1000000), alice, bob, gw, sponsor);
|
||||
env.close();
|
||||
|
||||
Vault const vault{env};
|
||||
auto const [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
// Alice owns the vault, pseudo account and MPToken
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 3);
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
|
||||
if (cosigning)
|
||||
{
|
||||
// Alice lets sponsor to sponsor her Vault
|
||||
env(sponsor::transfer(alice, tfSponsorshipCreate, vaultKeylet.key),
|
||||
sponsor::As(sponsor, spfSponsorReserve),
|
||||
Sig(sfSponsorSignature, sponsor));
|
||||
env.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create sponsorship with reserve count being 2 (for vault and pseudo account)
|
||||
env(sponsor::set_reserve(sponsor, 0, 2), sponsor::SponseeAcc(alice));
|
||||
env.close();
|
||||
env(sponsor::transfer(alice, tfSponsorshipCreate, vaultKeylet.key),
|
||||
sponsor::As(sponsor, spfSponsorReserve));
|
||||
env.close();
|
||||
|
||||
auto const sponsorshipSle = env.le(keylet::sponsor(sponsor, alice));
|
||||
if (!BEAST_EXPECT(sponsorshipSle))
|
||||
return;
|
||||
BEAST_EXPECT(sponsorshipSle->getFieldU32(sfReserveCount) == 0);
|
||||
}
|
||||
|
||||
BEAST_EXPECT(env.le(vaultKeylet)->getAccountID(sfSponsor) == sponsor.id());
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 3);
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2);
|
||||
// Vault counts for 2 reserves, vault and the pseudo account
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 2);
|
||||
|
||||
// End sponsorship
|
||||
env(sponsor::transfer(alice, tfSponsorshipEnd, vaultKeylet.key));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(!env.le(vaultKeylet)->isFieldPresent(sfSponsor));
|
||||
BEAST_EXPECT(ownerCount(env, alice) == 3);
|
||||
// Sponsorship ended and the sponsored owner count should be 0.
|
||||
BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0);
|
||||
BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user