Skip to content

feat(edsl): add uint8-backed enum support - #2248

Open
Th0rgal wants to merge 5 commits into
mainfrom
feat/enum-support-2088
Open

feat(edsl): add uint8-backed enum support#2248
Th0rgal wants to merge 5 commits into
mainfrom
feat/enum-support-2088

Conversation

@Th0rgal

@Th0rgal Th0rgal commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

  • add enum declarations, enum-aware macro types, member constants, and checked EnumName(x) casts
  • erase enums to uint8 throughout ABI/compiler paths while supporting params, returns, storage, mappings, events, and errors
  • reject out-of-range enum entrypoint values with Solidity panic 0x21, and reject implicit raw numeric literals where an enum is required
  • add Lean smoke coverage plus generated property and Foundry differential tests

Closes #2088.

Base and dependency audit

Targets live main at 4369b1dfbc42c65ceb76a668f748e9336f0d948f. Narrow integer support from #2240 is already merged. Open PRs #2245, #2247, #2249, and #2250 remain independent and were not rebased, modified, or merged.

Exact-head validation

Validated on CPU at exact head f448cc50d65ddd2182dbe89001a81bd005a0b939:

  • lake build Contracts.Smoke.EnumFeatureTest — pass (includes member constants, ABI erasure, checked cast, storage/mapping, event/error, and invalid enum parameter regressions)
  • make checks — pass (641 Python tests; generated artifacts current; zero source axioms or sorry)
  • EVMYulLean fork audit/native report plus bridge lemmas, bridge test, native harness, and Compiler.Proofs.EndToEnd — pass
  • lake build Compiler.ModuleInputTest Compiler.CompileDriverTest — pass
  • lake build PrintAxioms Compiler — pass
  • combined lake build PrintAxioms Compiler Contracts compiled all requested modules (Contracts, Compiler, and PrintAxioms each built), then exited on the repository's existing aggregate library-collection diagnostic: Contracts: some modules have bad imports
  • git diff --check — pass

Foundry/solc are not installed in this local environment. test/EnumFeature.t.sol includes solc differential coverage for valid and out-of-range casts, enum params/returns, storage, and mappings; the exact-head PR CI Foundry jobs are the execution gate.

No merge is requested; Phase 2 exact-head self-review/merge remains separate after CI.


Note

Medium Risk
Touches macro parsing, compilation model, and ABI lowering across many contract surfaces; incorrect range or erasure behavior could change on-chain encoding or revert semantics, though smoke and differential tests cover the main paths.

Overview
Adds native enum declarations via an enums block on verity_contract, with ordered members, Enum.Member constants, and checked EnumName(x) casts. Enums are modeled as word-like types but ABI-erase to uint8 across JSON ABI, Solidity signatures, interfaces, events, and custom errors; function/constructor enum inputs use a __verity_enum param wrapper so calldata stays uint8 while the runtime still sees a full word for validation.

The macro path wires enums through storage scalars and mappings (including chained keys), type checking on writes, translation to setStorage / mapping IR, and injected entrypoint guards that revert with panic 0x21 when a value is out of range; nested enum parameters in composites are rejected. Supporting tweaks include revertPanicAs for panics in expression-valued bodies, ident(...) call syntax for enum cast lowering, frame predicates for enum-valued mappings, and generated Foundry/property tests plus parity doc updates.

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

@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
verity Ready Ready Preview Aug 9, 2026 5:55pm

Request Review

@Th0rgal
Th0rgal marked this pull request as ready for review August 9, 2026 17:19
@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_877ff25a-7097-4a3a-b62b-859422de00bc)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30ec7fb761

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Verity/Macro/Translate/Expr.lean
Comment thread Verity/Macro/Translate.lean
Comment thread Verity/Macro/Storage.lean
@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e23cc544-18b2-46f6-9d74-869a829e1376)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenCodeReview first-pass review

🟡 Scout triage only — not a full review. no findings; a human or Codex must still cover the unflagged hunks and proof obligations.

Lean packet budget exceeded: 14 Lean file(s), 666 changed supported line(s).

Warnings

  • routing : Diff exceeded bounded packet review capability; full OCR not attempted.
OCR pilot metrics & packet coverage

