From 613fe48d545d50ddeb8cdc52ea58ccebbe794525 Mon Sep 17 00:00:00 2001 From: tequ Date: Sat, 20 Sep 2025 11:44:47 +0900 Subject: [PATCH] update account_objects for sponsorship --- include/xrpl/protocol/jss.h | 1 + src/test/rpc/AccountObjects_test.cpp | 37 ++++++++++++++++++++++- src/xrpld/rpc/detail/RPCHelpers.cpp | 28 ++++++++++++++--- src/xrpld/rpc/detail/RPCHelpers.h | 1 + src/xrpld/rpc/handlers/AccountObjects.cpp | 13 ++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 07b9e58927..dc6f1be28b 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -582,6 +582,7 @@ JSS(source_currencies); // in: PathRequest, RipplePathFind JSS(source_tag); // out: AccountChannels JSS(sponsee); // in: LedgerEntry JSS(sponsor); // in: LedgerEntry +JSS(sponsored); // in: AccountObjects JSS(stand_alone); // out: NetworkOPs JSS(standard_deviation); // out: get_aggregate_price JSS(start); // in: TxHistory diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 546bbe8715..ceb091e72a 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -630,6 +630,7 @@ public: BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0)); BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::did), 0)); BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::permissioned_domain), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::sponsorship), 0)); // we expect invalid field type reported for the following types BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments))); @@ -983,6 +984,39 @@ public: BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == seq + 1); } + { + // Create a sponsorship + env(sponsor::set( + alice, + gw, + tfSponsorshipSetRequireSignForFee, + 200, + XRP(100), + drops(10))); + env.close(); + + // Find the sponsorship. + for (auto acct : {alice, gw}) + { + Json::Value const resp = acctObjs(acct, jss::sponsorship); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); + + auto const& sponsorship = + resp[jss::result][jss::account_objects][0u]; + + BEAST_EXPECT(sponsorship[sfOwner.jsonName] == alice.human()); + BEAST_EXPECT(sponsorship[sfSponsee.jsonName] == gw.human()); + BEAST_EXPECT( + sponsorship[sfFlags.jsonName].asUInt() == + tfSponsorshipSetRequireSignForFee); + BEAST_EXPECT( + sponsorship[sfReserveCount.jsonName].asUInt() == 200); + BEAST_EXPECT( + sponsorship[sfFeeAmount.jsonName].asUInt() == 100000000); + BEAST_EXPECT(sponsorship[sfMaxFee.jsonName].asUInt() == 10); + } + } + { // See how "deletion_blockers_only" handles gw's directory. Json::Value params; @@ -997,7 +1031,8 @@ public: jss::NFTokenPage.c_str(), jss::RippleState.c_str(), jss::PayChannel.c_str(), - jss::PermissionedDomain.c_str()}; + jss::PermissionedDomain.c_str(), + jss::Sponsorship.c_str()}; std::sort(v.begin(), v.end()); return v; }(); diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 52a69eb79e..2133f1f2c2 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -157,6 +157,7 @@ getAccountObjects( uint256 dirIndex, uint256 entryIndex, std::uint32_t const limit, + std::optional const sponsored, Json::Value& jvResult) { // check if dirIndex is valid @@ -169,6 +170,13 @@ getAccountObjects( return it != typeFilter.end(); }; + auto sponsoredMatchesFilter = [](bool const sponsored, + std::optional const& sponsor) { + if (sponsored) + return sponsor.has_value(); + return !sponsor.has_value(); + }; + // if dirIndex != 0, then all NFTs have already been returned. only // iterate NFT pages if the filter says so AND dirIndex == 0 bool iterateNFTPages = @@ -297,11 +305,23 @@ getAccountObjects( { auto const sleNode = ledger.read(keylet::child(*iter)); - if (!typeFilter.has_value() || - typeMatchesFilter(typeFilter.value(), sleNode->getType())) - { + bool canAppend = true; + + if (typeFilter.has_value() && + !typeMatchesFilter(typeFilter.value(), sleNode->getType())) + canAppend = false; + + std::optional const sponsor = + sleNode->isFieldPresent(sfSponsorAccount) + ? sleNode->getAccountID(sfSponsorAccount) + : std::optional(std::nullopt); + + if (sponsored.has_value() && + !sponsoredMatchesFilter(sponsored.value(), sponsor)) + canAppend = false; + + if (canAppend) jvObjects.append(sleNode->getJson(JsonOptions::none)); - } if (++i == mlimit) { diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index 1d33d69459..a0af01baf3 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -109,6 +109,7 @@ getAccountObjects( uint256 dirIndex, uint256 entryIndex, std::uint32_t const limit, + std::optional const sponsored, Json::Value& jvResult); /** Get ledger by hash diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index 2b2496a1dd..6df319aad7 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -43,6 +43,7 @@ namespace ripple { type: // optional, defaults to all account objects types limit: // optional marker: // optional, resume previous query + sponsored: // optional, defaults to null } */ @@ -226,6 +227,7 @@ doAccountObjects(RPC::JsonContext& context) {jss::mptoken, ltMPTOKEN}, {jss::permissioned_domain, ltPERMISSIONED_DOMAIN}, {jss::vault, ltVAULT}, + {jss::sponsorship, ltSPONSORSHIP}, }; typeFilter.emplace(); @@ -284,6 +286,16 @@ doAccountObjects(RPC::JsonContext& context) return RPC::invalid_field_error(jss::marker); } + std::optional sponsored; + if (params.isMember(jss::sponsored)) + { + auto const& sponsoredJv = params[jss::sponsored]; + if (!sponsoredJv.isBool()) + return RPC::expected_field_error(jss::sponsored, "boolean"); + + sponsored = sponsoredJv.asBool(); + } + if (!RPC::getAccountObjects( *ledger, accountID, @@ -291,6 +303,7 @@ doAccountObjects(RPC::JsonContext& context) dirIndex, entryIndex, limit, + sponsored, result)) return RPC::invalid_field_error(jss::marker);