This commit is contained in:
JCW
2026-08-17 16:02:35 +01:00
parent 1fbdc98242
commit 76a034b747
4 changed files with 33 additions and 0 deletions

View File

@@ -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&);
};

View File

@@ -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)

View File

@@ -7,6 +7,7 @@
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
@@ -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;
}

View File

@@ -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)));