Problem
The lending contract implements a proper 2-step governance timelock for interest-rate risk parameters: queue_set_reserve_params → wait out the unlock delay → apply_queued_reserve_params (or cancel_queued_reserve_params before it unlocks). The frontend only wires the first step:
InterestRateParamsForm.tsx (apps/web-app/src/features/admin/components/) only calls lendingService.setInterestRateParams(), which wraps queue_set_reserve_params.
apply_queued_reserve_params and cancel_queued_reserve_params are exposed on the generated contract client (packages/contracts/lending/src/index.ts) but are never called anywhere in the frontend.
- There is no getter for
QueuedReserveConfig { new_params, unlock_time } in the binding, and no UI surfaces whether a change is pending, when it unlocks, or lets an admin apply/cancel it.
Why this needs real judgment, not a quick patch
Once an admin queues a reserve-param change today, it is effectively stuck — there's no way to see it, wait it out, apply it, or cancel it from the app. Fixing this requires:
- Deciding how to reconstruct pending-queue state given there's no direct getter — most plausibly by querying Soroban contract events by topic, mirroring the existing pattern in
getActiveBadDebtAuctions() (apps/web-app/src/lib/helpers/stellar/lending.ts), or by reading contract instance/temporary storage directly.
- Building unlock-time countdown + apply/cancel controls per pool/asset, analogous to the already-working backstop withdrawal-queue flow in
apps/web-app/src/features/backstop/hooks/useBackstop.ts (a genuinely similar "queue then execute after a delay" UX, worth using as a pattern reference — not a template to copy verbatim since the domain differs).
- Handling the case where the calling admin isn't the one who queued the change, and where a queued change has already unlocked vs. is still pending.
Scope
apps/web-app/src/features/admin/components/InterestRateParamsForm.tsx (add pending-queue table + apply/cancel controls)
- A new hook, e.g.
useQueuedReserveParams
apps/web-app/src/lib/services/lending.service.ts (add applyQueuedReserveParams/cancelQueuedReserveParams wrappers)
- Possibly a small addition to
apps/web-app/src/lib/helpers/stellar/lending.ts for event querying
Acceptance criteria
This is cross-cutting architectural work (missing half of a contract's governance flow, requiring new state-reconstruction logic) — evaluated per the project's PR rubric as HARD complexity.
Problem
The lending contract implements a proper 2-step governance timelock for interest-rate risk parameters:
queue_set_reserve_params→ wait out the unlock delay →apply_queued_reserve_params(orcancel_queued_reserve_paramsbefore it unlocks). The frontend only wires the first step:InterestRateParamsForm.tsx(apps/web-app/src/features/admin/components/) only callslendingService.setInterestRateParams(), which wrapsqueue_set_reserve_params.apply_queued_reserve_paramsandcancel_queued_reserve_paramsare exposed on the generated contract client (packages/contracts/lending/src/index.ts) but are never called anywhere in the frontend.QueuedReserveConfig { new_params, unlock_time }in the binding, and no UI surfaces whether a change is pending, when it unlocks, or lets an admin apply/cancel it.Why this needs real judgment, not a quick patch
Once an admin queues a reserve-param change today, it is effectively stuck — there's no way to see it, wait it out, apply it, or cancel it from the app. Fixing this requires:
getActiveBadDebtAuctions()(apps/web-app/src/lib/helpers/stellar/lending.ts), or by reading contract instance/temporary storage directly.apps/web-app/src/features/backstop/hooks/useBackstop.ts(a genuinely similar "queue then execute after a delay" UX, worth using as a pattern reference — not a template to copy verbatim since the domain differs).Scope
apps/web-app/src/features/admin/components/InterestRateParamsForm.tsx(add pending-queue table + apply/cancel controls)useQueuedReserveParamsapps/web-app/src/lib/services/lending.service.ts(addapplyQueuedReserveParams/cancelQueuedReserveParamswrappers)apps/web-app/src/lib/helpers/stellar/lending.tsfor event queryingAcceptance criteria
setInterestRateParams) flowThis is cross-cutting architectural work (missing half of a contract's governance flow, requiring new state-reconstruction logic) — evaluated per the project's PR rubric as HARD complexity.