mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
Enforce zero transfer rate for confidential MPT (#7106)
This commit is contained in:
@@ -177,6 +177,12 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
|
||||
if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Sanity check: transfer rate must be 0 for confidential MPTs.
|
||||
// This is unreachable since it is already enforced during MPTokenIssuanceCreate and
|
||||
// MPTokenIssuanceSet.
|
||||
if ((*sleIssuance)[~sfTransferFee].value_or(0) > 0)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// Check if issuance has issuer ElGamal public key
|
||||
if (!sleIssuance->isFieldPresent(sfIssuerEncryptionKey))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
@@ -71,6 +71,10 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx)
|
||||
// must also be set.
|
||||
if (fee > 0u && !ctx.tx.isFlag(tfMPTCanTransfer))
|
||||
return temMALFORMED;
|
||||
|
||||
// Confidential amounts are encrypted so transfer rate is disallowed.
|
||||
if (fee > 0u && ctx.tx.isFlag(tfMPTCanConfidentialAmount))
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (auto const domain = ctx.tx[~sfDomainID])
|
||||
|
||||
@@ -166,6 +166,12 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx)
|
||||
// in the same transaction is not allowed.
|
||||
if ((transferFee.value_or(0) != 0u) && ((*mutableFlags & tmfMPTClearCanTransfer) != 0u))
|
||||
return temMALFORMED;
|
||||
|
||||
// Enabling confidential transfer and setting a non-zero TransferFee
|
||||
// in the same transaction is not allowed.
|
||||
if ((transferFee.value_or(0) > 0u) &&
|
||||
((*mutableFlags & tmfMPTSetCanConfidentialAmount) != 0u))
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +315,12 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
|
||||
// the lsfMPTCanConfidentialAmount flag
|
||||
if (confidentialOA > 0)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Cannot enable confidential transfer on an issuance that has a
|
||||
// non-zero transfer fee
|
||||
if (((*mutableFlags & tmfMPTSetCanConfidentialAmount) != 0u) &&
|
||||
(*sleMptIssuance)[~sfTransferFee].value_or(0) > 0)
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +336,11 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
|
||||
if (fee > 0u && !sleMptIssuance->isFlag(lsfMPTCanTransfer))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Cannot set a non-zero TransferFee on an issuance that has confidential
|
||||
// transfer enabled
|
||||
if (fee > 0u && sleMptIssuance->isFlag(lsfMPTCanConfidentialAmount))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
if (!isMutableFlag(lsmfMPTCanMutateTransferFee))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
@@ -1163,6 +1163,95 @@ class ConfidentialTransfer_test : public beast::unit_test::Suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testTransferFee(FeatureBitset features)
|
||||
{
|
||||
testcase("test transfer fee");
|
||||
using namespace test::jtx;
|
||||
|
||||
// MPTokenIssuanceCreate: cannot create with both TransferFee > 0 and
|
||||
// tfMPTCanConfidentialAmount
|
||||
{
|
||||
Env env{*this, features};
|
||||
Account const alice("alice");
|
||||
MPTTester mptAlice(env, alice, {.holders = {}});
|
||||
|
||||
mptAlice.create({
|
||||
.transferFee = 100,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount,
|
||||
.err = temMALFORMED,
|
||||
});
|
||||
|
||||
// transferFee being 0 is allowed, even with tfMPTCanConfidentialAmount
|
||||
mptAlice.create({
|
||||
.transferFee = 0,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount,
|
||||
});
|
||||
}
|
||||
|
||||
// MPTokenIssuanceSet (preflight): cannot enable confidential amounts and
|
||||
// set TransferFee > 0 in the same transaction
|
||||
{
|
||||
Env env{*this, features};
|
||||
Account const alice("alice");
|
||||
MPTTester mptAlice(env, alice, {.holders = {}});
|
||||
|
||||
mptAlice.create({
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanLock,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee,
|
||||
});
|
||||
|
||||
mptAlice.set({
|
||||
.account = alice,
|
||||
.mutableFlags = tmfMPTSetCanConfidentialAmount,
|
||||
.transferFee = 100,
|
||||
.err = temMALFORMED,
|
||||
});
|
||||
}
|
||||
|
||||
// MPTokenIssuanceSet (preclaim): cannot enable confidential amounts on
|
||||
// an issuance that already has a non-zero TransferFee
|
||||
{
|
||||
Env env{*this, features};
|
||||
Account const alice("alice");
|
||||
MPTTester mptAlice(env, alice, {.holders = {}});
|
||||
|
||||
mptAlice.create({
|
||||
.transferFee = 100,
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanLock,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee,
|
||||
});
|
||||
|
||||
mptAlice.set({
|
||||
.account = alice,
|
||||
.mutableFlags = tmfMPTSetCanConfidentialAmount,
|
||||
.err = tecNO_PERMISSION,
|
||||
});
|
||||
}
|
||||
|
||||
// MPTokenIssuanceSet (preclaim): cannot set TransferFee > 0 on an
|
||||
// issuance that already has lsfMPTCanConfidentialAmount
|
||||
{
|
||||
Env env{*this, features};
|
||||
Account const alice("alice");
|
||||
MPTTester mptAlice(env, alice, {.holders = {}});
|
||||
|
||||
mptAlice.create({
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee,
|
||||
});
|
||||
|
||||
mptAlice.set({
|
||||
.account = alice,
|
||||
.transferFee = 100,
|
||||
.err = tecNO_PERMISSION,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testConvertPreclaim(FeatureBitset features)
|
||||
{
|
||||
@@ -10030,9 +10119,12 @@ class ConfidentialTransfer_test : public beast::unit_test::Suite
|
||||
// Crafted-proof Tests
|
||||
testSendSharedRandomnessViolation(features);
|
||||
|
||||
// Fee Tests
|
||||
// Transaction Fee Tests
|
||||
testConfidentialMPTBaseFee(features);
|
||||
|
||||
// TransferFee (transfer rate) Tests
|
||||
testTransferFee(features);
|
||||
|
||||
// Ticket Tests
|
||||
testWithTickets(features);
|
||||
testConvertTicketProofBinding(features);
|
||||
|
||||
Reference in New Issue
Block a user