LAUNCH-BLOCKER: TimeCurve.sol exceeds EIP-170 24KB cap (28,454 bytes) — DeployDev fails on Anvil #72

Closed
opened 2026-04-27 02:46:31 +00:00 by Brouie · 10 comments
Brouie commented 2026-04-27 02:46:31 +00:00 (Migrated from gitlab.com)

Found Monday 2026-04-27 morning while attempting to verify #61 fix on live Anvil stack. Hard blocker for #61, #65, #66, #67, #71 verification AND mainnet deploy.

Repro

cd /srv/qa/repos/yieldomega
SKIP_ANVIL_RICH_STATE=1 bash scripts/start-local-anvil-stack.sh

Stack reaches === Deploy (DeployDev) === then exits 1. Per /tmp/yieldomega_deploy_dev.log:

Error: `TimeCurve` is above the contract size limit (28454 > 24576).

Direct measurement

forge build --optimizer-runs 1
jq '.deployedBytecode.object | length / 2 - 1' out/TimeCurve.sol/TimeCurve.json
# 28454

forge build --optimizer-runs 200
jq '.deployedBytecode.object | length / 2 - 1' out/TimeCurve.sol/TimeCurve.json
# 28783

Cap is 24,576. Overage is ~3,878 to 4,207 bytes depending on optimizer setting. --optimizer-runs 1 (used by scripts/start-local-anvil-stack.sh to fit local) doesn't help. Higher runs makes it slightly larger here.

Likely cause

contracts/src/TimeCurve.sol git history:

