Observe LendingProtocolV1_1: principal-only accounting and closed-ended vaults - #91
Open
manasip-prog wants to merge 5 commits into
Open
Observe LendingProtocolV1_1: principal-only accounting and closed-ended vaults#91manasip-prog wants to merge 5 commits into
manasip-prog wants to merge 5 commits into
Conversation
Track the four Vault/LoanBroker fields the amendment moves (AssetsTotal, AssetsAvailable, LossUnrealized, DebtTotal) and stamp Vault.LEVersion on any result touching a Vault node, since LEVersion -- not amendment activation -- gates which accounting model a Vault follows and both coexist post-activation.
…-65) LendingProtocolV1_1 adds VaultKind/SubscriptionDate/RedemptionDate to VaultCreate and an optional MemoData deletion reason to VaultDelete. The pinned xrpl-py has neither the model fields nor the codec definitions, so lending_v1_1_compat registers the field headers into the live binarycodec maps and subclasses both models. Length and range checks stay server-side so faulty handlers can still build the out-of-range cases. The amendment is latched off metadata, not config: a validated Vault's LEVersion is 1 only once LendingProtocolV1_1 is active, so the V1.1 fields join only after one has been seen. Pre-amendment they are temDISABLED, which never validates and would starve the failure bucket. VaultCreate now mints a minority of closed-ended vaults, so open-ended ones keep the phase-free deposit/withdraw valid paths stocked. Vault tracks the kind and both dates from the created node, and deposit/withdraw pick a vault whose current phase permits the transaction. Faulty vectors cover the sub-kMinInvestmentPeriod gap, already-expired dates, an out-of-enum VaultKind, and for VaultDelete an empty and an over-256-byte MemoData (validDataLength rejects both). Genesis was activating only Supported::Yes amendments, but Dockerfile.xrpld rewrites Supported::No to Yes before building, so LendingProtocolV1_1 was known to the binary yet inactive in the ledger. Genesis now includes those too, skipping VoteBehavior::Obsolete (enabling one amendment-blocks the node). Also scopes XRPLD_NO_PATCH_NIX_BINARY to the fuzzer's conan install, whose build folder lacks the loader script rippled's PatchNixBinary.cmake expects. RXT-832
Every XLS-65 path is gated on lending_v1_1_compat.enabled(), which latches off a validated Vault's LEVersion. If that never flips -- amendment inactive, or a genesis regression -- the whole feature goes dark while VaultCreate's success/failure dims stay satisfied off the open-ended vectors, so a run would report green having exercised none of it. Five sometimes buckets off tx_result's validated stream: lending_v1_1_active (the latch itself), vault_closed_ended_created (created node carries a nonzero VaultKind), vault_deposit_phase_blocked (tecEXPIRED) and vault_withdraw_phase_blocked (tecTOO_SOON) for the two phase gates, and vault_delete_reason_used (validated MemoData). All must_hit=False, matching conf_mpt_version_monotonic: they only fire against an xrpld with LendingProtocolV1_1 active, so a run without it must not starve. _fire_sometimes takes must_hit so the fire site can match its catalog entry. RXT-832
The XLS-0096 crypto step cloned xrpl-py at `confidential-mpt`, a branch that no longer exists on XRPLF/xrpl-py (no confidential-* ref remains). The clone fails under `set -e`, so `build workload image` aborted ~30s in and every Antithesis run since has never reached `launch experiment`. `pre-3.3-release-group` — already the pin for the core dependency in `pyproject.toml`, and the ref CLAUDE.md documents — carries the same `xrpl/ext/confidential` source at MPT_CRYPTO_VERSION 1.0.2, matching the rippled mpt-crypto pin. Using it for both means the proof bindings and the installed models come from one ref rather than two that can drift.
rippled develop renamed CamelCase namespaces to snake_case (XRPLF/rippled#7933): beast::IP -> beast::ip and xrpl::BuildInfo -> xrpl::build_info. rippled-fuzzer (all branches) still uses the old spelling in four call sites, so building the fuzzer fails against develop and takes the whole `build xrpld` stage with it. Rewrite the fuzzer's references in the image, gated on the cloned xrpld actually declaring the new namespaces, so pre-rename refs (e.g. xrpld-private staging/3.3.x-private) build unchanged. The includes keep the BuildInfo.h filename, which the substitutions leave alone. develop is the only ref carrying Lending v1.1 (closed-ended vaults landed Aug 12, after the Aug 4 rename), so there is no commit with both the v1.1 fields and the old namespaces to pin instead.
manasip-prog
marked this pull request as ready for review
September 2, 2026 17:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits, both under the
LendingProtocolV1_1amendment.Principal-only accounting (XLS-66, rippled PR #582)
The amendment moves
Vault.AssetsTotalfrom accrual- to cash-basis: interest no longer counts until it's paid. Legacy and amended vaults coexist forever (a pre-amendment vault never migrates), so the balance rows inworkload::resultwere unattributable without knowing which basis produced them.tx_resultnow carriesvault_le_version(Vault.LEVersion, XLS-65 §3.1.2.2) on any result touching aVaultnode, and thebalance_changeslist tracks the vault'sAssetsTotal/AssetsAvailable/LossUnrealizedplus the broker'sDebtTotal.Closed-ended vaults + VaultDelete deletion reason (XLS-65)
VaultCreategainsVaultKind/SubscriptionDate/RedemptionDate;VaultDeletegains an optionalMemoDatadeletion reason. The pinned xrpl-py has neither the model fields nor the codec definitions, solending_v1_1_compat.pyregisters the field headers into the live binarycodec maps and subclasses both models. Validation stays server-side so faulty handlers can still build the out-of-range cases.The amendment is latched off metadata, not config: a validated
Vault'sLEVersionis1only once the amendment is active, so the V1.1 fields join only after one has been seen. Pre-amendment they'retemDISABLED— never validates, would starve the failure bucket.A minority of vaults are closed-ended, so open-ended ones keep the phase-free deposit/withdraw valid paths stocked.
Vaulttracks the kind and both dates from the created node, and deposit/withdraw pick a vault whose current phase (Subscription / Investment / Redemption) permits the transaction. Date generation has two flavors: a long subscription window keeps a vault depositable for the whole run, a short one walks it through all three phases so the gates actually fire.Faulty vectors: sub-
kMinInvestmentPeriodgap (temMALFORMED), already-expired dates (tecEXPIRED— a tec, so it validates and feeds the failure bucket), out-of-enumVaultKind, and forVaultDeletean empty and an over-256-byteMemoData(validDataLengthrejects both).Genesis fix
Genesis was activating only
Supported::Yesamendments, butDockerfile.xrpldrewritesSupported::NotoYesbefore building — soLendingProtocolV1_1was known to the binary yet inactive in the ledger, and every V1.1 field came backtemDISABLED. Genesis now includes those too, skippingVoteBehavior::Obsolete(enabling one amendment-blocks the node).Also scopes
XRPLD_NO_PATCH_NIX_BINARYto the fuzzer'sconan install, whose build folder lacks the loader script rippled'sPatchNixBinary.cmakeexpects.Follow-up
xrpl-py PR #1034 lands all of this upstream with matching field codes, so the shim's
_register_fieldguard will stand down cleanly. It's targetingmainrather than thepre-3.3-release-groupbranch we pin, and it adds client-side validation that would reject the deliberately-malformed vectors at construction — those move tosubmit_rawas part of the swap. Tracked separately.Checks
check-imports,check-endpoints,check-fuzz-coverage,check-modifier-coverage,check-assembler-roundtrip, ruff, ruff format, basedpyright all pass. The two mypyno-any-returnhits are pre-existing and untouched by this branch.RXT-832
Pull Request opened by Augment Code with guidance from the PR author