OCR pilot metrics

  • Routing: large-lean-hotspots (router-v10)
  • Changed files: 21 supported / 21 total; Lean 14, trust docs 0, workflow/scripts 3, contracts 2, docs 2
  • Changed lines: 666 supported; thresholds large Lean >=3 files or >800 lines
  • OCR: status large-lean-hotspots; comments 0; files 0; tokens 0; tool calls 0; warnings 1; duration 0s
  • Largest changed files: Verity/Macro/Translate.lean (+119/-33), Contracts/Smoke/EnumFeatureTest.lean (+92/-0), artifacts/macro_property_tests/PropertyMacroEnumUsage.t.sol (+81/-0), Verity/Macro/Translate/Expr.lean (+51/-22), test/EnumFeature.t.sol (+62/-0)

Packet coverage

  • Packet review: not used; selected 0/8 packet(s)
  • Scout: configured; status skipped_no_packets; model builtin/assistant
  • Scout lenses: provenance, verification-independence, environment-determinism, proof-soundness; rubric items checked 3
  • Strong review: required; status blocked_packet_input
  • Residual risk: Diff exceeded packet budget; use top changed files and deterministic signals as required Codex/human review checklist.
  • Strong packet-review blocker: OpenCodeReview 1.7.9 supports --from/--to full diff ranges, but this workflow does not have a safe packet/window input bridge for Lean hunks yet.

Pilot mode: advisory only. Codex Review remains the merge gate.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd1eec43e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Compiler/CompilationModel/AbiHelpers.lean
Comment thread Verity/Macro/Translate.lean
Comment thread Verity/Macro/Translate.lean Outdated
Comment thread Verity/Macro/Translate.lean
@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_43bfdf7f-5d09-4328-9c33-c88014c7971f)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenCodeReview first-pass review

🟡 Scout triage only — not a full review. no findings; a human or Codex must still cover the unflagged hunks and proof obligations.

Lean packet budget exceeded: 14 Lean file(s), 673 changed supported line(s).

Warnings

  • routing : Diff exceeded bounded packet review capability; full OCR not attempted.
OCR pilot metrics & packet coverage

OCR pilot metrics

  • Routing: large-lean-hotspots (router-v10)
  • Changed files: 21 supported / 21 total; Lean 14, trust docs 0, workflow/scripts 3, contracts 2, docs 2
  • Changed lines: 673 supported; thresholds large Lean >=3 files or >800 lines
  • OCR: status large-lean-hotspots; comments 0; files 0; tokens 0; tool calls 0; warnings 1; duration 0s
  • Largest changed files: Verity/Macro/Translate.lean (+126/-34), Contracts/Smoke/EnumFeatureTest.lean (+94/-0), artifacts/macro_property_tests/PropertyMacroEnumUsage.t.sol (+81/-0), Verity/Macro/Translate/Expr.lean (+48/-22), test/EnumFeature.t.sol (+62/-0)

Packet coverage

  • Packet review: not used; selected 0/8 packet(s)
  • Scout: configured; status skipped_no_packets; model builtin/assistant
  • Scout lenses: provenance, verification-independence, environment-determinism, proof-soundness; rubric items checked 3
  • Strong review: required; status blocked_packet_input
  • Residual risk: Diff exceeded packet budget; use top changed files and deterministic signals as required Codex/human review checklist.
  • Strong packet-review blocker: OpenCodeReview 1.7.9 supports --from/--to full diff ranges, but this workflow does not have a safe packet/window input bridge for Lean hunks yet.

Pilot mode: advisory only. Codex Review remains the merge gate.

@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_0716b10c-5b62-4cd6-b3b4-8dc3f0c4d1f8)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenCodeReview first-pass review

🟡 Scout triage only — not a full review. no findings; a human or Codex must still cover the unflagged hunks and proof obligations.

Lean packet budget exceeded: 15 Lean file(s), 711 changed supported line(s).

Warnings

  • routing : Diff exceeded bounded packet review capability; full OCR not attempted.
OCR pilot metrics & packet coverage

