Files
rippled/include
Vito ec74f74013 refactor: Exempt sfAssetsTotal from the associateAsset sweep post-Lend11
Replace the per-transactor `if (!useDust)` gate around
`associateAsset(*vaultSle, asset)` and the pre-truncation
`- split.receiver->dustDelta` compensation in the dust-aware
Vault writes with a metadata-driven exemption on sfAssetsTotal
itself. Under featureLendingProtocolV1_1, sfAssetsTotal now
retains full Number (19-digit) precision instead of being
truncated to STAmount (16-digit) precision at end of transactor,
so it can absorb the same sub-quantum residual that sfDust
absorbs on the custody line. The receivable invariant becomes
`sfAssetsTotal − (sfAssetsAvailable + custodyLine.sfDust) =
Σ PrincipalOutstanding`, which reduces to the classic form
pre-amendment (dust always zero) and holds byte-for-byte across
arbitrarily long dust-bearing sequences post-amendment.

Design (no signature changes, no plumbing at any of the ~19
associateAsset call sites):

- Introduce `SField::kSmdAssetPreLend11 = 0x100`, semantically
  "swept only when featureLendingProtocolV1_1 is not enabled."
- Retag sfAssetsTotal from `kSmdNeedsAsset | kSmdDefault` to
  `kSmdAssetPreLend11 | kSmdDefault`. sfAssetsAvailable,
  sfAssetsMaximum, sfLossUnrealized keep kSmdNeedsAsset.
- `associateAsset(SLE&, Asset const&)` gate becomes the union
  `kSmdNeedsAsset || (kSmdAssetPreLend11 &&
  !isFeatureEnabled(featureLendingProtocolV1_1))`, read from the
  thread-local CurrentTransactionRulesGuard. No rules installed
  → returns false → sweep runs (safe legacy behavior).
- Widen the Debug-only sanity assertion in
  `STNumber::associateAsset` to accept either bit. The
  serialisation-path check at STNumber::add remains keyed on
  kSmdNeedsAsset only — that is what keeps sfAssetsTotal at full
  precision on the wire post-amendment.

Consequences:

- addVaultAssets: `sfAssetsTotal += Number{valueDelta}` (no
  `- dustDelta` compensation).
- reconcileSenderDust: only sfAssetsAvailable moves on a
  sender-leg dust reshuffle; sfAssetsTotal is unchanged because
  the underlying quantity on the custody line is unchanged.
- LoanPay: unconditional `associateAsset(*vaultSle, asset)`; the
  20-line docblock explaining the local skip is gone.
- VaultInvariant: sfAssetsTotal delta comparisons in the
  deposit / withdraw / clawback branches now use the extended
  delta `delta + dustDelta`. Pre-amendment dustDelta is always
  zero, so the check reduces to the classic form there.

Tests:

- New src/tests/libxrpl/protocol/STTakesAsset.cpp — 6 targeted
  gtest cases covering the sweep for (kSmdNeedsAsset-only,
  kSmdAssetPreLend11-only, both, neither) × (rules on, rules
  off, no rules installed).
- Existing Vault/Loan suites re-baselined to the dust-inclusive
  invariant via `readVaultDust()`; the shared VaultRounding_test
  fixtures now degrade cleanly to the classic RED contract on
  the base branch where readVaultDust() returns zero.
2026-08-14 04:50:37 +02:00
..