WarBow: indexer refresh candidates + protocol page refresh button (EcoStrategy M-04) #160

Closed
opened 2026-05-05 08:52:56 +00:00 by PlasticDigits · 18 comments
PlasticDigits commented 2026-05-05 08:52:56 +00:00 (Migrated from gitlab.com)

Context

EcoStrategy audit M-04: finalizeWarbowPodium(candidates) needs a complete superset; refreshWarbowPodium(candidates) is permissionless but require(!ended) (GitLab #149) blocks post-end refresh.

Ask: allow anyone to call refreshWarbowPodium any time; indexer feeds candidates; /timecurve/protocol button loads candidates and submits the tx.

Design / conflict

GitLab #149 prevents post-end permissionless refresh from unlatching owner finalize. Implementation must not regress #129 / #133 / #149 invariants.

Resolution options (pick in MR):

  • A: Indexer + protocol button for sale-live refresh only; post-end remains owner finalizeWarbowPodium only.
  • B: Contract change: allow refreshWarbowPodium after ended only if !warbowPodiumFinalized and/or before distributePrizes—requires state-machine review + Forge.

Indexer

New or extended route, e.g. GET /v1/timecurve/warbow/refresh-candidates → address[] (deduped), derived from WarBow events + BP mutators + current podium hints; document max length / pagination.

Frontend

frontend/src/pages/TimeCurveProtocolPage.tsx: button Load candidates → Refresh WarBow podium calling refreshWarbowPodium(candidates).

Reuse patterns from timeCurveWarbowSnapshotClaim.ts / arena model where appropriate.

Acceptance criteria

  • Documented live vs ended behavior; no grief of distributePrizes latch.
  • Indexer schema stable + versioned if needed.
  • Protocol page works with indexer (manual QA).

References

  • contracts/src/TimeCurve.sol — refreshWarbowPodium, finalizeWarbowPodium
  • Audit audits/audit_ecostrategy_1777969776.md — M-04
## Context EcoStrategy audit **M-04**: `finalizeWarbowPodium(candidates)` needs a complete superset; `refreshWarbowPodium(candidates)` is permissionless but **`require(!ended)`** (GitLab #149) blocks post-end refresh. **Ask:** allow **anyone** to call `refreshWarbowPodium` **any time**; **indexer** feeds **candidates**; **`/timecurve/protocol`** button loads candidates and submits the tx. ## Design / conflict GitLab #149 prevents post-end permissionless refresh from unlatching owner finalize. **Implementation must not regress** #129 / #133 / #149 invariants. Resolution options (pick in MR): - **A:** Indexer + protocol button for **sale-live** refresh only; post-end remains owner `finalizeWarbowPodium` only. - **B:** Contract change: allow `refreshWarbowPodium` after `ended` only if `!warbowPodiumFinalized` and/or before `distributePrizes`—requires state-machine review + Forge. ## Indexer New or extended route, e.g. `GET /v1/timecurve/warbow/refresh-candidates` → `address[]` (deduped), derived from WarBow events + BP mutators + current podium hints; document max length / pagination. ## Frontend `frontend/src/pages/TimeCurveProtocolPage.tsx`: button **Load candidates** → **Refresh WarBow podium** calling `refreshWarbowPodium(candidates)`. Reuse patterns from `timeCurveWarbowSnapshotClaim.ts` / arena model where appropriate. ## Acceptance criteria - [ ] Documented live vs ended behavior; no grief of `distributePrizes` latch. - [ ] Indexer schema stable + versioned if needed. - [ ] Protocol page works with indexer (manual QA). ## References - `contracts/src/TimeCurve.sol` — `refreshWarbowPodium`, `finalizeWarbowPodium` - Audit `audits/audit_ecostrategy_1777969776.md` — **M-04**
PlasticDigits commented 2026-05-05 10:07:43 +00:00 (Migrated from gitlab.com)

mentioned in commit 4ebbdb9086

mentioned in commit 4ebbdb908673023a4783b6555a96d0c8047f1c57
PlasticDigits commented 2026-05-05 10:07:43 +00:00 (Migrated from gitlab.com)

mentioned in commit a6482837c9

mentioned in commit a6482837c933efdf45a6e15883ac2a45a0c6ec2e
PlasticDigits commented 2026-05-05 10:08:07 +00:00 (Migrated from gitlab.com)

Implemented (#160 / EcoStrategy M-04 — Option A)

Merged to main (4ebbdb9): sale-live indexer-assisted refreshWarbowPodium candidates only — no contract change; post-end behavior unchanged (refreshWarbowPodium reverts when ended per #149); operators still use owner finalizeWarbowPodium before distributePrizes when required.

What changed

  • Indexer GET /v1/timecurve/warbow/refresh-candidates (schema 1.15.0): deduped addresses from WarBow idx_* tables + buyers with battle_points_after > 0, prepends head WarBow podium(3) hints when chain_timer has a snapshot; limit (1–500, default 200), offset, total, next_offset, distinct_sql_cap_hit, podium_warbow_hint_count.
  • Frontend /timecurve/protocol: Load candidates from indexer → merge with connected wallet + onchain warbowLadderPodium via existing warBowRefreshCandidateAddresses, then Refresh WarBow podium (wrong-chain barrier + sale-ended guard).
  • Docs / invariants: INV-INDEXER-160-WARBOW-REFRESH-CANDIDATES, manual QA, indexer design, timecurve-views, play skill + skills/README.md, guardrails cross-link.

Verification checklist for @brouie

  • Indexer serves route: curl -sS "$INDEXER/v1/timecurve/warbow/refresh-candidates?limit=10" | jq .candidates,.total,.note
  • Response header x-schema-version: 1.15.0 on indexer routes.
  • With sale live: protocol panel loads candidates (VITE_INDEXER_URL set) and an EOA can submit refreshWarbowPodium; warbowPodiumFinalized may flip false until owner re-finalizes (expected #129 behavior).
  • With sale ended: same tx path reverts onchain; UI disables refresh and points to finalizeWarbowPodium (#149).
  • cargo clippy --all-targets -- -D warnings + indexer tests; frontend tsc -b / Vitest green on CI.

Issue left open for your sign-off.

## Implemented (#160 / EcoStrategy M-04 — Option A) Merged to `main` ([`4ebbdb9`](https://gitlab.com/PlasticDigits/yieldomega/-/commit/4ebbdb9)): sale-live **indexer-assisted** `refreshWarbowPodium` candidates only — **no** contract change; post-end behavior unchanged (**`refreshWarbowPodium` reverts when `ended`** per #149); operators still use owner `finalizeWarbowPodium` before `distributePrizes` when required. ### What changed - **Indexer** `GET /v1/timecurve/warbow/refresh-candidates` (schema **1.15.0**): deduped addresses from WarBow `idx_*` tables + buyers with `battle_points_after > 0`, prepends head **WarBow** `podium(3)` hints when `chain_timer` has a snapshot; `limit` (1–500, default 200), `offset`, `total`, `next_offset`, `distinct_sql_cap_hit`, `podium_warbow_hint_count`. - **Frontend** `/timecurve/protocol`: **Load candidates from indexer** → merge with connected wallet + onchain `warbowLadderPodium` via existing `warBowRefreshCandidateAddresses`, then **Refresh WarBow podium** (wrong-chain barrier + sale-ended guard). - **Docs / invariants:** `INV-INDEXER-160-WARBOW-REFRESH-CANDIDATES`, manual QA, indexer design, timecurve-views, play skill + `skills/README.md`, guardrails cross-link. ### Verification checklist for @brouie - [ ] Indexer serves route: `curl -sS "$INDEXER/v1/timecurve/warbow/refresh-candidates?limit=10" | jq .candidates,.total,.note` - [ ] Response header `x-schema-version: 1.15.0` on indexer routes. - [ ] With sale **live**: protocol panel loads candidates (`VITE_INDEXER_URL` set) and an EOA can submit `refreshWarbowPodium`; `warbowPodiumFinalized` may flip false until owner re-finalizes (expected #129 behavior). - [ ] With sale **ended**: same tx path reverts onchain; UI disables refresh and points to `finalizeWarbowPodium` (#149). - [ ] `cargo clippy --all-targets -- -D warnings` + indexer tests; frontend `tsc -b` / Vitest green on CI. Issue left **open** for your sign-off.
Brouie commented 2026-05-06 01:44:28 +00:00 (Migrated from gitlab.com)

@PlasticDigits — verification PASS on a648283 (merge 4ebbdb9).

checklist walked:

  1. indexer route serves the new endpoint:

curl -sS "http://127.0.0.1:3100/v1/timecurve/warbow/refresh-candidates?limit=10" → returns 21 total candidates, deduped, podium hints prepended (top 3 = 0x02484c, 0x5e661b, 0x8626f6 matching the live WarBow leaderboard at 22000 BP). note field correctly explains sale-live-only behavior + post-end fallback to owner finalize + candidate derivation logic (DISTINCT WarBow participants + buyers with battle_points_after > 0). pagination/cap fields all present.

  1. response header: x-schema-version: 1.15.0 confirmed via curl -sI.

  2. live walk on /timecurve/protocol → "Indexer + Wallet → WarBow Podium Refresh" panel:

  • initial state: warbowPodiumFinalized (read): false, candidates: —
  • click "Load candidates from indexer" → panel populates: Indexer candidates loaded (checksummed): 21, Indexer merged total (API): 21, Head WarBow hints merged: 3, SQL DISTINCT cap hit: false
  • click "Refresh WarBow podium" → MetaMask popup appears, calldata to TimeCurve 0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1 with method selector 0x5e68e4c2 (refreshWarbowPodium(address[]))
  • confirmed → tx landed at block 400, from 0xf39fd6e5...b92266 (deployer EOA), status 0x1 SUCCESS
  • panel correctly handles wrong-chain barrier + sale-ended guard per code path
  1. sale-ended path not walked separately — sale is live (deadline still ~2 days out), can't end it without breaking the rest of the verification matrix. source side coverage: refreshWarbowPodium reverts with TimeCurve: ended per #149 baseline; UI disables and points to finalizeWarbowPodium per the panel description.

  2. tooling clean:

  • cargo clippy --all-targets -- -D warnings (indexer): clean
  • cargo test (indexer): 42/42 PASS at HEAD 390f9be
  • frontend tsc -b: clean
  • frontend full npm test: 286/286 PASS across 47 files

scope honored: option A (sale-live indexer-assisted refresh only, no contract change) — #149 invariant preserved (post-end refresh still reverts), #129 / #133 expectations intact (warbowPodiumFinalized may flip false until owner re-finalizes, expected).

ready for close on your side.

@PlasticDigits — verification PASS on `a648283` (merge `4ebbdb9`). checklist walked: 1. indexer route serves the new endpoint: `curl -sS "http://127.0.0.1:3100/v1/timecurve/warbow/refresh-candidates?limit=10"` → returns 21 total candidates, deduped, podium hints prepended (top 3 = 0x02484c, 0x5e661b, 0x8626f6 matching the live WarBow leaderboard at 22000 BP). note field correctly explains sale-live-only behavior + post-end fallback to owner finalize + candidate derivation logic (DISTINCT WarBow participants + buyers with battle_points_after > 0). pagination/cap fields all present. 2. response header: `x-schema-version: 1.15.0` confirmed via `curl -sI`. 3. live walk on /timecurve/protocol → "Indexer + Wallet → WarBow Podium Refresh" panel: - initial state: `warbowPodiumFinalized (read): false`, candidates: `—` - click "Load candidates from indexer" → panel populates: `Indexer candidates loaded (checksummed): 21`, `Indexer merged total (API): 21`, `Head WarBow hints merged: 3`, `SQL DISTINCT cap hit: false` - click "Refresh WarBow podium" → MetaMask popup appears, calldata to TimeCurve `0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1` with method selector `0x5e68e4c2` (`refreshWarbowPodium(address[])`) - confirmed → tx landed at block 400, from `0xf39fd6e5...b92266` (deployer EOA), status `0x1` SUCCESS - panel correctly handles wrong-chain barrier + sale-ended guard per code path 4. sale-ended path not walked separately — sale is live (deadline still ~2 days out), can't end it without breaking the rest of the verification matrix. source side coverage: `refreshWarbowPodium` reverts with `TimeCurve: ended` per #149 baseline; UI disables and points to `finalizeWarbowPodium` per the panel description. 5. tooling clean: - `cargo clippy --all-targets -- -D warnings` (indexer): clean - `cargo test` (indexer): 42/42 PASS at HEAD `390f9be` - frontend `tsc -b`: clean - frontend full `npm test`: 286/286 PASS across 47 files scope honored: option A (sale-live indexer-assisted refresh only, no contract change) — #149 invariant preserved (post-end refresh still reverts), #129 / #133 expectations intact (warbowPodiumFinalized may flip false until owner re-finalizes, expected). ready for close on your side.
Brouie commented 2026-05-06 02:23:26 +00:00 (Migrated from gitlab.com)

@PlasticDigits — follow-up observations from a deeper read of TimeCurveProtocolWarbowRefreshSection.tsx after the live-walk PASS posted earlier. all hand-verified against source at HEAD 390f9be. none block close on #160; flagging here so you can fold any of these into a follow-up commit or spawn children as you prefer.

P2 — silent fail when indexer response shape drifts (lines 90-134)

loadFromIndexer only handles the explicit chunk === null branch. if getJson resolves but chunk.candidates is missing / non-iterable (older schema, partial response, intercepting proxy, malformed JSON that still parses), the for (const c of chunk.candidates) throws synchronously inside the loop. the function has try { ... } finally { setLoadingIdx(false) } — no catch — so the spinner clears but setLoadErr is never set. combined with void loadFromIndexer() at the click handler (line 218), the rejection becomes an unhandled console error and the user sees the spinner blip with no message.

suggested fix: add a top-level catch (e) { setLoadErr(\Indexer response invalid: ${e instanceof Error ? e.message : String(e)}`); setLoadedCandidates([]); setIdxExtras(null); }. tighten chunk.candidatestoArray.isArray(chunk.candidates)` before iterating.

P3 — loadedCandidates not cleared at start of fresh load (lines 90-93)

paired with the silent-fail above. the function clears setLoadErr(null) upfront but leaves prior loadedCandidates and idxExtras in place until new pages successfully accumulate. so if load 1 succeeds with N candidates and load 2 fails per the silent-fail path, the UI still shows N + previous extras and the user thinks the second load worked.

suggested fix: reset setLoadedCandidates([]) and setIdxExtras(null) at the top of the function, alongside setLoadErr(null).

P2 — large-candidate gas-blowup unguarded (lines 100-123, 136-170)

indexer caps the SQL DISTINCT result at REFRESH_CANDIDATES_DISTINCT_CAP = 10_000 (indexer/src/api.rs:59) plus head podium hints; frontend pages everything (guard < 50 × limit = 500 = 25,000 ceiling) into one tx. refreshWarbowPodium iterates _updateWarbowPodium per candidate (contracts/src/TimeCurve.sol:1073-1082), so a real BP-earner population in the thousands can blow block gas in a single submit. user sees a generic revert via friendlyRevertFromUnknown, no preflight or estimateGas, no chunking suggestion.

severity scales with expected real-mainnet participation. probably P2 polish if peak BP-earner count stays in the low hundreds; closer to P1 if it's into the thousands.

suggested fix (minimum): estimateGas before submit, refuse / warn if it exceeds a configured fraction of block gas. (full): chunked submit with progress UI when loadedCandidates.length exceeds a soft threshold.

P3 — chainMismatchWriteMessage(chainId) called twice (lines 142-143)

if (chainMismatchWriteMessage(chainId)) { setTxErr(chainMismatchWriteMessage(chainId) ?? "..."); return; } invokes the helper twice. cosmetic, but the rest of the codebase patterns the call once into a local. trivial fix: const cm = chainMismatchWriteMessage(chainId); if (cm) { setTxErr(cm); return; }.

P3 — silent truncation if pagination guard ever fires (lines 100-123)

while (guard < 50) exits cleanly after 50 pages. with the current 10k indexer cap the loop always exits via next_offset === null first, but if the cap is raised in a future schema bump and the frontend is pulled forward without lifting the guard, this becomes silent truncation — user sees a candidate count without knowing more wallets were skipped.

suggested fix: if guard === 50 && chunk.next_offset !== null after the loop, set a non-fatal warning state.

P4 — no Vitest unit/component test ships with the new section (commit a648283)

manual QA + indexer integration test landed but no Vitest covering frontend behavior — pagination accumulation across next_offset, OR-aggregation of distinct_sql_cap_hit across pages, dedup correctness across podium hints + indexer rows + connected wallet, the saleEnded early-return, the wbReads not-loaded gate. the sister flow at useTimeCurveArenaModel.tsx:2626 is similarly untested so this isn't a regression. cheap to add; high coverage gain on a permissionless write path.

anti-findings (looked suspicious, are actually fine)

  • no wallet-drift snapshot pattern. correct here — refreshWarbowPodium is permissionless and the contract reads battlePoints[c] directly. drift across awaits has no security or correctness impact. consistent with the Arena sister flow at useTimeCurveArenaModel.tsx:2615-2641.
  • connected wallet bundled into viewer even when on wrong chain. just one extra BP read; dedup helper handles a viewer already in podiumWallets.
  • warbowPodiumFinalized flips false on every refresh. documented per TimeCurve.sol:1075 and #129 — owner re-finalizes after endSale.
  • saleEnded defaults to true while parent reads load (TimeCurveProtocolPage.tsx:206-207). correct fail-safe.
  • pr[0]?.status === "success" && pr[0].result === undefined paranoia check at line 151. wagmi typing already implies result is defined when status is success, but redundant safety is harmless.

open questions

  • expected upper bound on candidate count for mainnet sales? answers whether the gas-blowup is P1 or P2.
  • worth surfacing a mismatch warning when indexer podium_warbow_hint_count differs from the onchain warbowLadderPodium the component already reads? could help operators spot stale chain-timer state.
  • should runRefresh estimateGas first, or rely on the wallet's own gas-estimate UX? either is defensible.

happy to ship a follow-up MR covering P2 silent-fail + P3 reset-on-reload + P3 cosmetic-double-call as a single tight patch if you want it. larger scope items (gas-blowup mitigation, vitest coverage) i'd want your steer on first.

(#160 ready for close on your side regardless of what you do with these — they're follow-ups, not blockers.)

@PlasticDigits — follow-up observations from a deeper read of `TimeCurveProtocolWarbowRefreshSection.tsx` after the live-walk PASS posted earlier. all hand-verified against source at HEAD `390f9be`. none block close on #160; flagging here so you can fold any of these into a follow-up commit or spawn children as you prefer. ## P2 — silent fail when indexer response shape drifts (lines 90-134) `loadFromIndexer` only handles the explicit `chunk === null` branch. if `getJson` resolves but `chunk.candidates` is missing / non-iterable (older schema, partial response, intercepting proxy, malformed JSON that still parses), the `for (const c of chunk.candidates)` throws synchronously inside the loop. the function has `try { ... } finally { setLoadingIdx(false) }` — no `catch` — so the spinner clears but `setLoadErr` is never set. combined with `void loadFromIndexer()` at the click handler (line 218), the rejection becomes an unhandled console error and the user sees the spinner blip with no message. suggested fix: add a top-level `catch (e) { setLoadErr(\`Indexer response invalid: \${e instanceof Error ? e.message : String(e)}\`); setLoadedCandidates([]); setIdxExtras(null); }`. tighten `chunk.candidates` to `Array.isArray(chunk.candidates)` before iterating. ## P3 — `loadedCandidates` not cleared at start of fresh load (lines 90-93) paired with the silent-fail above. the function clears `setLoadErr(null)` upfront but leaves prior `loadedCandidates` and `idxExtras` in place until new pages successfully accumulate. so if load 1 succeeds with N candidates and load 2 fails per the silent-fail path, the UI still shows N + previous extras and the user thinks the second load worked. suggested fix: reset `setLoadedCandidates([])` and `setIdxExtras(null)` at the top of the function, alongside `setLoadErr(null)`. ## P2 — large-candidate gas-blowup unguarded (lines 100-123, 136-170) indexer caps the SQL DISTINCT result at `REFRESH_CANDIDATES_DISTINCT_CAP = 10_000` (`indexer/src/api.rs:59`) plus head podium hints; frontend pages everything (guard `< 50 × limit = 500 = 25,000` ceiling) into one tx. `refreshWarbowPodium` iterates `_updateWarbowPodium` per candidate (`contracts/src/TimeCurve.sol:1073-1082`), so a real BP-earner population in the thousands can blow block gas in a single submit. user sees a generic revert via `friendlyRevertFromUnknown`, no preflight or `estimateGas`, no chunking suggestion. severity scales with expected real-mainnet participation. probably P2 polish if peak BP-earner count stays in the low hundreds; closer to P1 if it's into the thousands. suggested fix (minimum): `estimateGas` before submit, refuse / warn if it exceeds a configured fraction of block gas. (full): chunked submit with progress UI when `loadedCandidates.length` exceeds a soft threshold. ## P3 — `chainMismatchWriteMessage(chainId)` called twice (lines 142-143) `if (chainMismatchWriteMessage(chainId)) { setTxErr(chainMismatchWriteMessage(chainId) ?? "..."); return; }` invokes the helper twice. cosmetic, but the rest of the codebase patterns the call once into a local. trivial fix: `const cm = chainMismatchWriteMessage(chainId); if (cm) { setTxErr(cm); return; }`. ## P3 — silent truncation if pagination guard ever fires (lines 100-123) `while (guard < 50)` exits cleanly after 50 pages. with the current 10k indexer cap the loop always exits via `next_offset === null` first, but if the cap is raised in a future schema bump and the frontend is pulled forward without lifting the guard, this becomes silent truncation — user sees a candidate count without knowing more wallets were skipped. suggested fix: if `guard === 50 && chunk.next_offset !== null` after the loop, set a non-fatal warning state. ## P4 — no Vitest unit/component test ships with the new section (commit `a648283`) manual QA + indexer integration test landed but no Vitest covering frontend behavior — pagination accumulation across `next_offset`, OR-aggregation of `distinct_sql_cap_hit` across pages, dedup correctness across podium hints + indexer rows + connected wallet, the `saleEnded` early-return, the `wbReads` not-loaded gate. the sister flow at `useTimeCurveArenaModel.tsx:2626` is similarly untested so this isn't a regression. cheap to add; high coverage gain on a permissionless write path. ## anti-findings (looked suspicious, are actually fine) - no wallet-drift snapshot pattern. correct here — `refreshWarbowPodium` is permissionless and the contract reads `battlePoints[c]` directly. drift across awaits has no security or correctness impact. consistent with the Arena sister flow at `useTimeCurveArenaModel.tsx:2615-2641`. - connected wallet bundled into viewer even when on wrong chain. just one extra BP read; dedup helper handles a viewer already in `podiumWallets`. - `warbowPodiumFinalized` flips false on every refresh. documented per `TimeCurve.sol:1075` and #129 — owner re-finalizes after `endSale`. - `saleEnded` defaults to `true` while parent reads load (`TimeCurveProtocolPage.tsx:206-207`). correct fail-safe. - `pr[0]?.status === "success" && pr[0].result === undefined` paranoia check at line 151. wagmi typing already implies result is defined when status is success, but redundant safety is harmless. ## open questions - expected upper bound on candidate count for mainnet sales? answers whether the gas-blowup is P1 or P2. - worth surfacing a mismatch warning when indexer `podium_warbow_hint_count` differs from the onchain `warbowLadderPodium` the component already reads? could help operators spot stale chain-timer state. - should `runRefresh` `estimateGas` first, or rely on the wallet's own gas-estimate UX? either is defensible. happy to ship a follow-up MR covering P2 silent-fail + P3 reset-on-reload + P3 cosmetic-double-call as a single tight patch if you want it. larger scope items (gas-blowup mitigation, vitest coverage) i'd want your steer on first. (#160 ready for close on your side regardless of what you do with these — they're follow-ups, not blockers.)
Brouie commented 2026-05-06 03:59:18 +00:00 (Migrated from gitlab.com)

mentioned in issue #167

mentioned in issue #167
PlasticDigits commented 2026-05-06 08:30:51 +00:00 (Migrated from gitlab.com)
  • All of these findings need to have issues opened for them @Brouie and anti-findings are correct.
  • Upper bound could be 10s of millions, this is a serious issue. We need to design and implement a more gas and query efficient solution, so in the issue "P2 — large-candidate gas-blowup unguarded (lines 100-123, 136-170)" mark as severe, critical, and design required.
  • We should estimate gas as some wallets do not correclty estimate gas, and this also allows us to add a gas buffer of 30% in case the contract state changes and consumes more gas than expected - so please open an issue for this as well
- All of these findings need to have issues opened for them @Brouie and anti-findings are correct. - Upper bound could be 10s of millions, this is a serious issue. We need to design and implement a more gas and query efficient solution, so in the issue "P2 — large-candidate gas-blowup unguarded (lines 100-123, 136-170)" mark as severe, critical, and design required. - We should estimate gas as some wallets do not correclty estimate gas, and this also allows us to add a gas buffer of 30% in case the contract state changes and consumes more gas than expected - so please open an issue for this as well
PlasticDigits commented 2026-05-06 08:31:08 +00:00 (Migrated from gitlab.com)

Once those issues are opened you can close this issue (#160)

Once those issues are opened you can close this issue (#160)
Brouie commented 2026-05-07 01:53:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #172

mentioned in issue #172
Brouie commented 2026-05-07 01:58:32 +00:00 (Migrated from gitlab.com)

mentioned in issue #173

mentioned in issue #173
Brouie commented 2026-05-07 02:01:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #174

mentioned in issue #174
Brouie commented 2026-05-07 02:02:52 +00:00 (Migrated from gitlab.com)

mentioned in issue #175

mentioned in issue #175
Brouie commented 2026-05-07 02:05:59 +00:00 (Migrated from gitlab.com)

mentioned in issue #176

mentioned in issue #176
Brouie commented 2026-05-07 02:09:58 +00:00 (Migrated from gitlab.com)

@PlasticDigits — opened the follow-up tickets per your direction.

#172 — TimeCurve refreshWarbowPodium / finalizeWarbowPodium scaling (CRITICAL, design required, supersedes the original P2 framing per your bump). includes per-candidate gas math at the 10M upper bound and 5 design directions to evaluate.

#173 — chainMismatchWriteMessage double-call in runRefresh (P3 cosmetic).

#174 — pagination guard exhaustion silently truncates candidate set (P3 forward-compat — does not bite today, bites if indexer cap rises later).

#175 — missing Vitest coverage on TimeCurveProtocolWarbowRefreshSection (P4).

#176 — estimateGas + 30% buffer threading across all 5 wagmi write-path files (P2 — your separate ask). estimateGasUnits helper already exists in lib/estimateContractGas.ts but only at 6 display-only sites in the Arena hook, no buffer applied anywhere.

two of my original findings (P2 silent-fail at 88-134, P3 reset-on-reload at 90-93) were absorbed by the #170 P3 polish patch (fff7946) — already in tree at HEAD 284c15c. flagging here so the count adds up: 6 follow-up findings + estimateGas ask = 5 new tickets after dedup.

closing #160 per your earlier note.

@PlasticDigits — opened the follow-up tickets per your direction. #172 — TimeCurve refreshWarbowPodium / finalizeWarbowPodium scaling (CRITICAL, design required, supersedes the original P2 framing per your bump). includes per-candidate gas math at the 10M upper bound and 5 design directions to evaluate. #173 — chainMismatchWriteMessage double-call in runRefresh (P3 cosmetic). #174 — pagination guard exhaustion silently truncates candidate set (P3 forward-compat — does not bite today, bites if indexer cap rises later). #175 — missing Vitest coverage on TimeCurveProtocolWarbowRefreshSection (P4). #176 — estimateGas + 30% buffer threading across all 5 wagmi write-path files (P2 — your separate ask). estimateGasUnits helper already exists in lib/estimateContractGas.ts but only at 6 display-only sites in the Arena hook, no buffer applied anywhere. two of my original findings (P2 silent-fail at 88-134, P3 reset-on-reload at 90-93) were absorbed by the #170 P3 polish patch (`fff7946`) — already in tree at HEAD `284c15c`. flagging here so the count adds up: 6 follow-up findings + estimateGas ask = 5 new tickets after dedup. closing #160 per your earlier note.
Brouie (Migrated from gitlab.com) closed this issue 2026-05-07 02:10:24 +00:00
Brouie commented 2026-05-07 02:49:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #170

mentioned in issue #170
Brouie commented 2026-05-07 03:19:40 +00:00 (Migrated from gitlab.com)

mentioned in merge request !377

mentioned in merge request !377
PlasticDigits commented 2026-05-13 15:13:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 8dfdf64871

mentioned in commit 8dfdf64871eafede5789ed9ba29e3b3d231ef167
PlasticDigits commented 2026-05-13 15:13:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 08a95bd913

mentioned in commit 08a95bd91318d716205edd178ffc63c91ef76ff8
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#160
No description provided.