You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As described in the related issue about the missing Boost UI, SorobanService.setBoost and useSetBoost are fully implemented but have no test coverage anywhere in the repo (a search of all *.test.ts/*.test.tsx files turns up zero references to setBoost, useSetBoost, openBoost, or BoostConfig), and no UI component consumes them at all yet. This is a distinct, standalone testing gap from the UI-implementation gap: even the already-written setBoost contract-interaction code (allocation-percentage validation, validateSimulationAuth security check for the set_boost function, fee-bump handling) has never been exercised by a single test, unlike its siblings lockAssets/unlockAssets, which have dedicated coverage (soroban.test.ts, soroban.partial-unlock.test.ts, soroban.feebump.test.ts).
Acceptance Criteria
Add unit tests for SorobanService.setBoost covering: valid allocation (0-100), out-of-range allocation rejection, simulation failure, validateSimulationAuth rejecting a mismatched auth entry for set_boost, and fee-bump sponsorship, mirroring the structure of soroban.feebump.test.ts/soroban.partial-unlock.test.ts.
Add tests for useSetBoost's mutation success/error toast behavior and cache invalidation, mirroring useLockAssets/useUnlockAssets hook test patterns if any exist, or establishing the pattern if not.
Once the BoostModal UI exists (see the companion issue), add component tests for its validation and step-machine states following UnlockModal's test coverage as a template.
Ensure new tests run under the existing vitest run script with no additional configuration required.
Relevant Files
src/lib/soroban.ts — SorobanService.setBoost (~L1159) has zero test coverage
src/hooks/useSorobanQuery.ts — useSetBoost (~L255) has zero test coverage
src/lib/soroban.feebump.test.ts — the closest existing test pattern (fee-bump path) new boost tests should follow
Further Investigation
Confirmed: the UI genuinely does not exist, and its interaction model is unspecified anywhere
A repo-wide search (find src -iname "*boost*") turns up zero BoostModal, BoostConfig component, or any file whose name references boost UI. The only front-end trace of "boost" is:
src/app/farm/EarningRow.tsx L145-158 — a permanently-disabled Button with no onClick at all:
There is no handler wired to open a modal — this is dead markup, not a stubbed-out entry point.
src/store/farmStore.ts L5-39 — FarmModal already has a "boost" variant and openBoost(position) action fully implemented in the zustand store, exactly mirroring openUnlock/openDeposit. So the state plumbing for a boost modal exists and works, but nothing calls openBoost, and nothing renders when activeModal === "boost" (compare to how activeModal === "unlock" presumably renders <UnlockModal> somewhere in farm/page.tsx — worth double-checking that render-switch during implementation, since it may need a new case/conditional branch added).
src/lib/soroban.ts L1159-1230 (SorobanService.setBoost) and src/hooks/useSorobanQuery.ts L255-297 (useSetBoost) are fully implemented and functionally complete: allocation-percentage bounds validation (allocationPercentage < 0 || > 100, soroban.ts L1166-1171), validateSimulationAuth check scoped to the set_boost function (L1198-1203), fee-bump-compatible transaction flow, and success/error toasts with cache invalidation for USER_POSITION/USER_CREDITS in the mutation's onSuccess (useSorobanQuery.ts ~L271-286). None of this is in question — the data layer is done and correct-looking.
What's genuinely undetermined, and why this warrants spike rather than a straightforward "write the missing test" task:
Input model: is boost allocation set via a slider (0-100%), a numeric input, preset buttons (25/50/75/100%), or something else? setBoost's signature (allocationPercentage: number) doesn't constrain the UI — any of these are valid callers.
Relationship to existing modals: should BoostModal follow UnlockModal's step-machine pattern (confirm → sign → pending → success, see src/components/UnlockModal/UnlockModal.tsx) or is boost config simple enough for a single-step form? UnlockModal also does partial-unlock preview math (computePartialUnlockPreview, tested in soroban.partial-unlock.test.ts) — does boost need an analogous "preview effect of this allocation on my daily rate" calculation, or is it a blind percentage-in/percentage-out?
What does "boost" even do to the user's position? The store/service layer names it but nothing in the reachable UI explains the feature's effect (no tooltip, no copy, no docs found in a repo-wide grep for "boost" outside code). Writing a meaningful component test requires first deciding what the component should communicate and validate — that's a product/design decision, not just an engineering one, which is the hallmark of a spike per this batch's triage criteria.
Approach A — Minimal modal, mirror UnlockModal's skeleton exactly. Copy UnlockModal's structure (Chakra Modal, step state, isNetworkMismatch gating, toast wiring already present in useSetBoost) and reduce the form to a single percentage input/slider with client-side 0-100 validation matching setBoost's own bounds check. Fastest to ship, lowest design risk, but risks being product-wrong if "boost" allocation actually needs preview/impact math the team hasn't specified (see point 2 above) — could require a follow-up rework once real requirements surface.
Approach B — Spike first: write a short design note capturing the intended UX (input type, preview math if any, copy/tooltip explaining what boost does, relationship to boostUnavailable), get it reviewed/approved, then implement BoostModal + tests together. Slower to first PR, but avoids building the wrong thing twice. Given openBoost/FarmModal were clearly scaffolded in anticipation of this UI (farmStore.ts already has the "boost" variant sitting unused), it's likely someone already had an intended design that never got written down or got dropped — worth checking with the repo owner / issue #81 before assuming from scratch.
Approach C — Treat this purely as a testing issue and defer the UI entirely to #81. Write the SorobanService.setBoost/useSetBoost unit tests now (these have zero ambiguity — the contract is fully specified by existing code), and leave the BoostModal component-test AC as blocked/deferred until #81 lands. This decouples the "well-specified, low-risk" test-writing work (service + hook layer) from the "needs design decisions" work (component), letting a contributor claim partial value now instead of blocking on a UX decision.
Recommendation: do the SorobanService.setBoost/useSetBoost tests immediately (well-specified, see below) and treat the BoostModal component itself as the actual spike, tracked jointly with #81.
Testing strategy for the parts that ARE well-specified today
New test file src/lib/soroban.setboost.test.ts, mirroring src/lib/soroban.feebump.test.ts's structure (describe/it blocks, vi.mock for the RPC server per that file's existing pattern) and soroban.partial-unlock.test.ts for pure-function-style assertions where applicable.
Cases to cover for SorobanService.setBoost (soroban.ts L1159-1230): valid allocation (e.g. 50) happy path through simulate→sign→submit; allocation -1 and 101 rejected before any RPC call (assert rpcServer.simulateTransaction/getAccount were never called — this exercises the early-return at L1167-1172); simulation returning { error } (L1188-1193); validateSimulationAuth throwing SecurityError for a mismatched set_boost auth entry (mirror however soroban.test.ts tests this for lockAssets/unlockAssets); and submissionResult.status === 'ERROR' (L1219-1224).
For useSetBoost (useSorobanQuery.ts ~L255-297): assert mutationFn throws 'Wallet not connected' when walletApi/publicKey are absent; assert onSuccess toast fires with the correct allocation percentage in its description and that invalidateQueries is called with [QUERY_KEYS.USER_POSITION, poolId] and [QUERY_KEYS.USER_CREDITS, poolId]; assert onError toast fires on a rejected mutation. Check whether any existing hook test (useSorobanQuery.test.ts if present) already establishes a wrapper/renderHook pattern for mutations to reuse rather than inventing a new one.
Defer BoostModal component tests (the UnlockModal-template AC) until the UI itself is designed and built — attempting to write these tests first, without a settled interaction model, would produce tests that lock in an arbitrary/wrong UI and need to be rewritten anyway.
Cross-reference
Directly duplicative scope with #81 ("Boost allocation is fully wired in the data layer but has no UI — the Boost button is permanently disabled dead code"), which is the implementation-side issue for the exact same gap described here. These two issues should be assigned/worked together — #81 for the UI decision, this issue for the tests that follow it — rather than independently, to avoid one PR reinventing what the other already decided.
Problem
As described in the related issue about the missing Boost UI,
SorobanService.setBoostanduseSetBoostare fully implemented but have no test coverage anywhere in the repo (a search of all*.test.ts/*.test.tsxfiles turns up zero references tosetBoost,useSetBoost,openBoost, orBoostConfig), and no UI component consumes them at all yet. This is a distinct, standalone testing gap from the UI-implementation gap: even the already-writtensetBoostcontract-interaction code (allocation-percentage validation,validateSimulationAuthsecurity check for theset_boostfunction, fee-bump handling) has never been exercised by a single test, unlike its siblingslockAssets/unlockAssets, which have dedicated coverage (soroban.test.ts,soroban.partial-unlock.test.ts,soroban.feebump.test.ts).Acceptance Criteria
SorobanService.setBoostcovering: valid allocation (0-100), out-of-range allocation rejection, simulation failure,validateSimulationAuthrejecting a mismatched auth entry forset_boost, and fee-bump sponsorship, mirroring the structure ofsoroban.feebump.test.ts/soroban.partial-unlock.test.ts.useSetBoost's mutation success/error toast behavior and cache invalidation, mirroringuseLockAssets/useUnlockAssetshook test patterns if any exist, or establishing the pattern if not.BoostModalUI exists (see the companion issue), add component tests for its validation and step-machine states followingUnlockModal's test coverage as a template.vitest runscript with no additional configuration required.Relevant Files
src/lib/soroban.ts— SorobanService.setBoost (~L1159) has zero test coveragesrc/hooks/useSorobanQuery.ts— useSetBoost (~L255) has zero test coveragesrc/lib/soroban.feebump.test.ts— the closest existing test pattern (fee-bump path) new boost tests should followFurther Investigation
Confirmed: the UI genuinely does not exist, and its interaction model is unspecified anywhere
A repo-wide search (
find src -iname "*boost*") turns up zeroBoostModal,BoostConfigcomponent, or any file whose name references boost UI. The only front-end trace of "boost" is:src/app/farm/EarningRow.tsxL145-158 — a permanently-disabledButtonwith noonClickat all:src/store/farmStore.tsL5-39 —FarmModalalready has a"boost"variant andopenBoost(position)action fully implemented in the zustand store, exactly mirroringopenUnlock/openDeposit. So the state plumbing for a boost modal exists and works, but nothing callsopenBoost, and nothing renders whenactiveModal === "boost"(compare to howactiveModal === "unlock"presumably renders<UnlockModal>somewhere infarm/page.tsx— worth double-checking that render-switch during implementation, since it may need a newcase/conditional branch added).src/lib/soroban.tsL1159-1230 (SorobanService.setBoost) andsrc/hooks/useSorobanQuery.tsL255-297 (useSetBoost) are fully implemented and functionally complete: allocation-percentage bounds validation (allocationPercentage < 0 || > 100, soroban.ts L1166-1171),validateSimulationAuthcheck scoped to theset_boostfunction (L1198-1203), fee-bump-compatible transaction flow, and success/error toasts with cache invalidation forUSER_POSITION/USER_CREDITSin the mutation'sonSuccess(useSorobanQuery.ts ~L271-286). None of this is in question — the data layer is done and correct-looking.What's genuinely undetermined, and why this warrants
spikerather than a straightforward "write the missing test" task:setBoost's signature (allocationPercentage: number) doesn't constrain the UI — any of these are valid callers.BoostModalfollowUnlockModal's step-machine pattern (confirm → sign → pending → success, seesrc/components/UnlockModal/UnlockModal.tsx) or is boost config simple enough for a single-step form?UnlockModalalso does partial-unlock preview math (computePartialUnlockPreview, tested insoroban.partial-unlock.test.ts) — does boost need an analogous "preview effect of this allocation on my daily rate" calculation, or is it a blind percentage-in/percentage-out?boostUnavailable(referenced at EarningRow.tsx L151 alongsideisNetworkMismatch) — trace where this flag is computed and what conditions gate it; the eventual modal will need to respect the same gating and probably surface why boost is unavailable (e.g. position too new, already at max allocation) rather than a silently-disabled button, which is the same UX anti-pattern issue UnlockModal's autofocus uses a fragile document-wide querySelector instead of a ref, with no ARIA-live status region #85 (UnlockModal's ARIA gap) and Leaderboard's "You are rank X" banner only checks the currently-fetched page, not the user's true global rank #78 (leaderboard rank ambiguity) flag elsewhere in this batch — worth a consistent fix, not a one-off.Two viable approaches, with tradeoffs
Approach A — Minimal modal, mirror
UnlockModal's skeleton exactly. CopyUnlockModal's structure (ChakraModal, step state,isNetworkMismatchgating, toast wiring already present inuseSetBoost) and reduce the form to a single percentage input/slider with client-side 0-100 validation matchingsetBoost's own bounds check. Fastest to ship, lowest design risk, but risks being product-wrong if "boost" allocation actually needs preview/impact math the team hasn't specified (see point 2 above) — could require a follow-up rework once real requirements surface.Approach B — Spike first: write a short design note capturing the intended UX (input type, preview math if any, copy/tooltip explaining what boost does, relationship to
boostUnavailable), get it reviewed/approved, then implementBoostModal+ tests together. Slower to first PR, but avoids building the wrong thing twice. GivenopenBoost/FarmModalwere clearly scaffolded in anticipation of this UI (farmStore.ts already has the "boost" variant sitting unused), it's likely someone already had an intended design that never got written down or got dropped — worth checking with the repo owner / issue #81 before assuming from scratch.Approach C — Treat this purely as a testing issue and defer the UI entirely to #81. Write the
SorobanService.setBoost/useSetBoostunit tests now (these have zero ambiguity — the contract is fully specified by existing code), and leave theBoostModalcomponent-test AC as blocked/deferred until #81 lands. This decouples the "well-specified, low-risk" test-writing work (service + hook layer) from the "needs design decisions" work (component), letting a contributor claim partial value now instead of blocking on a UX decision.Recommendation: do the
SorobanService.setBoost/useSetBoosttests immediately (well-specified, see below) and treat theBoostModalcomponent itself as the actual spike, tracked jointly with #81.Testing strategy for the parts that ARE well-specified today
src/lib/soroban.setboost.test.ts, mirroringsrc/lib/soroban.feebump.test.ts's structure (describe/itblocks,vi.mockfor the RPC server per that file's existing pattern) andsoroban.partial-unlock.test.tsfor pure-function-style assertions where applicable.SorobanService.setBoost(soroban.ts L1159-1230): valid allocation (e.g. 50) happy path through simulate→sign→submit; allocation-1and101rejected before any RPC call (assertrpcServer.simulateTransaction/getAccountwere never called — this exercises the early-return at L1167-1172); simulation returning{ error }(L1188-1193);validateSimulationAuththrowingSecurityErrorfor a mismatchedset_boostauth entry (mirror howeversoroban.test.tstests this forlockAssets/unlockAssets); andsubmissionResult.status === 'ERROR'(L1219-1224).useSetBoost(useSorobanQuery.ts ~L255-297): assertmutationFnthrows'Wallet not connected'whenwalletApi/publicKeyare absent; assertonSuccesstoast fires with the correct allocation percentage in its description and thatinvalidateQueriesis called with[QUERY_KEYS.USER_POSITION, poolId]and[QUERY_KEYS.USER_CREDITS, poolId]; assertonErrortoast fires on a rejected mutation. Check whether any existing hook test (useSorobanQuery.test.tsif present) already establishes a wrapper/renderHookpattern for mutations to reuse rather than inventing a new one.BoostModalcomponent tests (theUnlockModal-template AC) until the UI itself is designed and built — attempting to write these tests first, without a settled interaction model, would produce tests that lock in an arbitrary/wrong UI and need to be rewritten anyway.Cross-reference
Directly duplicative scope with #81 ("Boost allocation is fully wired in the data layer but has no UI — the Boost button is permanently disabled dead code"), which is the implementation-side issue for the exact same gap described here. These two issues should be assigned/worked together — #81 for the UI decision, this issue for the tests that follow it — rather than independently, to avoid one PR reinventing what the other already decided.