Skip to content

Seed closed-ended vaults for setup's loan brokers - #97

Closed
manasip-prog wants to merge 6 commits into
mainfrom
manasip/setup-closed-ended-broker-vault
Closed

manasip-prog wants to merge 6 commits into
mainfrom
manasip/setup-closed-ended-broker-vault

Conversation

@manasip-prog

Copy link
Copy Markdown
Collaborator

Stacked on #91. Setup currently creates only open-ended vaults, so on 3.4.x every LoanBrokerSet is rejected and the run aborts before it starts:

workload::setup_incomplete  {expected: 4, got: 0, phase: loan_brokers}

3.4.x's LoanBrokerSet::preclaim returns tecNO_PERMISSION for a broker on an open-ended vault once featureLendingProtocolV1_1 is active, which the genesis rewrite always enables.

The window is constrained from both sides: VaultDeposit only succeeds in Subscription, and 3.4.x's LoanSet returns tecTOO_SOON in Subscription and tecEXPIRED in Redemption — so a loan can only be created during Investment. Setup therefore has to cross the boundary, with deposits in phase 7b and loans in phase 13.

  • params.setup_broker_vault_dates() — subscription closes 120s out, redemption 26h beyond that. The intervening phases (8–12 plus cover_deposits) supply the elapsed time, so no artificial wait is needed. Redemption is deliberately past any run length so StartDate + interval × total + kLoanRedemptionBuffer clears it for loans created at any point. closed_ended_dates() is unusable here — it is tuned to make driver vaults transition phases quickly.
  • The vaults phase is split: IOU/MPT vaults first, because a validated Vault's LEVersion is what latches lending_v1_1_compat.enabled(), and _run_phase polls until the state updater has fired. The four XRP broker vaults are then created closed-ended in 7a.
  • The broker phase filters for closed-ended vaults when the amendment is active.

With the amendment inactive — 3.3.x — enabled() is false, no V1.1 fields are sent and the filter is skipped, so behaviour is unchanged.

This clears the loan_brokers abort. It does not claim to clear the whole chain: 3.4.x carries ~690 lines of V1.1 changes across 12 lending and vault transactors, and _run_phase is fail-loud, so any further incompatibility surfaces as the next phase to abort.

🤖 Generated with Claude Code

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
Base automatically changed from manasip/lending-v1_1-accounting to main September 8, 2026 19:01
@manasip-prog

Copy link
Copy Markdown
Collaborator Author

Closing in favour of a cleaner branch. This one also picked up 3200 lines of unrelated local files via git add -A. The approach in it was weaker anyway: it relied on the intervening setup phases to push the vault out of Subscription rather than waiting on the subscription date explicitly, and it did not touch lending.py, where LoanSet's V1.1 phase and redemption-buffer constraints also need handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant