Replace v-model with :value + @input on the number input in LocalSwapWidget.
Vue 3's vModelText directive coerces <input type="number"> values to numbers
via looseToNumber(), causing swapAmount to become a JS number (e.g. 0.05) after
Playwright fill(). viem's parseEther() requires a string and throws when passed
a number, triggering the "Enter a valid ETH amount" error.
The fix mirrors FInput's explicit @input handler which always reads
event.target.value as a string, keeping swapAmount typed as string throughout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch from account 5 to account 0 (matches e2e tests)
- Use cheats page (/app/cheats) instead of get-krk (/app/get-krk) -
get-krk swap widget has v-model reactivity issue with Playwright fill()
- Match e2e/01 wallet connection pattern with mobile fallback
- Add debug screenshots for swap widget diagnosis
- Use getByLabel/getByRole selectors matching e2e patterns
- evaluate.sh: add --ignore-scripts to npm install (prevents husky from
writing to permanent repo .git/hooks from the ephemeral worktree)
- evaluate.sh: change --silent to --quiet (errors still printed on failure)
- evaluate.sh: add `npx playwright install chromium` step so browser
binaries are present even when the cached revision doesn't match ^1.55.1
- evaluate.sh: set CI=true inline on the playwright invocation so
forbidOnly activates and accidental test.only() causes a gate failure
- holdout.config.ts: document that CI=true is supplied by evaluate.sh
- always-leave.spec.ts: add waitForReceipt() helper; replace fixed
waitForTimeout(2000) after eth_sendTransaction with proper receipt
polling so tx confirmation is not a timing assumption
- always-leave.spec.ts: log the caught error in the button-cycling
try/catch so contract reverts surface in the output
- always-leave.spec.ts: add console.log when connect button or connector
panel is not found to make silent-skip cases diagnosable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace shell-script scenario runner with Playwright. The evaluator now
runs `npx playwright test --config scripts/harb-evaluator/holdout.config.ts`
after booting the stack, using the existing tests/setup/ wallet-provider
and navigation infrastructure.
Changes:
- scripts/harb-evaluator/holdout.config.ts — new Playwright config pointing
to scenarios/, headless chromium, 5-min timeout per test
- scripts/harb-evaluator/scenarios/sovereign-exit/always-leave.spec.ts —
Playwright spec that buys KRK through the LocalSwapWidget then sells it
back via the injected wallet provider, asserting sovereign exit works
- scripts/harb-evaluator/evaluate.sh — adds root npm install step (needed
for npx playwright), exports STACK_* env aliases for getStackConfig(),
replaces shell-script loop with a single playwright test invocation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- container_name(): derive separator from compose version (_COMPOSE_SEP),
so v1 (underscores) and v2 (hyphens) both resolve the right container name
- Drop buggy grep fallback for JSON branch extraction; python3 path is
sufficient and safe; grep cannot reliably target only head.ref in the
nested Gitea response
- Validate KRAIKEN/STAKE/LIQUIDITY_MANAGER after sourcing contracts.env to
catch renamed variables with a clear infra_error instead of a cryptic
'unbound variable' abort
- wait_exited: handle Docker 'dead' state alongside 'exited' to fail fast
instead of polling the full timeout
- Ponder /ready timeout is now infra_error (was a logged warning); scenarios
must not run against a partially-indexed chain
- Avoid double git fetch: only fetch the specific branch if the earlier
--prune fetch (fallback path) has not already retrieved all remote refs
- Use mktemp -u so git worktree add creates the directory itself, avoiding
failures on older git versions that reject a pre-existing target path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds scripts/harb-evaluator/evaluate.sh which:
- Accepts a PR number, resolves the branch via Codeberg API or git remote scan
- Checks out that branch into an isolated git worktree
- Boots a fresh docker compose stack with a unique COMPOSE_PROJECT name
- Waits for anvil healthy, bootstrap complete, ponder healthy + indexed
- Sources contract addresses from tmp/containers/contracts.env (never hardcoded)
- Exports EVAL_* env vars and runs any *.sh scripts under scenarios/
- Always tears down the stack and removes the worktree on exit (pass or fail)
- Returns 0 (gate passed), 1 (gate failed), or 2 (infra error)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace "Open Source." with "On-Chain." — the repo is private so "open
source" is a false claim per PRODUCT-TRUTH.md §Code/Open Source and
UX-DECISIONS.md §Don't Say. "On-Chain." is accurate and consistent with
the subtitle already present in the section.
Also remove duplicate garbled sentence in the Adaptive Trading card
("The optimizer evolves — new versions ship as the protocol matures."
was a copy-paste repeat of the preceding clause).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace vague "Open." with "Open Source." in the trust section heading
to give the claim concrete meaning and match the Source Code link below.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Initialize taxDue as ref<bigint>(0n) instead of ref<bigint>() so the
type is always bigint, eliminating the undefined in the Ref type and
making the bigint addition at line 219 type-safe without a null guard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add an explanatory comment to uniswapV3SwapCallback clarifying that
address(this) is pre-funded by _replaySwap before pool.swap() is
called, so no inline mint is required (unlike uniswapV3MintCallback).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove kraiken-lib/yarn.lock (npm is the sole package manager per CI and
build scripts), add packageManager field to kraiken-lib/package.json to
make the intent explicit, and add a single-package-manager CI step that
fails the build if yarn.lock reappears in kraiken-lib/.
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>
- Fix fee attribution: distribute fees only to positions whose tick range
contains the active tick at close time (in-range weight), not by raw
liquidity. FLOOR is priced far below current tick and rarely earns fees;
the old approach would over-credit it and corrupt capital-efficiency and
net-P&L numbers. Fallback to raw-liquidity weighting with a WARN log
when no position is in range.
- Warn on first-close skip: when _closePosition finds no open record
(first recenter, before any tracking), log [TRACKER][WARN] instead of
silently returning so the gap is visible in reports.
- Add tick range assertion: require() that the incoming close snapshot
tick range matches the stored open record — a mismatch would mean IL
is computed across different ranges (apples vs oranges).
- Fix finalBlock accuracy: logSummary now calls
tracker.logFinalSummary(tracker.lastNotifiedBlock()) instead of
lastRecenterBlock, so the summary reflects the actual last replay block
rather than potentially hundreds of blocks early.
- Initialize lastRecenterBlock = block.number in StrategyExecutor
constructor to defer the first recenter attempt by recenterInterval
blocks and document the invariant.
- Extract shared FormatLib: _str(uint256) and _istr(int256) were
copy-pasted in both PositionTracker and StrategyExecutor. Extracted to
FormatLib.sol internal library; both contracts now use `using FormatLib`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PositionTracker.sol: tracks position lifecycle (open/close per
recenter), records tick ranges, liquidity, entry/exit blocks/timestamps,
token amounts (via LiquidityAmounts math), fees (proportional to
liquidity share), IL (LP exit value − HODL value at exit price), and
net P&L per position. Aggregates total fees, cumulative IL, net P&L,
rebalance count, Anchor time-in-range, and capital efficiency accumulators.
Logs with [TRACKER][TYPE] prefix; emits cumulative P&L every 500 blocks.
- Modify StrategyExecutor.sol: add IUniswapV3Pool + token0isWeth to
constructor (creates PositionTracker internally), call
tracker.notifyBlock() on every block for time-in-range, and call
tracker.recordRecenter() on each successful recenter. logSummary()
now delegates to tracker.logFinalSummary().
- Modify BacktestRunner.s.sol: pass sp.pool and token0isWeth to
StrategyExecutor constructor; log tracker address.
- forge fmt: reformat all backtesting scripts and affected src/test files
to project style (number_underscore=thousands, multiline_func_header=all).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- LocalSwapWidget: move useWallet() to top-level <script setup> (was
incorrectly called inside async buyKrk() event handler)
- LocalSwapWidget + CheatsView: fix misleading toast — all transactions
are fully confirmed at that point, so say 'Swap complete' not 'Swap
submitted'
- LocalSwapWidget: add $KRK sigil to warning/hint text for consistency
with GetKrkView
- LocalSwapWidget: add comment on amountOutMinimum: 0n explaining it is
intentional for a no-MEV local anvil environment
- CheatsView: apply same useWallet() fix (pre-existing anti-pattern)
- docs/ENVIRONMENT.md: document VITE_ENABLE_LOCAL_SWAP and related
VITE_ variables in a new webapp env-var table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
woodpeckerci/plugin-git reads credentials via PLUGIN_NETRC_* env vars
(set from settings:), not CI_NETRC_* (set from environment:). The
previous fix in 57deaaa put the secret under environment:, so the
plugin never populated .netrc and git fell back to prompting, which
fails with GIT_TERMINAL_PROMPT=0.
Fix both ci.yml and e2e.yml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add BacktestKraiken.sol: extends MockToken with Kraiken-compatible interface
(dual mint overloads — public mint(address,uint256) for EventReplayer and
restricted mint(uint256) for LiquidityManager; peripheryContracts() stubs
staking pool as address(0))
- Add KrAIkenDeployer.sol: library deploying OptimizerV3Push3 + LiquidityManager
on the shadow pool, wiring BacktestKraiken permissions, setting fee destination,
and funding LM with configurable initial mock-WETH capital (default 10 ETH)
- Add StrategyExecutor.sol: time-based recenter trigger (configurable block
interval, default 100 blocks); logs block, pre/post positions (Floor/Anchor/
Discovery tick ranges + liquidity), fees collected, and revert reason on skip;
negligible-impact assumption documented as TODO(#319)
- Modify EventReplayer.sol: add overloaded replay() accepting an optional
StrategyExecutor hook; maybeRecenter() called after each block advancement
without halting replay on failure
- Modify BacktestRunner.s.sol: replace tokenA/B with MockWETH + BacktestKraiken,
integrate KrAIkenDeployer + StrategyExecutor into broadcast block; configurable
via RECENTER_INTERVAL and INITIAL_CAPITAL_WETH env vars; executor.logSummary()
printed after replay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Guard final drift sample with `idx % LOG_INTERVAL != 0` to prevent
double-counting stats when totalReplayed is an exact multiple of
LOG_INTERVAL (the loop's _logCheckpoint already fired for that state)
- Hoist pool.slot0() before the guard and pass finalSqrtPrice/finalTick
to _logSummary(), eliminating the redundant slot0 read inside it
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /:pathMatch(.*)* catch-all route that redirects to / so unknown
URLs no longer render blank
- Replace German inline comments in scrollBehavior with English equivalents
- Remove seven dead `// group: "navbar"` comments from /docs route and its
child routes (the live group: 'navbar' property on the parent is kept)
- HomeView.vue and HomeViewMixed.vue already carry the renamed
"Verified On-Chain" heading with supporting copy; no changes needed there
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>