From e4a8ba51f9e3a29ebff84b0f0235c1b32bbf8448 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Thu, 23 Oct 2025 12:58:38 -0400 Subject: [PATCH] check lock in ConfidentialSend (#5933) --- src/test/app/ConfidentialTransfer_test.cpp | 40 ++++++++++++++++++++ src/xrpld/app/tx/detail/ConfidentialSend.cpp | 14 +++++++ 2 files changed, 54 insertions(+) diff --git a/src/test/app/ConfidentialTransfer_test.cpp b/src/test/app/ConfidentialTransfer_test.cpp index e9a3f56257..243aa5f0d5 100644 --- a/src/test/app/ConfidentialTransfer_test.cpp +++ b/src/test/app/ConfidentialTransfer_test.cpp @@ -819,6 +819,46 @@ class ConfidentialTransfer_test : public beast::unit_test::suite Buffer(ripple::ecGamalEncryptedTotalLength), .err = tecOBJECT_NOT_FOUND}); } + + // issuance is locked globally + { + mptAlice.set({.account = alice, .flags = tfMPTLock}); + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = "123", + .err = tecLOCKED}); + } + + // sender is locked + { + mptAlice.set( + {.account = alice, .flags = tfMPTUnlock}); // unlock issuance + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = "123", + .err = tecLOCKED}); + } + + // destination is locked + { + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = tfMPTUnlock}); // unlock bob + mptAlice.set( + {.account = alice, .holder = carol, .flags = tfMPTLock}); + mptAlice.send( + {.account = bob, + .dest = carol, + .amt = 10, + .proof = "123", + .err = tecLOCKED}); + } } void diff --git a/src/xrpld/app/tx/detail/ConfidentialSend.cpp b/src/xrpld/app/tx/detail/ConfidentialSend.cpp index 9c49fd3d0a..64519f3b15 100644 --- a/src/xrpld/app/tx/detail/ConfidentialSend.cpp +++ b/src/xrpld/app/tx/detail/ConfidentialSend.cpp @@ -79,6 +79,10 @@ ConfidentialSend::preclaim(PreclaimContext const& ctx) if (!sleIssuance) return tecOBJECT_NOT_FOUND; + // Check if the issuance allows transfer + if (!sleIssuance->isFlag(lsfMPTCanTransfer)) + return tecLOCKED; + // Check if issuance allows confidential transfer if (sleIssuance->isFlag(lsfMPTNoConfidentialTransfer)) return tecNO_PERMISSION; @@ -111,6 +115,16 @@ ConfidentialSend::preclaim(PreclaimContext const& ctx) !sleDestinationMPToken->isFieldPresent(sfIssuerEncryptedBalance)) return tecNO_PERMISSION; + // Check lock + MPTIssue const mptIssue(mptIssuanceID); + if (auto const ter = checkFrozen(ctx.view, account, mptIssue); + ter != tesSUCCESS) + return ter; + + if (auto const ter = checkFrozen(ctx.view, destination, mptIssue); + ter != tesSUCCESS) + return ter; + // todo: check zkproof. equality proof and range proof, combined or separate // TBD. TER const terProof = verifyConfidentialSendProof( // ctx.tx[sfZKProof],