Compare commits

...

34 Commits

Author SHA1 Message Date
Vito Tumas
189f2d60bd Merge branch 'develop' into tapanito/lending-fix-amendment 2026-06-08 14:09:28 +02:00
Vito
beb8a1872d fix: Regenerate protocol autogenerated files 2026-06-08 12:07:19 +02:00
Vito
24db40e56c fix: remove unnecessary tests & clang-tidy 2026-06-08 11:57:42 +02:00
Vito
da4513d096 post-merge cleanup 2026-06-08 11:47:11 +02:00
Vito
2e2fddefe9 Merge remote-tracking branch 'origin/develop' into tapanito/lending-fix-amendment
# Conflicts:
#	include/xrpl/ledger/helpers/LendingHelpers.h
#	include/xrpl/protocol/STAmount.h
#	include/xrpl/protocol/detail/features.macro
#	include/xrpl/protocol/detail/transactions.macro
#	src/libxrpl/tx/invariants/VaultInvariant.cpp
#	src/test/app/Invariants_test.cpp
#	src/test/app/LoanBroker_test.cpp
#	src/test/app/Loan_test.cpp
#	src/test/app/Vault_test.cpp
2026-06-08 11:28:35 +02:00
Vito
db997ecad9 chore: Reset VaultInvariant to develop state before merge
VaultInvariant changes parked in /tmp/vault-invariant-changes.patch
for later re-evaluation.
2026-06-08 11:19:05 +02:00
Vito
68e4fbdf2b Merge remote-tracking branch 'origin/develop' into tapanito/lending-fix-amendment 2026-03-31 10:00:59 +02:00
Vito
bb0a09ae21 Merge remote-tracking branch 'origin/develop' into tapanito/lending-fix-amendment 2026-03-26 17:16:49 +01:00
Vito
d94232007f fix: updates autogen files 2026-03-24 14:34:54 +01:00
Vito
df8bfbe5af fix: errors introduced post-merge 2026-03-24 12:37:06 +01:00
Vito
347d1a19ef Merge remote-tracking branch 'origin/develop' into tapanito/lending-fix-amendment 2026-03-24 12:35:50 +01:00
Vito Tumas
d65fab27a1 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-21 14:39:10 +01:00
Vito Tumas
b5d25c5ab1 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-18 18:39:43 +01:00
Vito Tumas
7222150095 refactor: Rename fixLendingProtocolV1_1 to featureLendingProtocolV1_1 (#6527)
Use XRPL_FEATURE macro instead of XRPL_FIX since
LendingProtocolV1_1 is a feature amendment, not a fix.
Update all references in VaultDelete and related tests.
2026-03-16 09:26:57 +01:00
Vito
a67da5c2ed Merge remote-tracking branch 'origin/develop' into tapanito/lending-fix-amendment 2026-03-09 11:34:59 +01:00
Vito Tumas
d2f23b2f5b Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-05 14:29:35 +01:00
Vito Tumas
4067e5025f Add rounding to Vault invariants (#6217)
Co-authored-by: Ed Hennis <ed@ripple.com>
2026-03-05 10:38:42 +01:00
Vito Tumas
ed4330a7d6 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-04 11:26:33 +01:00
Vito Tumas
feba605998 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-03 15:38:14 +01:00
Vito
b322097529 fixes formatting errors 2026-03-03 13:51:15 +01:00
Vito Tumas
e159d27373 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-03-03 13:48:37 +01:00
Vito Tumas
ba53026006 adds sfMemoData field to VaultDelete transaction (#6356)
* adds sfMemoData field to VaultDelete transaction
2026-02-26 14:13:29 +01:00
Vito Tumas
34773080df Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-25 13:44:20 +01:00
Vito Tumas
3c3bd75991 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-24 14:40:31 +01:00
Vito Tumas
7459fe454d Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-23 12:17:17 +01:00
Vito
106bf48725 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-18 18:29:08 +01:00
Vito Tumas
74c968d4e3 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-17 13:51:08 +01:00
Vito
167147281c Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-12 15:22:30 +01:00
Vito Tumas
ba60306610 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-11 17:46:20 +01:00
Vito Tumas
6674500896 Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-10 11:48:23 +01:00
Vito
c5d7ebe93d restores missing linebreak 2026-02-05 10:24:14 +01:00
Ed Hennis
d0b5ca9dab Merge branch 'develop' into tapanito/lending-fix-amendment 2026-02-04 18:21:55 -04:00
Vito
5e51893e9b fixes a typo 2026-02-04 11:31:58 +01:00
Vito
3422c11d02 adds lending v1.1 fix amendment 2026-02-04 11:30:41 +01:00
6 changed files with 156 additions and 0 deletions

View File

@@ -15,6 +15,7 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_2_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)

View File

@@ -887,6 +887,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
MustDeleteAcct | DestroyMptIssuance | MustModifyVault,
({
{sfVaultID, SoeRequired},
{sfMemoData, SoeOptional},
}))
/** This transaction trades assets for shares with a vault. */

View File

@@ -57,6 +57,32 @@ public:
{
return this->tx_->at(sfVaultID);
}
/**
* @brief Get sfMemoData (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_VL::type::value_type>
getMemoData() const
{
if (hasMemoData())
{
return this->tx_->at(sfMemoData);
}
return std::nullopt;
}
/**
* @brief Check if sfMemoData is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasMemoData() const
{
return this->tx_->isFieldPresent(sfMemoData);
}
};
/**
@@ -112,6 +138,17 @@ public:
return *this;
}
/**
* @brief Set sfMemoData (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultDeleteBuilder&
setMemoData(std::decay_t<typename SF_VL::type::value_type> const& value)
{
object_[sfMemoData] = value;
return *this;
}
/**
* @brief Build and return the VaultDelete wrapper.
* @param publicKey The public key for signing.

View File

@@ -7,8 +7,10 @@
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
@@ -28,6 +30,14 @@ VaultDelete::preflight(PreflightContext const& ctx)
return temMALFORMED;
}
if (ctx.tx.isFieldPresent(sfMemoData) && !ctx.rules.enabled(featureLendingProtocolV1_1))
return temDISABLED;
// The sfMemoData field is an optional field used to record the deletion reason.
if (auto const data = ctx.tx[~sfMemoData];
data && !validDataLength(data, kMaxDataPayloadLength))
return temMALFORMED;
return tesSUCCESS;
}

View File

@@ -8027,6 +8027,63 @@ class Vault_test : public beast::unit_test::Suite
}
}
void
testVaultDeleteData()
{
using namespace test::jtx;
Env env{*this};
Account const owner{"owner"};
env.fund(XRP(1'000'000), owner);
env.close();
Vault const vault{env};
auto const keylet = keylet::vault(owner.id(), 1);
auto delTx = vault.del({.owner = owner, .id = keylet.key});
// Test VaultDelete with featureLendingProtocolV1_1 disabled
// Transaction fails if the data field is provided
{
testcase("VaultDelete data featureLendingProtocolV1_1 disabled");
env.disableFeature(featureLendingProtocolV1_1);
delTx[sfMemoData] = strHex(std::string(kMaxDataPayloadLength, 'A'));
env(delTx, Ter(temDISABLED));
env.close();
env.enableFeature(featureLendingProtocolV1_1);
}
// Transaction fails if the data field is too large
{
testcase("VaultDelete data featureLendingProtocolV1_1 enabled data too large");
delTx[sfMemoData] = strHex(std::string(kMaxDataPayloadLength + 1, 'A'));
env(delTx, Ter(temMALFORMED));
env.close();
}
// Transaction fails if the data field is set, but is empty
{
testcase("VaultDelete data featureLendingProtocolV1_1 enabled data empty");
delTx[sfMemoData] = strHex(std::string(0, 'A'));
env(delTx, Ter(temMALFORMED));
env.close();
}
{
testcase("VaultDelete data featureLendingProtocolV1_1 enabled data valid");
PrettyAsset const xrpAsset = xrpIssue();
auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpAsset});
env(tx, Ter(tesSUCCESS));
env.close();
// Recreate the transaction as the vault keylet changed
auto delTx = vault.del({.owner = owner, .id = keylet.key});
delTx[sfMemoData] = strHex(std::string(kMaxDataPayloadLength, 'A'));
env(delTx, Ter(tesSUCCESS));
env.close();
}
}
public:
void
run() override
@@ -8055,6 +8112,7 @@ public:
testVaultClawbackAssets();
testVaultEscrowedMPT();
testAssetsMaximum();
testVaultDeleteData();
testBug6LimitBypassWithShares();
testRemoveEmptyHoldingLockedAmount();

View File

@@ -30,6 +30,7 @@ TEST(TransactionsVaultDeleteTests, BuilderSettersRoundTrip)
// Transaction-specific field values
auto const vaultIDValue = canonical_UINT256();
auto const memoDataValue = canonical_VL();
VaultDeleteBuilder builder{
accountValue,
@@ -39,6 +40,7 @@ TEST(TransactionsVaultDeleteTests, BuilderSettersRoundTrip)
};
// Set optional fields
builder.setMemoData(memoDataValue);
auto tx = builder.build(publicKey, secretKey);
@@ -62,6 +64,14 @@ TEST(TransactionsVaultDeleteTests, BuilderSettersRoundTrip)
}
// Verify optional fields
{
auto const& expected = memoDataValue;
auto const actualOpt = tx.getMemoData();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMemoData should be present";
expectEqualField(expected, *actualOpt, "sfMemoData");
EXPECT_TRUE(tx.hasMemoData());
}
}
// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper,
@@ -79,6 +89,7 @@ TEST(TransactionsVaultDeleteTests, BuilderFromStTxRoundTrip)
// Transaction-specific field values
auto const vaultIDValue = canonical_UINT256();
auto const memoDataValue = canonical_VL();
// Build an initial transaction
VaultDeleteBuilder initialBuilder{
@@ -88,6 +99,7 @@ TEST(TransactionsVaultDeleteTests, BuilderFromStTxRoundTrip)
feeValue
};
initialBuilder.setMemoData(memoDataValue);
auto initialTx = initialBuilder.build(publicKey, secretKey);
@@ -112,6 +124,13 @@ TEST(TransactionsVaultDeleteTests, BuilderFromStTxRoundTrip)
}
// Verify optional fields
{
auto const& expected = memoDataValue;
auto const actualOpt = rebuiltTx.getMemoData();
ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMemoData should be present";
expectEqualField(expected, *actualOpt, "sfMemoData");
}
}
// 3) Verify wrapper throws when constructed from wrong transaction type.
@@ -142,5 +161,35 @@ TEST(TransactionsVaultDeleteTests, BuilderThrowsOnWrongTxType)
EXPECT_THROW(VaultDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error);
}
// 5) Build with only required fields and verify optional fields return nullopt.
TEST(TransactionsVaultDeleteTests, OptionalFieldsReturnNullopt)
{
// Generate a deterministic keypair for signing
auto const [publicKey, secretKey] =
generateKeyPair(KeyType::Secp256k1, generateSeed("testVaultDeleteNullopt"));
// Common transaction fields
auto const accountValue = calcAccountID(publicKey);
std::uint32_t const sequenceValue = 3;
auto const feeValue = canonical_AMOUNT();
// Transaction-specific required field values
auto const vaultIDValue = canonical_UINT256();
VaultDeleteBuilder builder{
accountValue,
vaultIDValue,
sequenceValue,
feeValue
};
// Do NOT set optional fields
auto tx = builder.build(publicKey, secretKey);
// Verify optional fields are not present
EXPECT_FALSE(tx.hasMemoData());
EXPECT_FALSE(tx.getMemoData().has_value());
}
}