Replace screen.width with window.innerWidth in useMobile composable.
screen.width reports the physical screen size (0 in headless Chromium),
while window.innerWidth reflects the actual viewport — the correct metric
for responsive layout. The previous Object.defineProperty workaround in
wallet-provider.ts could not override the native Screen.prototype getter,
so screen.width remained 0, isMobile stayed true, and ConnectButton was
never rendered. Fix wallet-provider.ts to pass viewport/screen options
directly to browser.newContext() and remove the broken init-script shim.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract shared Uniswap ABIs (WETH_ABI, SWAP_ROUTER_ABI, UNISWAP_FACTORY_ABI,
UNISWAP_POOL_ABI), utility functions (isRecord, coerceString, getErrorMessage,
ensureAddress), and the wrap→approve→exactInputSingle flow into a new composable
useSwapKrk(). Both LocalSwapWidget and CheatsView now delegate to this single
source of truth, so swap logic changes only need to be made in one place.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- landing/eslint.config.js: ban imports from web-app paths (rule 1),
direct RPC clients from viem/@wagmi/vue (rule 2), and axios (rule 4)
- web-app/eslint.config.js: ban string interpolation inside GraphQL
query/mutation property values (rule 3); fixes 4 pre-existing violations
in usePositionDashboard, usePositions, useSnatchNotifications,
useWalletDashboard by migrating to variables: {} pattern
- services/ponder/eslint.config.js: ban findMany() calls that lack a
limit parameter to prevent unbounded indexed-data growth (rule 5)
All error messages follow the [what is wrong][rule][how to fix][where to
read more] template so agents and humans fix on the first try.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract relativeTime and formatTokenAmount to helper.ts, eliminating
duplicated logic between CollapseHistory and NotificationBell
- Use formatUnits (via formatTokenAmount) instead of Number(BigInt)/1e18
to avoid precision loss on large token amounts
- Fix allRecentSnatches emptying after mark-seen: now runs two parallel
queries — one filtered by lastSeen timestamp (unseen badge count) and
one unfiltered (panel history), so history is preserved after opening
- Remove dead no-op watch block from useSnatchNotifications
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- add a useSnatchSelection composable that centralises snatch shortfall calculations, position filtering, and RPC memoisation
- refactor StakeHolder.vue to consume the composable instead of reimplementing the flow inline
- introduce Vitest config and first composable tests (useSnatchSelection.spec.ts) to cover empty/partial fills and ownership edge cases
- wire up project tooling updates so the new tests run (jsdom dep, updated package metadata)
## Testing
- cd web-app && npm install
- npm test
resolves#24
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/harb/pulls/30