Compare commits

..

1 Commits

Author SHA1 Message Date
JCW
31b48e3b08 Fix the bug
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-12-05 09:27:21 +00:00
5 changed files with 19 additions and 68 deletions

View File

@@ -655,7 +655,7 @@ createPseudoAccount(
uint256 const& pseudoOwnerKey, uint256 const& pseudoOwnerKey,
SField const& ownerField); SField const& ownerField);
// Returns true iff sleAcct is a pseudo-account or specific // Returns true if sleAcct is a pseudo-account or specific
// pseudo-accounts in pseudoFieldFilter. // pseudo-accounts in pseudoFieldFilter.
// //
// Returns false if sleAcct is // Returns false if sleAcct is

View File

@@ -1024,6 +1024,12 @@ class LoanBroker_test : public beast::unit_test::suite
destination(dest), destination(dest),
ter(tecFROZEN), ter(tecFROZEN),
THISLINE); THISLINE);
// preclaim: tecPSEUDO_ACCOUNT
env(coverWithdraw(alice, brokerKeylet.key, asset(10)),
destination(vaultInfo.pseudoAccount),
ter(tecPSEUDO_ACCOUNT),
THISLINE);
} }
if (brokerTest == CoverClawback) if (brokerTest == CoverClawback)

View File

@@ -5243,46 +5243,6 @@ class Vault_test : public beast::unit_test::suite
}); });
} }
void
testFrozenWithdrawToIssuer()
{
using namespace test::jtx;
testcase("frozen IOU can be withdrawn to issuer");
Env env{*this, testable_amendments() | featureSingleAssetVault};
Account issuer{"issuer"};
Account owner{"owner"};
Account depositor{"depositor"};
env.fund(XRP(1000), issuer, owner, depositor);
env.close();
PrettyAsset asset = issuer["IOU"];
env.trust(asset(1000), owner);
env.trust(asset(1000), depositor);
env(pay(issuer, owner, asset(100)));
env(pay(issuer, depositor, asset(200)));
env.close();
Vault vault{env};
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
env(tx);
env.close();
env(vault.deposit(
{.depositor = depositor, .id = keylet.key, .amount = asset(50)}));
env.close();
env(fset(issuer, asfGlobalFreeze));
env.close();
auto withdraw = vault.withdraw(
{.depositor = depositor, .id = keylet.key, .amount = asset(10)});
withdraw[sfDestination] = issuer.human();
env(withdraw, ter{tesSUCCESS});
env.close();
}
public: public:
void void
run() override run() override
@@ -5301,7 +5261,6 @@ public:
testScaleIOU(); testScaleIOU();
testRPC(); testRPC();
testDelegate(); testDelegate();
testFrozenWithdrawToIssuer();
} }
}; };

View File

@@ -48,6 +48,11 @@ LoanBrokerCoverWithdraw::preclaim(PreclaimContext const& ctx)
auto const dstAcct = tx[~sfDestination].value_or(account); auto const dstAcct = tx[~sfDestination].value_or(account);
if (isPseudoAccount(ctx.view, dstAcct))
{
JLOG(ctx.j.warn()) << "Trying to withdraw into a pseudo-account.";
return tecPSEUDO_ACCOUNT;
}
auto const sleBroker = ctx.view.read(keylet::loanbroker(brokerID)); auto const sleBroker = ctx.view.read(keylet::loanbroker(brokerID));
if (!sleBroker) if (!sleBroker)
{ {

View File

@@ -80,23 +80,13 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
return ter; return ter;
// Cannot withdraw from a Vault an Asset frozen for the destination account // Cannot withdraw from a Vault an Asset frozen for the destination account
if (!vaultAsset.holds<Issue>() ||
(dstAcct != vaultAsset.getIssuer() &&
account != vaultAsset.getIssuer()))
{
if (auto const ret = checkFrozen(ctx.view, dstAcct, vaultAsset)) if (auto const ret = checkFrozen(ctx.view, dstAcct, vaultAsset))
return ret; return ret;
}
// Cannot return shares to the vault, if the underlying asset was frozen for // Cannot return shares to the vault, if the underlying asset was frozen for
// the submitter // the submitter
if (!vaultAsset.holds<Issue>() ||
(dstAcct != vaultAsset.getIssuer() &&
account != vaultAsset.getIssuer()))
{
if (auto const ret = checkFrozen(ctx.view, account, vaultShare)) if (auto const ret = checkFrozen(ctx.view, account, vaultShare))
return ret; return ret;
}
return tesSUCCESS; return tesSUCCESS;
} }
@@ -125,7 +115,6 @@ VaultWithdraw::doApply()
auto const amount = ctx_.tx[sfAmount]; auto const amount = ctx_.tx[sfAmount];
Asset const vaultAsset = vault->at(sfAsset); Asset const vaultAsset = vault->at(sfAsset);
auto const dstAcct = ctx_.tx[~sfDestination].value_or(account_);
MPTIssue const share{mptIssuanceID}; MPTIssue const share{mptIssuanceID};
STAmount sharesRedeemed = {share}; STAmount sharesRedeemed = {share};
STAmount assetsWithdrawn; STAmount assetsWithdrawn;
@@ -176,21 +165,11 @@ VaultWithdraw::doApply()
return tecPATH_DRY; return tecPATH_DRY;
} }
// When withdrawing IOU to the issuer, ignore freeze since spec allows
// returning frozen IOU assets to their issuer. MPTs don't have this
// exemption - MPT locks function like "deep freeze" with no issuer
// exception.
FreezeHandling const freezeHandling = (vaultAsset.holds<Issue>() &&
(dstAcct == vaultAsset.getIssuer() ||
account_ == vaultAsset.getIssuer()))
? FreezeHandling::fhIGNORE_FREEZE
: FreezeHandling::fhZERO_IF_FROZEN;
if (accountHolds( if (accountHolds(
view(), view(),
account_, account_,
share, share,
freezeHandling, FreezeHandling::fhZERO_IF_FROZEN,
AuthHandling::ahIGNORE_AUTH, AuthHandling::ahIGNORE_AUTH,
j_) < sharesRedeemed) j_) < sharesRedeemed)
{ {
@@ -258,6 +237,8 @@ VaultWithdraw::doApply()
// else quietly ignore, account balance is not zero // else quietly ignore, account balance is not zero
} }
auto const dstAcct = ctx_.tx[~sfDestination].value_or(account_);
return doWithdraw( return doWithdraw(
view(), view(),
ctx_.tx, ctx_.tx,