Batch chain-timer eth_calls via Multicall3 (#307) #488

Merged
PlasticDigits merged 2 commits from issue-307-multicall-chain-timer into main 2026-06-14 07:11:20 +00:00
PlasticDigits commented 2026-06-14 05:39:43 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #307: collapse the chain-timer poll_once fan-out (~30 sequential eth_calls per ~1 Hz cycle) into one Multicall3 aggregate3 round-trip at a single read_block_number, with duplicate-call coalescing and a sequential fallback when Multicall3 bytecode is absent.

  • New indexer/src/multicall.rs — aggregate3 encode/decode, batch chunking, coalesce helper
  • chain_timer::poll_once — Multicall3 primary path; poll_once_sequential fallback
  • sale_state — sale_state_from_fields for batched decode (no extra RPC for deadline)
  • Anvil bootstrap — scripts/lib/anvil_multicall3.sh + bytecode at canonical 0xcA11… (wired into verify/benchmark scripts)
  • Benchmark artifact docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json — idle peak_calls_10s 44 (was 354)

Related: parent #306 · MR !454 baseline

Acceptance checklist

Item Command / step Result
poll_once uses Multicall3 for majority of chain-timer eth_calls code review multicall.rs + chain_timer.rs PASS — 1 aggregate replaces ~28 sequential calls
Idle peak_calls_10s ≤ 50 (120s benchmark) BENCHMARK_SCENARIO_SEC=120 bash scripts/benchmark-indexer-rpc-anvil.sh PASS — idle final sample peak_calls_10s=44
by_caller.chain_timer eth_call ≥40% reduction vs baseline compare to rpc-benchmark-20260610T111415Z.json PASS — ~11 eth_call:chain_timer / 10s burst vs 352 (~97% reduction)
GET /v1/arena/timers freshness ≤3s (idle Anvil) HTTP 200 during verify; read_block_number tracks head PASS (proxy — polled_at_ms internal only)
INV-INDEXER-306-NO-REGRESSION bash scripts/verify-podium-live-anvil.sh FAIL — on-chain steps pass; bundled integration_stage2 flakes arena_wallet_stats_two_epochs_and_bonus_fields in harness only (standalone cargo test PASS)
Unit + clippy cd indexer && cargo clippy --all-targets -- -D warnings && cargo test PASS
Status metrics smoke bash scripts/verify-indexer-rpc-metrics.sh PASS — peak_calls_10s=44
Docs / invariants docs/indexer/rpc-load-benchmark.md, invariants §307 PASS
Malformed aggregate / partial batch / metrics gaming unit tests + allowFailure: false PASS (decode failure fails whole poll; one metric per aggregate)

Verification for third parties

export PATH="$HOME/.foundry/bin:$PATH"
source /usr/local/cargo/env 2>/dev/null || true
bash scripts/bootstrap-cloud-postgres-native.sh

cd indexer && cargo clippy --all-targets -- -D warnings && cargo test
bash scripts/verify-indexer-rpc-metrics.sh
BENCHMARK_SCENARIO_SEC=120 bash scripts/benchmark-indexer-rpc-anvil.sh
# Expect idle peak_calls_10s ≤ 50 in docs/indexer/benchmarks/rpc-benchmark-*.json

Operator note: production chains need Multicall3 at 0xcA11bde05977b3631167028862bE2a173976CA11 (standard). Fresh Anvil installs it via scripts/lib/anvil_multicall3.sh.

Blockers

  • verify-podium-live-anvil.sh harness flake on arena_wallet_stats_two_epochs_and_bonus_fields (pre-existing; unrelated to multicall)

Follow-ups

  • Investigate arena_wallet_stats_two_epochs_and_bonus_fields ordering flake in verify harness
  • Adaptive poll-interval sibling from #306 triage

Note

Medium Risk
Touches the hot path for GET /v1/arena/timers freshness; decode or batch failures fail the whole poll, though sequential fallback and existing backoff limit stale-as-fresh exposure.

Overview
Implements GitLab #307 by replacing the chain-timer poll_once fan-out (~30 sequential eth_calls per ~1 Hz cycle) with one Multicall3 aggregate3 at a single read_block_number, including duplicate-call coalescing and a sequential fallback when Multicall3 bytecode is missing. sale_state gains batched decode helpers so deadlines do not need extra RPC after the aggregate.

This diff adds verification artifacts: a 120s Anvil RPC benchmark (docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json + .md) showing idle peak_calls_10s 44 (vs ~354 pre-batch baseline), plus indexer/README documentation for INV-INDEXER-307-MULTICALL-BATCH. scripts/lib/multicall3_anvil_bytecode.hex supports fresh Anvil installs at canonical 0xcA11…CA11 (wired via anvil_multicall3.sh into verify/benchmark scripts).

Reviewed by Cursor Bugbot for commit c432cee3fe. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Implements GitLab #307: collapse the chain-timer `poll_once` fan-out (~30 sequential `eth_call`s per ~1 Hz cycle) into **one Multicall3 `aggregate3`** round-trip at a single `read_block_number`, with duplicate-call coalescing and a sequential fallback when Multicall3 bytecode is absent. - New `indexer/src/multicall.rs` — `aggregate3` encode/decode, batch chunking, coalesce helper - `chain_timer::poll_once` — Multicall3 primary path; `poll_once_sequential` fallback - `sale_state` — `sale_state_from_fields` for batched decode (no extra RPC for deadline) - Anvil bootstrap — `scripts/lib/anvil_multicall3.sh` + bytecode at canonical `0xcA11…` (wired into verify/benchmark scripts) - Benchmark artifact `docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json` — idle `peak_calls_10s` **44** (was **354**) Related: parent #306 · MR !454 baseline ## Acceptance checklist | Item | Command / step | Result | |------|----------------|--------| | `poll_once` uses Multicall3 for majority of chain-timer `eth_call`s | code review `multicall.rs` + `chain_timer.rs` | **PASS** — 1 aggregate replaces ~28 sequential calls | | Idle `peak_calls_10s` ≤ 50 (120s benchmark) | `BENCHMARK_SCENARIO_SEC=120 bash scripts/benchmark-indexer-rpc-anvil.sh` | **PASS** — idle final sample `peak_calls_10s=44` | | `by_caller.chain_timer` `eth_call` ≥40% reduction vs baseline | compare to `rpc-benchmark-20260610T111415Z.json` | **PASS** — ~11 `eth_call:chain_timer` / 10s burst vs 352 (~97% reduction) | | `GET /v1/arena/timers` freshness ≤3s (idle Anvil) | HTTP 200 during verify; `read_block_number` tracks head | **PASS** (proxy — `polled_at_ms` internal only) | | `INV-INDEXER-306-NO-REGRESSION` | `bash scripts/verify-podium-live-anvil.sh` | **FAIL** — on-chain steps pass; bundled `integration_stage2` flakes `arena_wallet_stats_two_epochs_and_bonus_fields` in harness only (standalone `cargo test` PASS) | | Unit + clippy | `cd indexer && cargo clippy --all-targets -- -D warnings && cargo test` | **PASS** | | Status metrics smoke | `bash scripts/verify-indexer-rpc-metrics.sh` | **PASS** — `peak_calls_10s=44` | | Docs / invariants | `docs/indexer/rpc-load-benchmark.md`, `invariants §307` | **PASS** | | Malformed aggregate / partial batch / metrics gaming | unit tests + `allowFailure: false` | **PASS** (decode failure fails whole poll; one metric per aggregate) | ## Verification for third parties ```bash export PATH="$HOME/.foundry/bin:$PATH" source /usr/local/cargo/env 2>/dev/null || true bash scripts/bootstrap-cloud-postgres-native.sh cd indexer && cargo clippy --all-targets -- -D warnings && cargo test bash scripts/verify-indexer-rpc-metrics.sh BENCHMARK_SCENARIO_SEC=120 bash scripts/benchmark-indexer-rpc-anvil.sh # Expect idle peak_calls_10s ≤ 50 in docs/indexer/benchmarks/rpc-benchmark-*.json ``` Operator note: production chains need Multicall3 at `0xcA11bde05977b3631167028862bE2a173976CA11` (standard). Fresh Anvil installs it via `scripts/lib/anvil_multicall3.sh`. ## Blockers - `verify-podium-live-anvil.sh` harness flake on `arena_wallet_stats_two_epochs_and_bonus_fields` (pre-existing; unrelated to multicall) ## Follow-ups - Investigate `arena_wallet_stats_two_epochs_and_bonus_fields` ordering flake in verify harness - Adaptive poll-interval sibling from #306 triage <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches the hot path for `GET /v1/arena/timers` freshness; decode or batch failures fail the whole poll, though sequential fallback and existing backoff limit stale-as-fresh exposure. > > **Overview** > Implements **GitLab #307** by replacing the chain-timer **`poll_once`** fan-out (~30 sequential **`eth_call`s** per ~1 Hz cycle) with **one Multicall3 `aggregate3`** at a single **`read_block_number`**, including duplicate-call coalescing and a **sequential fallback** when Multicall3 bytecode is missing. **`sale_state`** gains batched decode helpers so deadlines do not need extra RPC after the aggregate. > > This diff adds **verification artifacts**: a 120s Anvil RPC benchmark (`docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json` + `.md`) showing idle **`peak_calls_10s` 44** (vs ~354 pre-batch baseline), plus **`indexer/README`** documentation for **`INV-INDEXER-307-MULTICALL-BATCH`**. **`scripts/lib/multicall3_anvil_bytecode.hex`** supports fresh Anvil installs at canonical **`0xcA11…CA11`** (wired via **`anvil_multicall3.sh`** into verify/benchmark scripts). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c432cee3fe1b58dcce2f2cc87bad8963aaf0dd44. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 05:39:52 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 05:40:03 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 05:41:38 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ac2b9b2871. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTo5YTg3ODFmZi1mNjc1LTQyZGMtOTNlZS0wZGZjYzRkOTA1MDYiLCJlbmNyeXB0aW9uS2V5IjoiT2JSOElyQlZKdkNpSmJCdFF1TEZwaEk0T1hOUjQ0R1RyTldQUDh5T3hkbyIsImJyYW5jaCI6Imlzc3VlLTMwNy1tdWx0aWNhbGwtY2hhaW4tdGltZXIiLCJyZXBvT3duZXIiOiJQbGFzdGljRGlnaXRzIiwicmVwb05hbWUiOiJ5aWVsZG9tZWdhIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix All in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a> <!-- /BUGBOT_FIX_ALL --> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the [Cursor dashboard](https://www.cursor.com/dashboard/bugbot).</sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ac2b9b2871f3d57d581e2a52a946aacbdea30a2e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 05:41:39 +00:00 (Migrated from gitlab.com)

Failed batch never disables multicall

Medium Severity

When poll_once_multicall fails, poll_once logs and falls back to sequential calls but leaves Multicall3 marked available. Each subsequent poll retries the failing aggregate3 before running the full sequential fan-out, adding an extra eth_call every cycle while Multicall3 bytecode is broken or incompatible.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ac2b9b2871. Configure here.

### Failed batch never disables multicall **Medium Severity** <!-- DESCRIPTION START --> When `poll_once_multicall` fails, `poll_once` logs and falls back to sequential calls but leaves Multicall3 marked available. Each subsequent poll retries the failing `aggregate3` before running the full sequential fan-out, adding an extra `eth_call` every cycle while Multicall3 bytecode is broken or incompatible. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 6183ee5b-e6f2-41ca-8f76-b630efe02b30 --> <!-- LOCATIONS START indexer/src/chain_timer.rs#L311-L323 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjgxODc3YTE0LTc5Y2MtNGY0NC04Yzg4LWI4YmMwNWUxYThhNyIsImVuY3J5cHRpb25LZXkiOiJ4UkUwZGJ5b2lNSTh2b2JlZWZOYjZQVi1Cem9qMzE0Z2ZoQi04UGRBMk9rIiwiYnJhbmNoIjoiaXNzdWUtMzA3LW11bHRpY2FsbC1jaGFpbi10aW1lciIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6InlpZWxkb21lZ2EifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjgxODc3YTE0LTc5Y2MtNGY0NC04Yzg4LWI4YmMwNWUxYThhNyIsImVuY3J5cHRpb25LZXkiOiJ4UkUwZGJ5b2lNSTh2b2JlZWZOYjZQVi1Cem9qMzE0Z2ZoQi04UGRBMk9rIiwiYnJhbmNoIjoiaXNzdWUtMzA3LW11bHRpY2FsbC1jaGFpbi10aW1lciIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6InlpZWxkb21lZ2EiLCJwck51bWJlciI6MTE4LCJjb21taXRTaGEiOiJhYzJiOWIyODcxZjNkNTdkNTgxZTJhNTJhOTQ2YWFjYmRlYTMwYTJlIiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ac2b9b2871f3d57d581e2a52a946aacbdea30a2e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 05:41:39 +00:00 (Migrated from gitlab.com)

Probe errors disable multicall permanently

Medium Severity

In probe_multicall3, a failed get_code_at RPC (timeout, 5xx, or all endpoints down) is treated the same as confirmed absent bytecode: MULTICALL_MODE is set to MC_UNAVAILABLE for the rest of the process. Later polls skip Multicall3 entirely via multicall_batching_enabled, even after RPC recovers on chains where Multicall3 is deployed.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ac2b9b2871. Configure here.

### Probe errors disable multicall permanently **Medium Severity** <!-- DESCRIPTION START --> In `probe_multicall3`, a failed `get_code_at` RPC (timeout, 5xx, or all endpoints down) is treated the same as confirmed absent bytecode: `MULTICALL_MODE` is set to `MC_UNAVAILABLE` for the rest of the process. Later polls skip Multicall3 entirely via `multicall_batching_enabled`, even after RPC recovers on chains where Multicall3 is deployed. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 8ba13eeb-059a-4bf3-a8d0-2a4e54009dd6 --> <!-- LOCATIONS START indexer/src/multicall.rs#L66-L87 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmY2MGRhNmI4LTYzYWEtNDM0Mi04ZDkzLWY4YTVlZGVkMzMyMCIsImVuY3J5cHRpb25LZXkiOiJKSVo3YXJPNm16Mmw1b1h1d05RWGNHVlNzNHNUVEVwQTc4aWR4NE44U2hrIiwiYnJhbmNoIjoiaXNzdWUtMzA3LW11bHRpY2FsbC1jaGFpbi10aW1lciIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6InlpZWxkb21lZ2EifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmY2MGRhNmI4LTYzYWEtNDM0Mi04ZDkzLWY4YTVlZGVkMzMyMCIsImVuY3J5cHRpb25LZXkiOiJKSVo3YXJPNm16Mmw1b1h1d05RWGNHVlNzNHNUVEVwQTc4aWR4NE44U2hrIiwiYnJhbmNoIjoiaXNzdWUtMzA3LW11bHRpY2FsbC1jaGFpbi10aW1lciIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6InlpZWxkb21lZ2EiLCJwck51bWJlciI6MTE4LCJjb21taXRTaGEiOiJhYzJiOWIyODcxZjNkNTdkNTgxZTJhNTJhOTQ2YWFjYmRlYTMwYTJlIiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ac2b9b2871f3d57d581e2a52a946aacbdea30a2e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-14 05:45:37 +00:00 (Migrated from gitlab.com)

Security review — MR !488

Commit reviewed: ac2b9b2871f3d57d581e2a52a946aacbdea30a2e

Scope: Multicall3 aggregate3 batching for chain-timer head reads (indexer/src/multicall.rs, chain_timer.rs, sale_state.rs), Anvil Multicall3 bootstrap (scripts/lib/anvil_multicall3.sh + bytecode), verify/benchmark wiring, docs/invariants.

Method: Diff review; traced batch inputs (operator-configured TimeArena / PodiumVaults addresses + fixed selectors) through aggregate3 encode/decode to GET /v1/arena/timers snapshot fields. Compared trust boundaries vs pre-MR sequential eth_call path.

Outcome: FINDINGS: 0 medium+

Notes (below severity threshold / not introduced exploit paths)

  • Batch inputs are not user-controlled. Sub-calls are hardcoded view selectors against registry addresses; no injection surface into SQL, shell, or HTTP handlers.
  • allowFailure: false + subcall success checks reject partial/malformed aggregate results; decode errors fail the poll and fall back to sequential reads — no silent field substitution observed.
  • Single read_block_number block tag for the batch improves head consistency vs scattered sequential calls (reduces cross-read TOCTOU), with the same RPC/chain trust model as before.
  • Multicall3 probe caches MC_UNAVAILABLE on transient get_code_at errors and failed batches do not call mark_multicall_unavailable (Bugbot threads) — these are availability/efficiency regressions, not authz bypasses or fund-impact paths; sequential fallback still serves data from the same RPC sources.
  • scripts/lib/anvil_multicall3.sh is local-dev only; skips install when bytecode already present (operator/dev trust). Committed bytecode includes standard Multicall3 aggregate3 selector (0x82ad56cb) and revert string Multicall3: call failed.
  • Display-oracle manipulation via malicious RPC or wrong-chain Multicall3 bytecode is pre-existing indexer trust on RPC_URL + registry addresses; this MR does not expand attacker-controlled sinks.

Inline threads: none (no medium+ findings).

Security review: no medium+ findings on this diff.

## Security review — MR !488 **Commit reviewed:** `ac2b9b2871f3d57d581e2a52a946aacbdea30a2e` **Scope:** Multicall3 `aggregate3` batching for chain-timer head reads (`indexer/src/multicall.rs`, `chain_timer.rs`, `sale_state.rs`), Anvil Multicall3 bootstrap (`scripts/lib/anvil_multicall3.sh` + bytecode), verify/benchmark wiring, docs/invariants. **Method:** Diff review; traced batch inputs (operator-configured `TimeArena` / `PodiumVaults` addresses + fixed selectors) through `aggregate3` encode/decode to `GET /v1/arena/timers` snapshot fields. Compared trust boundaries vs pre-MR sequential `eth_call` path. **Outcome:** **FINDINGS: 0** medium+ ### Notes (below severity threshold / not introduced exploit paths) - **Batch inputs are not user-controlled.** Sub-calls are hardcoded view selectors against registry addresses; no injection surface into SQL, shell, or HTTP handlers. - **`allowFailure: false` + subcall `success` checks** reject partial/malformed aggregate results; decode errors fail the poll and fall back to sequential reads — no silent field substitution observed. - **Single `read_block_number` block tag** for the batch improves head consistency vs scattered sequential calls (reduces cross-read TOCTOU), with the same RPC/chain trust model as before. - **Multicall3 probe caches `MC_UNAVAILABLE` on transient `get_code_at` errors** and **failed batches do not call `mark_multicall_unavailable`** (Bugbot threads) — these are availability/efficiency regressions, not authz bypasses or fund-impact paths; sequential fallback still serves data from the same RPC sources. - **`scripts/lib/anvil_multicall3.sh`** is local-dev only; skips install when bytecode already present (operator/dev trust). Committed bytecode includes standard Multicall3 `aggregate3` selector (`0x82ad56cb`) and revert string `Multicall3: call failed`. - **Display-oracle manipulation** via malicious RPC or wrong-chain Multicall3 bytecode is pre-existing indexer trust on `RPC_URL` + registry addresses; this MR does not expand attacker-controlled sinks. **Inline threads:** none (no medium+ findings). Security review: **no medium+ findings** on this diff.
PlasticDigits commented 2026-06-14 06:56:05 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/yieldomega/-/merge_requests/118/diffs?diff_id=1850611564&start_sha=ac2b9b2871f3d57d581e2a52a946aacbdea30a2e#3440af45bad0179d2131631d0d2bfbfd3512be1b_323_389)
PlasticDigits commented 2026-06-14 06:56:06 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/yieldomega/-/merge_requests/118/diffs?diff_id=1850611564&start_sha=ac2b9b2871f3d57d581e2a52a946aacbdea30a2e#c8878200f6813259dbd5c5f848b3c5fc621704ee_87_53)
PlasticDigits commented 2026-06-14 06:56:06 +00:00 (Migrated from gitlab.com)

added 100 commits

  • ac2b9b28...862964db - 99 commits from branch main
  • c432cee3 - Merge origin/main into issue-307-multicall-chain-timer

Compare with previous version

added 100 commits <ul><li>ac2b9b28...862964db - 99 commits from branch <code>main</code></li><li>c432cee3 - Merge origin/main into issue-307-multicall-chain-timer</li></ul> [Compare with previous version](/PlasticDigits/yieldomega/-/merge_requests/118/diffs?diff_id=1850611564&start_sha=ac2b9b2871f3d57d581e2a52a946aacbdea30a2e)
PlasticDigits commented 2026-06-14 06:56:08 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with origin/main (merge commit c432cee3).

Conflicts resolved (9 files): took main's integrated #307 implementation — MulticallBatch / aggregate3_at_block in multicall.rs, sale_state_from_returns, shared yieldomega_verify_boot_indexer_stack verify bootstrap, and yieldomega_ensure_anvil_multicall3 (signed deploy tx). Dropped branch-only MulticallRequest probe path and anvil_setCode helper in favor of main.

Preserved from branch: benchmark artifact docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json.

Sanity: cargo clippy --all-targets -- -D warnings and cargo test in indexer/ — PASS.

Resolved merge conflicts with `origin/main` (merge commit `c432cee3`). **Conflicts resolved (9 files):** took main's integrated #307 implementation — `MulticallBatch` / `aggregate3_at_block` in `multicall.rs`, `sale_state_from_returns`, shared `yieldomega_verify_boot_indexer_stack` verify bootstrap, and `yieldomega_ensure_anvil_multicall3` (signed deploy tx). Dropped branch-only `MulticallRequest` probe path and `anvil_setCode` helper in favor of main. **Preserved from branch:** benchmark artifact `docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.json`. **Sanity:** `cargo clippy --all-targets -- -D warnings` and `cargo test` in `indexer/` — PASS.
project_80561744_bot_5118c68a88bff95eacb6ab1c47c19cae commented 2026-06-14 06:56:36 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-14 06:58:44 +00:00 (Migrated from gitlab.com)

Security review — MR !488

Commit reviewed: c432cee3fe1b58dcce2f2cc87bad8963aaf0dd44

Scope: Post-merge diff vs main (4 files): benchmark artifacts (docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.{json,md}), indexer/README.md §307 note, scripts/lib/multicall3_anvil_bytecode.hex. Surrounding #307 paths on this SHA reviewed for exploitability: indexer/src/multicall.rs, chain_timer.rs, sale_state.rs, scripts/lib/anvil_multicall3.sh (merged from main; branch-only MulticallRequest probe / anvil_setCode path removed).

Method: Diff review; traced batch inputs (operator-configured TimeArena / PodiumVaults + fixed selectors) through aggregate3 encode/decode to GET /v1/arena/timers snapshot fields; verified Anvil bootstrap trust boundaries and committed bytecode surface.

Outcome: FINDINGS: 0 medium+

Notes (below severity threshold / not introduced exploit paths)

  • Batch inputs are not user-controlled. Sub-calls are hardcoded view selectors against registry addresses; no injection surface into SQL, shell, or HTTP handlers.
  • allowFailure: false + per-subcall success checks (multicall.rs) reject partial/malformed aggregate results; decode errors fail the poll and poll_once falls back to sequential reads — no silent field substitution.
  • Single read_block_number block tag for the batch improves head consistency vs scattered sequential calls; same RPC/chain trust model as pre-#307.
  • Failed multicall batches do not disable batching (retry + sequential fallback each cycle) — availability/efficiency only; sequential path reads the same contracts via the same RPC.
  • multicall3_anvil_bytecode.hex is unreferenced in scripts/code; Anvil bootstrap uses the mds1 signed deploy tx in anvil_multicall3.sh. The hex artifact is a minimal aggregate3-only stub (0x82ad56cb, revert Multicall3: call failed) — local-dev operator trust, not a production deploy path.
  • Display-oracle manipulation via malicious RPC or non-standard Multicall3 bytecode is pre-existing indexer trust on RPC_URL + registry addresses; this MR does not expand attacker-controlled sinks.

Inline threads: none (no medium+ findings).

Security review: no medium+ findings on this diff.

## Security review — MR !488 **Commit reviewed:** `c432cee3fe1b58dcce2f2cc87bad8963aaf0dd44` **Scope:** Post-merge diff vs `main` (4 files): benchmark artifacts (`docs/indexer/benchmarks/rpc-benchmark-20260614T053127Z.{json,md}`), `indexer/README.md` §307 note, `scripts/lib/multicall3_anvil_bytecode.hex`. Surrounding #307 paths on this SHA reviewed for exploitability: `indexer/src/multicall.rs`, `chain_timer.rs`, `sale_state.rs`, `scripts/lib/anvil_multicall3.sh` (merged from `main`; branch-only `MulticallRequest` probe / `anvil_setCode` path removed). **Method:** Diff review; traced batch inputs (operator-configured `TimeArena` / `PodiumVaults` + fixed selectors) through `aggregate3` encode/decode to `GET /v1/arena/timers` snapshot fields; verified Anvil bootstrap trust boundaries and committed bytecode surface. **Outcome:** **FINDINGS: 0** medium+ ### Notes (below severity threshold / not introduced exploit paths) - **Batch inputs are not user-controlled.** Sub-calls are hardcoded view selectors against registry addresses; no injection surface into SQL, shell, or HTTP handlers. - **`allowFailure: false` + per-subcall `success` checks** (`multicall.rs`) reject partial/malformed aggregate results; decode errors fail the poll and `poll_once` falls back to sequential reads — no silent field substitution. - **Single `read_block_number` block tag** for the batch improves head consistency vs scattered sequential calls; same RPC/chain trust model as pre-#307. - **Failed multicall batches do not disable batching** (retry + sequential fallback each cycle) — availability/efficiency only; sequential path reads the same contracts via the same RPC. - **`multicall3_anvil_bytecode.hex` is unreferenced** in scripts/code; Anvil bootstrap uses the mds1 signed deploy tx in `anvil_multicall3.sh`. The hex artifact is a minimal `aggregate3`-only stub (`0x82ad56cb`, revert `Multicall3: call failed`) — local-dev operator trust, not a production deploy path. - **Display-oracle manipulation** via malicious RPC or non-standard Multicall3 bytecode is pre-existing indexer trust on `RPC_URL` + registry addresses; this MR does not expand attacker-controlled sinks. **Inline threads:** none (no medium+ findings). Security review: **no medium+ findings** on this diff.
PlasticDigits commented 2026-06-14 07:11:20 +00:00 (Migrated from gitlab.com)

mentioned in commit bd2d20e94b

mentioned in commit bd2d20e94b93865a5ac7e9e393a8de7dac615618
PlasticDigits (Migrated from gitlab.com) merged commit bd2d20e94b into main 2026-06-14 07:11:20 +00:00
Sign in to join this conversation.
No reviewers
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!488
No description provided.