From 6b2d698e11e0e67c469f1df876ab647de53ab7c7 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 6 Jul 2026 17:20:58 -0400 Subject: [PATCH] fix: AccountDelete works with sponsored objects --- .../tx/transactors/account/AccountDelete.cpp | 9 +++--- src/test/app/Sponsor_test.cpp | 30 +++++++++++++++---- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/libxrpl/tx/transactors/account/AccountDelete.cpp b/src/libxrpl/tx/transactors/account/AccountDelete.cpp index 6cbb0ff6d3..0e375946a6 100644 --- a/src/libxrpl/tx/transactors/account/AccountDelete.cpp +++ b/src/libxrpl/tx/transactors/account/AccountDelete.cpp @@ -396,9 +396,6 @@ AccountDelete::doApply() if (!isTesSuccess(ter)) return ter; - if (src->isFieldPresent(sfSponsoredOwnerCount)) - return tefINTERNAL; // LCOV_EXCL_LINE - // Transfer any XRP remaining after the fee is paid to the destination: auto const remainingBalance = src->getFieldAmount(sfBalance).xrp(); (*dst)[sfBalance] = (*dst)[sfBalance] + remainingBalance; @@ -410,9 +407,13 @@ AccountDelete::doApply() auto const sponsorID = src->getAccountID(sfSponsor); auto sponsorSle = view().peek(keylet::account(sponsorID)); - if (!sponsorSle || !sponsorSle->isFieldPresent(sfSponsoringAccountCount)) + if (!sponsorSle) return tefINTERNAL; // LCOV_EXCL_LINE + XRPL_ASSERT( + sponsorSle->isFieldPresent(sfSponsoringAccountCount), + "xrpl::AccountDelete::doApply : sponsoring account count is present"); + auto const sponsoringAccountCount = sponsorSle->getFieldU32(sfSponsoringAccountCount); if (sponsoringAccountCount == 0) diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index 21320c034a..fd2e20c732 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -3897,12 +3897,6 @@ public: auto const usd = gw["usd"]; - // Create sponsorship allowing reserve sponsoring - env(sponsor::set(sponsor, 0, 100, XRP(100)), - sponsor::SponseeAcc(alice), - Ter(tesSUCCESS)); - env.close(); - // Create a trust line for alice env(trust(alice, usd(1000))); env.close(); @@ -3962,6 +3956,30 @@ public: BEAST_EXPECT( sponsorSleAfter->getFieldU32(sfSponsoringAccountCount) == sponsoringAccountCount); } + + { + // Account with sponsored objects should be deletable + Env env{*this, testableAmendments()}; + env.fund(XRP(1000000), alice, bob, sponsor); + env.close(); + + // Create sponsored delegate (a non-deletion-blocker) + env(deposit::auth(alice, bob), + sponsor::As(sponsor, spfSponsorReserve), + Sig(sfSponsorSignature, sponsor)); + + auto const sponsorSle = env.le(keylet::account(sponsor)); + auto const aliceSle = env.le(keylet::account(alice)); + BEAST_EXPECT(sponsorSle->at(~sfSponsoringOwnerCount) == 1); + BEAST_EXPECT(aliceSle->at(sfOwnerCount) == 1); + BEAST_EXPECT(aliceSle->at(~sfSponsoredOwnerCount) == 1); + + incLgrSeqForAccDel(env, alice); + + // AccountDelete should succeed + auto const requiredFee = drops(env.current()->fees().increment); + env(acctdelete(alice, bob), Fee(requiredFee), Ter(tesSUCCESS)); + } } void