From 76a034b747bce907196b559ed93ada3dea2f582e Mon Sep 17 00:00:00 2001 From: JCW Date: Mon, 17 Aug 2026 16:02:35 +0100 Subject: [PATCH] WIP --- include/xrpl/tx/invariants/VaultInvariant.h | 3 +++ src/libxrpl/tx/invariants/VaultInvariant.cpp | 14 ++++++++++++++ src/libxrpl/tx/transactors/lending/LoanAccept.cpp | 10 ++++++++++ src/libxrpl/tx/transactors/vault/VaultDelete.cpp | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/include/xrpl/tx/invariants/VaultInvariant.h b/include/xrpl/tx/invariants/VaultInvariant.h index 136c6c4a25..aad803458e 100644 --- a/include/xrpl/tx/invariants/VaultInvariant.h +++ b/include/xrpl/tx/invariants/VaultInvariant.h @@ -31,6 +31,8 @@ namespace xrpl { * - loss unrealized does not exceed the difference between assets total and * assets available * - assets available do not exceed assets total + * - assets reserved is non-negative + * - sum of assets available and reserved does not exceed assets total * - vault deposit increases assets and share issuance, and adds to: * total assets, assets available, shares outstanding * - vault withdrawal and clawback reduce assets and share issuance, and @@ -55,6 +57,7 @@ class ValidVault Number assetsAvailable = 0; Number assetsMaximum = 0; Number lossUnrealized = 0; + Number assetsReserved = 0; Vault static make(SLE const&); }; diff --git a/src/libxrpl/tx/invariants/VaultInvariant.cpp b/src/libxrpl/tx/invariants/VaultInvariant.cpp index 7aa92e79cd..3a4ede1c08 100644 --- a/src/libxrpl/tx/invariants/VaultInvariant.cpp +++ b/src/libxrpl/tx/invariants/VaultInvariant.cpp @@ -44,6 +44,7 @@ ValidVault::Vault::make(SLE const& from) self.assetsAvailable = from.at(sfAssetsAvailable); self.assetsMaximum = from.at(sfAssetsMaximum); self.lossUnrealized = from.at(sfLossUnrealized); + self.assetsReserved = from.at(sfAssetsReserved); return self; } @@ -495,6 +496,19 @@ ValidVault::finalize( result = false; } + if (afterVault.assetsReserved < kZero) + { + JLOG(j.fatal()) << "Invariant failed: assets reserved must be positive"; + result = false; + } + + if (afterVault.assetsAvailable + afterVault.assetsReserved > afterVault.assetsTotal) + { + JLOG(j.fatal()) << "Invariant failed: sum of assets available and " + "reserved must not be greater than assets outstanding"; + result = false; + } + // Thanks to this check we can simply do `assert(!beforeVault_.empty()` when // enforcing invariants on transaction types other than ttVAULT_CREATE if (beforeVault_.empty() && txnType != ttVAULT_CREATE) diff --git a/src/libxrpl/tx/transactors/lending/LoanAccept.cpp b/src/libxrpl/tx/transactors/lending/LoanAccept.cpp index 62c697d156..be78429d4a 100644 --- a/src/libxrpl/tx/transactors/lending/LoanAccept.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanAccept.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,15 @@ LoanAccept::preclaim(PreclaimContext const& ctx) ctx.view, asset, vaultPseudo, brokerPseudo, account, brokerOwner, ctx.j)) return ter; + // Re-verify that the borrower and broker owner (the two accounts that + // receive funds at disbursement) are authorised to hold the vault asset. + // WeakAuth is used because the holdings need not exist yet; they are + // created at disbursement. + if (auto const ter = requireAuth(ctx.view, asset, account, AuthType::WeakAuth)) + return ter; + if (auto const ter = requireAuth(ctx.view, asset, brokerOwner, AuthType::WeakAuth)) + return ter; + return tesSUCCESS; } diff --git a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp index 497a2f2465..80c1a866e1 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp @@ -64,6 +64,12 @@ VaultDelete::preclaim(PreclaimContext const& ctx) return tecHAS_OBLIGATIONS; } + if (vault->at(sfAssetsReserved) != 0) + { + JLOG(ctx.j.debug()) << "VaultDelete: nonzero assets reserved."; + return tecHAS_OBLIGATIONS; + } + // Verify we can destroy MPTokenIssuance auto const sleMPT = ctx.view.read(keylet::mptokenIssuance(vault->at(sfShareMPTID)));