diff --git a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp index 82fe88aa9f..32a51555b1 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp @@ -52,9 +52,13 @@ DelegateSet::preclaim(PreclaimContext const& ctx) if (!ctx.view.exists(keylet::account(ctx.tx[sfAccount]))) return terNO_ACCOUNT; // LCOV_EXCL_LINE - if (!ctx.view.exists(keylet::account(ctx.tx[sfAuthorize]))) + auto const sleAuthorize = ctx.view.read(keylet::account(ctx.tx[sfAuthorize])); + if (!sleAuthorize) return tecNO_TARGET; + if (isPseudoAccount(sleAuthorize)) + return tecNO_PERMISSION; + // Deleting the delegate object is invalid if it doesn’t exist. if (ctx.tx.getFieldArray(sfPermissions).empty() && !ctx.view.exists(keylet::delegate(ctx.tx[sfAccount], ctx.tx[sfAuthorize]))) diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index 20668a42bf..1516219e46 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -235,6 +235,19 @@ class Delegate_test : public beast::unit_test::Suite env(delegate::set(gw, Account("unknown"), {"Payment"}), Ter(tecNO_TARGET)); } + // Delegating to a pseudo-account is not allowed, should return tecNO_PERMISSION + { + Vault const vault{env}; + auto [tx, keylet] = vault.create({.owner = gw, .asset = xrpIssue()}); + env(tx); + env.close(); + + auto const sleVault = env.le(keylet); + BEAST_EXPECT(sleVault); + Account const vaultPseudo{"vault", sleVault->at(sfAccount)}; + env(delegate::set(gw, vaultPseudo, {"Payment"}), Ter(tecNO_PERMISSION)); + } + // non-delegable transaction { env(delegate::set(gw, alice, {"SetRegularKey"}), Ter(temMALFORMED));