6d52ce6 fix(timecurve): opt-in WarBow flag plant on buy (GitLab #63)
d36cccb feat(contracts): TimeCurveBuyRouter + buyFor for single-tx Kumbaya buys
cf6fe19 feat(contracts): gate WarBow CL8Y burns on sale interactions (issue #55)
f2500ec feat(contracts): final signoff gates for DOUB claims and TimeCurve value (issue #55)
0048249 feat(contracts): UUPS + ERC1967Proxy for core routing (GitLab #54)

Most likely culprit is d36cccb adding buyFor (which TimeCurveBuyRouter calls) plus the surrounding storage / gate logic, with 6d52ce6 and cf6fe19 adding more on top. Sunday baseline (9a183b9 end of day) was probably already over but I didn't run a full stack on Sunday — only verified at source level for #55/#56. Forge tests pass (191/191) because they don't enforce EIP-170 (Anvil's --code-size-limit defaults disable it for tests).

Impact

  • #61 verification BLOCKED. 482a25a fix can't be tested because the deploy itself fails before the proxy address resolution code path even runs.
  • #65, #66, #67, #71 verification BLOCKED. Whole single-tx Kumbaya buy stack depends on a deployable TimeCurve.
  • #38, #39 still blocked (transitive).
  • MegaETH TGE April 30 = 3 days from now. Mainnet deploy fails the same way; EIP-170 is mainnet-enforced, not just an Anvil flag.

Mitigations the team may want to consider

  • Move TimeCurve sub-functions into libraries (external, delegatecall) — biggest typical EIP-170 fix
  • Use --code-size-limit Anvil flag for local testing as a stop-gap so QA can keep moving on #61, BUT this does not fix mainnet
  • Audit recent additions (buyFor, WarBow CL8Y gates, signoff flags) for inlining opportunities or shared internal helpers
  • Consider splitting TimeCurveBuyRouter integration so the router does more of the work and TimeCurve stays minimal

I'll wait for direction before re-running the stack — running with --code-size-limit Anvil flag would let me move on #61 verification, but I want to make sure that's the right call given mainnet timing.

cc @PlasticDigits

Found Monday 2026-04-27 morning while attempting to verify #61 fix on live Anvil stack. **Hard blocker for #61, #65, #66, #67, #71 verification AND mainnet deploy.** ## Repro ``` cd /srv/qa/repos/yieldomega SKIP_ANVIL_RICH_STATE=1 bash scripts/start-local-anvil-stack.sh ``` Stack reaches `=== Deploy (DeployDev) ===` then exits 1. Per `/tmp/yieldomega_deploy_dev.log`: ``` Error: `TimeCurve` is above the contract size limit (28454 > 24576). ``` ## Direct measurement ``` forge build --optimizer-runs 1 jq '.deployedBytecode.object | length / 2 - 1' out/TimeCurve.sol/TimeCurve.json # 28454 forge build --optimizer-runs 200 jq '.deployedBytecode.object | length / 2 - 1' out/TimeCurve.sol/TimeCurve.json # 28783 ``` Cap is 24,576. Overage is **~3,878 to 4,207 bytes** depending on optimizer setting. `--optimizer-runs 1` (used by `scripts/start-local-anvil-stack.sh` to fit local) doesn't help. Higher runs makes it slightly larger here. ## Likely cause `contracts/src/TimeCurve.sol` git history: ``` 6d52ce6 fix(timecurve): opt-in WarBow flag plant on buy (GitLab #63) d36cccb feat(contracts): TimeCurveBuyRouter + buyFor for single-tx Kumbaya buys cf6fe19 feat(contracts): gate WarBow CL8Y burns on sale interactions (issue #55) f2500ec feat(contracts): final signoff gates for DOUB claims and TimeCurve value (issue #55) 0048249 feat(contracts): UUPS + ERC1967Proxy for core routing (GitLab #54) ``` Most likely culprit is `d36cccb` adding `buyFor` (which TimeCurveBuyRouter calls) plus the surrounding storage / gate logic, with `6d52ce6` and `cf6fe19` adding more on top. Sunday baseline (`9a183b9` end of day) was probably already over but I didn't run a full stack on Sunday — only verified at source level for #55/#56. Forge tests pass (191/191) because they don't enforce EIP-170 (Anvil's `--code-size-limit` defaults disable it for tests). ## Impact - **#61 verification BLOCKED.** `482a25a` fix can't be tested because the deploy itself fails before the proxy address resolution code path even runs. - **#65, #66, #67, #71 verification BLOCKED.** Whole single-tx Kumbaya buy stack depends on a deployable TimeCurve. - **#38, #39 still blocked** (transitive). - **MegaETH TGE April 30 = 3 days from now.** Mainnet deploy fails the same way; EIP-170 is mainnet-enforced, not just an Anvil flag. ## Mitigations the team may want to consider - Move TimeCurve sub-functions into libraries (external, delegatecall) — biggest typical EIP-170 fix - Use `--code-size-limit` Anvil flag for local testing as a stop-gap so QA can keep moving on #61, BUT this **does not fix mainnet** - Audit recent additions (`buyFor`, WarBow CL8Y gates, signoff flags) for inlining opportunities or shared internal helpers - Consider splitting `TimeCurveBuyRouter` integration so the router does more of the work and TimeCurve stays minimal I'll wait for direction before re-running the stack — running with `--code-size-limit` Anvil flag would let me move on #61 verification, but I want to make sure that's the right call given mainnet timing. cc @PlasticDigits
Brouie commented 2026-04-27 02:55:14 +00:00 (Migrated from gitlab.com)

mentioned in issue #67

mentioned in issue #67
Brouie commented 2026-04-27 02:58:46 +00:00 (Migrated from gitlab.com)

mentioned in issue #63

mentioned in issue #63
Brouie commented 2026-04-27 03:00:54 +00:00 (Migrated from gitlab.com)

@PlasticDigits good catch on the MegaETH 512 KB limit — appreciated.

Reframing #72: this is not a mainnet launch-blocker, it's a local-Anvil-only verification block. TimeCurve at 28,454 bytes is well under MegaETH's 524,288 byte cap.

What's needed is just the Anvil --code-size-limit flag in scripts/start-local-anvil-stack.sh (and likely contracts/script/anvil_rich_state.sh) so local DeployDev matches MegaETH semantics. Mainnet deploy is unaffected.

Dropping the LAUNCH-BLOCKER label framing — happy for you to relabel as 'local-stack tooling fix' or similar. Apologies for the alarm — should have thought of MegaETH's raised limit before filing as LB.

Standing by for the Anvil flag fix; will resume #61 / #65 / #66 / #67 / #71 verification on the live stack as soon as deploy goes through.

@PlasticDigits good catch on the MegaETH 512 KB limit — appreciated. Reframing #72: this is **not** a mainnet launch-blocker, it's a **local-Anvil-only** verification block. TimeCurve at 28,454 bytes is well under MegaETH's 524,288 byte cap. What's needed is just the Anvil --code-size-limit flag in scripts/start-local-anvil-stack.sh (and likely contracts/script/anvil_rich_state.sh) so local DeployDev matches MegaETH semantics. Mainnet deploy is unaffected. Dropping the LAUNCH-BLOCKER label framing — happy for you to relabel as 'local-stack tooling fix' or similar. Apologies for the alarm — should have thought of MegaETH's raised limit before filing as LB. Standing by for the Anvil flag fix; will resume #61 / #65 / #66 / #67 / #71 verification on the live stack as soon as deploy goes through.
PlasticDigits commented 2026-04-27 03:07:24 +00:00 (Migrated from gitlab.com)

Implemented in 21a4d5c (main): Anvil in scripts/start-local-anvil-stack.sh now passes --code-size-limit 0x6000 (EIP-170 / MegaETH–mainnet parity). contracts/script/anvil_rich_state.sh documents the same requirement when the RPC is started manually. Mainnet deploy is unchanged.

Implemented in `21a4d5c` (main): Anvil in `scripts/start-local-anvil-stack.sh` now passes `--code-size-limit 0x6000` (EIP-170 / MegaETH–mainnet parity). `contracts/script/anvil_rich_state.sh` documents the same requirement when the RPC is started manually. Mainnet deploy is unchanged.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-04-27 03:07:27 +00:00
PlasticDigits commented 2026-04-27 03:10:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 49cdad4e89

mentioned in commit 49cdad4e89fe0f3f5b25343250929ae24df332fd
PlasticDigits commented 2026-04-27 03:10:37 +00:00 (Migrated from gitlab.com)

@Brouie Resolution: the “above EIP-170 24 KiB” failure on default Anvil does not imply a MegaETH mainnet deploy blocker.

MegaEVM limits (authoritative): Contract limits — 524,288 bytes (512 KiB) max deployed runtime bytecode; 548,864 bytes (536 KiB) max initcode (`MAX_CONTRACT_SIZE` + `ADDITIONAL_INITCODE_SIZE`).

Nested calls: MegaEVM uses 98/100 gas forwarding to child frames (stricter depth attenuation than Ethereum’s 63/64), documented here: Gas forwarding.

Repo check (from current `contracts/out/*.json` after `forge build`, commit `49cdad4`): TimeCurve ~11,168 B deployed, RabbitTreasury ~11,077 B — orders of magnitude under 512 KiB. Re-verify anytime with `cd contracts && forge build --sizes`.

Docs updated in main: `docs/contracts/foundry-and-megaeth.md` (MegaEVM vs EIP-170 / Anvil, verification commands, gas forwarding), `contracts/README.md`, `docs/research/megaeth.md`, test map `docs/testing/invariants-and-business-logic.md`, `skills/README.md`, contributor guardrail `.cursor/skills/yieldomega-guardrails/SKILL.md`.

Checklist for you: (1) Re-run local stack; if Anvil still rejects bytecode, raise `anvil --code-size-limit` or treat as L1-style tooling only. (2) Confirm MegaETH RPC `eth_estimateGas` on deep composer txs (Kumbaya + `buyFor`) given 98/100 forwarding. (3) Skim Contract limits if limits change in a future network upgrade.

Closing as invalid for MegaETH launch (environment mismatch: EIP-170 / Anvil vs MegaEVM limits); reopen if we add an Ethereum L1 deployment target where EIP-170 matters.

@Brouie **Resolution:** the “above EIP-170 24 KiB” failure on **default Anvil** does **not** imply a **MegaETH** mainnet deploy blocker. **MegaEVM limits** (authoritative): [Contract limits](https://docs.megaeth.com/spec/megaevm/contract-limits) — **524,288 bytes** (512 KiB) max **deployed** runtime bytecode; **548,864 bytes** (536 KiB) max **initcode** (\`MAX_CONTRACT_SIZE\` + \`ADDITIONAL_INITCODE_SIZE\`). **Nested calls:** MegaEVM uses **98/100** gas forwarding to child frames (stricter depth attenuation than Ethereum’s **63/64**), documented here: [Gas forwarding](https://docs.megaeth.com/spec/megaevm/gas-forwarding.md). **Repo check** (from current \`contracts/out/*.json\` after \`forge build\`, commit \`49cdad4\`): **TimeCurve** ~**11,168** B deployed, **RabbitTreasury** ~**11,077** B — orders of magnitude under **512 KiB**. Re-verify anytime with \`cd contracts && forge build --sizes\`. **Docs updated in main:** \`docs/contracts/foundry-and-megaeth.md\` (MegaEVM vs EIP-170 / Anvil, verification commands, gas forwarding), \`contracts/README.md\`, \`docs/research/megaeth.md\`, test map \`docs/testing/invariants-and-business-logic.md\`, \`skills/README.md\`, contributor guardrail \`.cursor/skills/yieldomega-guardrails/SKILL.md\`. **Checklist for you:** (1) Re-run local stack; if Anvil still rejects bytecode, raise \`anvil --code-size-limit\` or treat as **L1-style tooling** only. (2) Confirm MegaETH RPC \`eth_estimateGas\` on deep composer txs (Kumbaya + \`buyFor\`) given **98/100** forwarding. (3) Skim [Contract limits](https://docs.megaeth.com/spec/megaevm/contract-limits) if limits change in a future network upgrade. Closing as **invalid for MegaETH launch** (environment mismatch: EIP-170 / Anvil vs MegaEVM limits); reopen if we add an **Ethereum L1** deployment target where EIP-170 matters.
PlasticDigits commented 2026-04-27 03:14:40 +00:00 (Migrated from gitlab.com)

Update: Local Anvil in scripts/start-local-anvil-stack.sh now uses --code-size-limit 0x80000 (512 KiB = 524288 bytes), matching MegaEVM max deployed bytecode instead of the previous EIP-170 0x6000 (24576 bytes). contracts/script/anvil_rich_state.sh comments aligned.

Landed in commit on main (anvil 512 KiB code size fix).

**Update:** Local Anvil in `scripts/start-local-anvil-stack.sh` now uses `--code-size-limit 0x80000` (512 KiB = 524288 bytes), matching MegaEVM max deployed bytecode instead of the previous EIP-170 `0x6000` (24576 bytes). `contracts/script/anvil_rich_state.sh` comments aligned. Landed in commit on `main` (anvil 512 KiB code size fix).
Brouie commented 2026-04-27 04:03:42 +00:00 (Migrated from gitlab.com)

mentioned in issue #75

mentioned in issue #75
PlasticDigits commented 2026-05-27 07:07:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #259

mentioned in issue #259
PlasticDigits commented 2026-06-01 12:58:55 +00:00 (Migrated from gitlab.com)

mentioned in commit 77bbb5429f

mentioned in commit 77bbb5429fcf204b6b52a42f5a974e52ec23d511
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#72
No description provided.