OCR pilot metrics

  • Routing: large-lean-hotspots (router-v10)
  • Changed files: 22 supported / 22 total; Lean 15, trust docs 0, workflow/scripts 3, contracts 2, docs 2
  • Changed lines: 711 supported; thresholds large Lean >=3 files or >800 lines
  • OCR: status large-lean-hotspots; comments 0; files 0; tokens 0; tool calls 0; warnings 1; duration 0s
  • Largest changed files: Verity/Macro/Translate.lean (+160/-37), Contracts/Smoke/EnumFeatureTest.lean (+94/-0), artifacts/macro_property_tests/PropertyMacroEnumUsage.t.sol (+81/-0), Verity/Macro/Translate/Expr.lean (+48/-22), test/EnumFeature.t.sol (+62/-0)

Packet coverage

  • Packet review: not used; selected 0/8 packet(s)
  • Scout: configured; status skipped_no_packets; model builtin/assistant
  • Scout lenses: provenance, verification-independence, environment-determinism, proof-soundness; rubric items checked 3
  • Strong review: required; status blocked_packet_input
  • Residual risk: Diff exceeded packet budget; use top changed files and deterministic signals as required Codex/human review checklist.
  • Strong packet-review blocker: OpenCodeReview 1.7.9 supports --from/--to full diff ranges, but this workflow does not have a safe packet/window input bridge for Lean hunks yet.

Pilot mode: advisory only. Codex Review remains the merge gate.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb5bbc1681

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

| .uint256 | .int256 | .uint8 | .uint16 | .uintN _ | .intN _ | .bytesN _
| .address | .bytes32 => true
| .newtype _ baseType => isWordLikeValueType baseType
| .enum _ _ => true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce exact enum types before storage writes

Fresh evidence beyond the stated storage-write fix is that requireDeclaredValueType accepts any pair of word-like types, and this new branch classifies enums as word-like. Consequently the added checks around setStorage, mapping writes, and struct-member writes still accept a numeric literal or a value from another enum, allowing invalid enum words to be persisted. Use an enum-specific exact-type check rather than the generic word-like compatibility rule.

Useful? React with 👍 / 👎.

`(Compiler.CompilationModel.Expr.bitAnd $expr
(Compiler.CompilationModel.Expr.literal $(natTerm mask)))
| .newtype _ baseType => normalizeTranslatedExprForType baseType source expr
| .enum _ _ => `(Compiler.CompilationModel.Expr.bitAnd $expr (Compiler.CompilationModel.Expr.literal 255))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject raw values assigned to enum locals

When a mutable local is initialized from an enum and later assigned a raw word, such as let mut value := Status.Active; value := 999, assignment validation only infers the RHS type and this normalization silently turns it into 999 & 255 = 231. The local remains semantically typed as Status, so it can subsequently pass the enum storage-write checks even though a three-member enum has no member 231. Require an exact enum RHS or a checked enum cast instead of byte-masking arbitrary assignments.

Useful? React with 👍 / 👎.

| .newtype name baseType => do
let baseTerm ← modelParamTypeTerm baseType
`([Compiler.CompilationModel.ParamType.newtypeOf $(Lean.quote name) $baseTerm])
| .enum _ _ => `([Compiler.CompilationModel.ParamType.uint8])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate expressions returned as enums

A function declared to return an enum can currently use return 999, because return-expression validation merely infers the expression and never compares it with the declared return type, while the executable enum type is erased to Uint256. This line nevertheless advertises the result as ABI uint8, and Stmt.return emits the raw word without normalization, so callers receive noncanonical ABI data; an internal helper can also have that result treated as the enum and store it. Require the returned expression to have the exact enum type, obtainable through a checked cast or member constant.

Useful? React with 👍 / 👎.

Comment on lines +2799 to +2800
private def guardEnumParams (fn : FunctionDecl) : CommandElabM FunctionDecl := do
pure { fn with body := ← prependEnumGuards fn.params fn.body }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Run enum calldata guards before function preludes

Injecting the enum guard into fn.body does not make it the first executed statement: translateBodyToStmtTerms prepends initializer, role, and modifier statements before the translated body. Thus an out-of-range enum call to an annotated function can execute a modifier or fail an authorization/initializer check instead of immediately producing Solidity panic 0x21, unlike ABI decoding before function entry. Place the range guard at the dispatch boundary or before all generated function preludes.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(EDSL): enum support (uint8-backed with range checks)

1 participant