diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 352e86c69d..cff9ae380e 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -505,7 +505,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 68, VaultWithdraw, ({ TRANSACTION(ttVAULT_CLAWBACK, 69, VaultClawback, ({ {sfVaultID, soeREQUIRED}, {sfHolder, soeREQUIRED}, - {sfAmount, soeDEFAULT, soeMPTSupported}, + {sfAmount, soeOPTIONAL, soeMPTSupported}, })) /** This system-generated transaction type is used to update the status of the various amendments. diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index 59b17be483..ebb0752fb6 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -203,26 +203,45 @@ class Vault_test : public beast::unit_test::suite } { - testcase(prefix + " clawback"); + testcase(prefix + " clawback some"); auto code = asset.raw().native() ? ter(tecNO_PERMISSION) : ter(tesSUCCESS); auto tx = vault.clawback( {.issuer = issuer, .id = keylet.key, .holder = depositor, - .amount = asset(50)}); + .amount = asset(10)}); env(tx, code); } - // TODO: redeem. + { + testcase(prefix + " clawback all"); + auto code = asset.raw().native() ? ter(tecNO_PERMISSION) + : ter(tesSUCCESS); + auto tx = vault.clawback( + {.issuer = issuer, + .id = keylet.key, + .holder = depositor, + .amount = std::nullopt}); + env(tx, code); + } + + if (!asset.raw().native()) + { + testcase(prefix + " deposit again"); + auto tx = vault.deposit( + {.depositor = depositor, + .id = keylet.key, + .amount = asset(200)}); + env(tx); + } { testcase(prefix + " withdraw non-zero assets"); - auto number = asset.raw().native() ? 200 : 150; auto tx = vault.withdraw( {.depositor = depositor, .id = keylet.key, - .amount = asset(number)}); + .amount = asset(200)}); env(tx); } diff --git a/src/test/jtx/impl/vault.cpp b/src/test/jtx/impl/vault.cpp index 81325844a6..b8a3e001b7 100644 --- a/src/test/jtx/impl/vault.cpp +++ b/src/test/jtx/impl/vault.cpp @@ -94,7 +94,8 @@ Vault::clawback(ClawbackArgs const& args) jv[jss::Account] = args.issuer.human(); jv[jss::VaultID] = to_string(args.id); jv[jss::Holder] = args.holder.human(); - jv[jss::Amount] = to_json(args.amount); + if (args.amount) + jv[jss::Amount] = to_json(*args.amount); return jv; } diff --git a/src/test/jtx/vault.h b/src/test/jtx/vault.h index d070e3451f..abccd67ec7 100644 --- a/src/test/jtx/vault.h +++ b/src/test/jtx/vault.h @@ -95,7 +95,7 @@ struct Vault Account issuer; uint256 id; Account holder; - STAmount amount; + std::optional amount; }; Json::Value diff --git a/src/xrpld/app/tx/detail/VaultClawback.cpp b/src/xrpld/app/tx/detail/VaultClawback.cpp index 4d7fb97fdb..4385e0b6ce 100644 --- a/src/xrpld/app/tx/detail/VaultClawback.cpp +++ b/src/xrpld/app/tx/detail/VaultClawback.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,8 @@ VaultClawback::preflight(PreflightContext const& ctx) return temINVALID_FLAG; // Note, zero amount is valid, it means "all". It is also the default. - if (ctx.tx[sfAmount] < beast::zero) + auto const amount = ctx.tx[~sfAmount]; + if (amount && *amount < beast::zero) return temBAD_AMOUNT; return preflight2(ctx); @@ -61,8 +63,8 @@ VaultClawback::preclaim(PreclaimContext const& ctx) else if (asset.getIssuer() != account) return tecNO_PERMISSION; // Only issuers can clawback. - STAmount const amount = ctx.tx[sfAmount]; - if (asset != amount.asset()) + auto const amount = ctx.tx[~sfAmount]; + if (amount && asset != amount->asset()) return tecWRONG_ASSET; return tesSUCCESS; @@ -76,7 +78,17 @@ VaultClawback::doApply() if (!vault) return tecOBJECT_NOT_FOUND; - STAmount const amount = tx[sfAmount]; + Asset const asset = vault->at(sfAsset); + STAmount const amount = [&]() -> STAmount { + auto const maybeAmount = tx[~sfAmount]; + if (maybeAmount) + return *maybeAmount; + return {sfAmount, asset, 0}; + }(); + XRPL_ASSERT( + amount.asset() == asset, + "ripple::VaultClawback::doApply : matching asset"); + AccountID holder = tx[sfHolder]; STAmount assets, shares; if (amount == beast::zero)