Skip to content

feat: remove enableE3Program onlyOwner modifier#1421

Merged
hmzakhalid merged 3 commits into
mainfrom
feat/remove-e3-oo-modifier
Mar 13, 2026
Merged

feat: remove enableE3Program onlyOwner modifier#1421
hmzakhalid merged 3 commits into
mainfrom
feat/remove-e3-oo-modifier

Conversation

@hmzakhalid

@hmzakhalid hmzakhalid commented Mar 13, 2026

Copy link
Copy Markdown
Collaborator

This PR makes enableE3Program permissionless so anyone can register an E3 program. We want to let people use E3s without needing the protocol owner to whitelist their program first. The encryption scheme registry (decryptionVerifiers) remains owner-gated, which is the real security boundary, a permissionlessly registered E3 program still can't introduce new encryption schemes or verifiers.

There are two places where we call into a (now-untrusted) E3 program:

1. request() -> e3Program.validate()

If validate() tries to re-enter:

  • Re-enter request(): Gets a new e3Id, has to pay a new fee. Just creates an independent E3, no harm done.
  • Re-enter publishCiphertextOutput / publishPlaintextOutput: Stage is Requested, both require later stages (KeyPublished / CiphertextReady), so it'll reverts.
  • Re-enter markE3Failed: Calls getCommitteeDeadline(e3Id) on the registry, but the committee hasn't been requested yet (requestCommittee runs after validate), so the registry reverts with CommitteeNotRequested.
  • Re-enter processE3Failure: Stage is Requested, not Failed -> reverts.

The fee transfer before validate() is important, it means even with an ERC-777-style callback token, you can't create E3s without paying.

2. publishCiphertextOutput() -> e3Program.verify()

The ciphertextOutput hash is written to storage before calling verify(). If verify() re-enters publishCiphertextOutput for the same E3, the ciphertextOutput == bytes32(0) check sees the already-written value and reverts with CiphertextOutputAlreadyPublished. Stage hasn't advanced yet so no other function accepts this E3 either.

Risk

Anyone can spam enableE3Program to pollute the mapping (costs only gas). A malicious program could grief ciphernodes by creating junk E3s, but the attacker still pay E3 fee per request and ciphernodes get paid if the E3 completes. Owner can always disableE3Program to revoke bad actors.

Summary by CodeRabbit

  • Changes
    • E3 program enablement is now publicly callable; E3 request, publish, and completion flows have improved initialization, fee handling, and lifecycle ordering for more consistent behavior.
  • Tests
    • Test suite updated to reflect the relaxed access control for enabling E3 programs (non-owner revert test removed).

@vercel

vercel Bot commented Mar 13, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
crisp Skipped Skipped Mar 13, 2026 2:48pm
enclave-docs Skipped Skipped Mar 13, 2026 2:48pm

Request Review

@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5836631d-ac64-4bfc-ae88-d1b1a9c7216b

📥 Commits

Reviewing files that changed from the base of the PR and between bd251b0 and 2d4f388.

📒 Files selected for processing (1)
  • packages/enclave-contracts/contracts/Enclave.sol

📝 Walkthrough

Walkthrough

Removed the onlyOwner modifier from enableE3Program and reordered/centralized E3 lifecycle initialization and fee handling in request(). Adjusted lifecycle stage transitions in output publishing. Updated Rust ABI binding, tests, and several Solidity artifact metadata entries.

Changes

Cohort / File(s) Summary
Enclave contract (logic & access)
packages/enclave-contracts/contracts/Enclave.sol
Removed onlyOwner from enableE3Program (now public). Reordered request() to initialize per-E3 state and fee data earlier, moved fee transfer after request context setup, removed duplicated initializations, and set lifecycle stages earlier in publish methods.
Rust contract bindings
crates/evm-helpers/src/contracts.rs
Updated Enclave contract binding to reflect removal of the onlyOwner modifier in enableE3Program (ABI/signature adjusted accordingly).
Tests
packages/enclave-contracts/test/Enclave.spec.ts
Removed the test that expected enableE3Program to revert for non-owners; other enableE3Program tests retained.
Build artifacts / verifier metadata
packages/enclave-contracts/artifacts/.../IBondingRegistry.json, .../ICiphernodeRegistry.json, .../IEnclave.json, .../ISlashingManager.json, .../DkgPkVerifier.json, .../ZKTranscriptLib.json
Updated Solidity buildInfoId values across multiple artifact JSONs. DkgPkVerifier.json also remapped/expanded immutableReferences entries.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller as Caller (EOA)
participant Enclave as Enclave Contract
participant FeeToken as FeeToken (ERC20)
participant E3Prog as E3Program (contract)
Caller->>Enclave: request(e3Params, fee, feeToken)
Enclave-->>Enclave: allocate e3Id; set _e3Stages[e3Id]=Requested\n_e3Requesters[e3Id]=msg.sender\ncomputeDeadline = inputWindow[1]+computeWindow\nstore fee arrays
Caller->>FeeToken: approve/allowance (pre-step)
Enclave->>FeeToken: safeTransferFrom(msg.sender, feeReceiver, fee)
Enclave->>E3Prog: optional validation/instantiate e3Program.verify(...)
Enclave-->>Caller: emit RequestCreated / return e3Id

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ryardley
  • auryn-macmillan
  • nginnever

Poem

"I'm a rabbit in the dev wood, nose aglow,
I nudged a lock, now E3s may grow,
Fees set early, stages aligned,
Tests trimmed back, artifacts signed —
Hop, compile, and onward we go!" 🐇

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing the onlyOwner modifier from the enableE3Program function, which is the primary feature change in this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/remove-e3-oo-modifier
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

ctrlc03
ctrlc03 previously approved these changes Mar 13, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/enclave-contracts/contracts/Enclave.sol (1)

636-643: Harden permissionless registration with basic address validation.

Line 636 currently allows enabling zero-address/EOA entries, which can pollute the program registry with unusable targets. Add minimal guards before mutating e3Programs.

Suggested patch
 function enableE3Program(IE3Program e3Program) public {
+        require(
+            address(e3Program) != address(0) &&
+                address(e3Program).code.length > 0,
+            "Invalid E3 program"
+        );
         require(
             !e3Programs[e3Program],
             ModuleAlreadyEnabled(address(e3Program))
         );
         e3Programs[e3Program] = true;
         emit E3ProgramEnabled(e3Program);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/enclave-contracts/contracts/Enclave.sol` around lines 636 - 643, The
enableE3Program function currently allows zero-address or EOA entries into the
e3Programs mapping; add a guard before mutating e3Programs to require
address(e3Program) != address(0) and that the target is a contract (use
Address.isContract(address(e3Program)) or equivalent code size check) to reject
EOAs and the zero address; keep the existing ModuleAlreadyEnabled check and then
set e3Programs[e3Program] = true and emit E3ProgramEnabled(e3Program).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/evm-helpers/src/contracts.rs`:
- Line 128: The ABI declaration for enableE3Program incorrectly includes a
return value; remove the "returns (bool success)" clause from the function
signature in the contracts ABI so it matches the Solidity implementation and
interface (function enableE3Program(address e3Program) public;), which prevents
ABI decode mismatches when calling enableE3Program from bindings; update the
function signature in the same file (contracts.rs) where enableE3Program is
declared and ensure any generated bindings are re-derived if applicable.

---

Nitpick comments:
In `@packages/enclave-contracts/contracts/Enclave.sol`:
- Around line 636-643: The enableE3Program function currently allows
zero-address or EOA entries into the e3Programs mapping; add a guard before
mutating e3Programs to require address(e3Program) != address(0) and that the
target is a contract (use Address.isContract(address(e3Program)) or equivalent
code size check) to reject EOAs and the zero address; keep the existing
ModuleAlreadyEnabled check and then set e3Programs[e3Program] = true and emit
E3ProgramEnabled(e3Program).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f2d32632-3dba-4c3b-8736-48d10cb99f0b

📥 Commits

Reviewing files that changed from the base of the PR and between 6bcf88c and 2b6cea0.

📒 Files selected for processing (9)
  • crates/evm-helpers/src/contracts.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/ISlashingManager.sol/ISlashingManager.json
  • packages/enclave-contracts/artifacts/contracts/verifier/DkgPkVerifier.sol/DkgPkVerifier.json
  • packages/enclave-contracts/artifacts/contracts/verifier/DkgPkVerifier.sol/ZKTranscriptLib.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/test/Enclave.spec.ts
💤 Files with no reviewable changes (1)
  • packages/enclave-contracts/test/Enclave.spec.ts

Comment thread crates/evm-helpers/src/contracts.rs
@vercel vercel Bot temporarily deployed to Preview – crisp March 13, 2026 11:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – enclave-docs March 13, 2026 11:40 Inactive

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/enclave-contracts/contracts/Enclave.sol (1)

634-641: ⚠️ Potential issue | 🟠 Major

Public enable currently nullifies owner disable controls.

With Line 634 permissionless and disableE3Program still owner-only, any account can immediately re-enable a program after owner disable. That removes practical quarantine capability for compromised programs.

Admin-veto pattern that preserves permissionless registration
+    mapping(IE3Program e3Program => bool blocked) public e3ProgramBlocked;
+    error ModuleBlocked(address module);
+
     function enableE3Program(IE3Program e3Program) public {
+        require(!e3ProgramBlocked[e3Program], ModuleBlocked(address(e3Program)));
         require(
             !e3Programs[e3Program],
             ModuleAlreadyEnabled(address(e3Program))
         );
         e3Programs[e3Program] = true;
         emit E3ProgramEnabled(e3Program);
     }

     function disableE3Program(IE3Program e3Program) public onlyOwner {
         require(e3Programs[e3Program], ModuleNotEnabled(address(e3Program)));
         delete e3Programs[e3Program];
+        e3ProgramBlocked[e3Program] = true;
         emit E3ProgramDisabled(e3Program);
     }
+
+    function unblockE3Program(IE3Program e3Program) external onlyOwner {
+        e3ProgramBlocked[e3Program] = false;
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/enclave-contracts/contracts/Enclave.sol` around lines 634 - 641, The
enableE3Program function is public which allows any account to re-enable an E3
program even after the owner has disabled it; add an owner-veto check so
permissionless registration remains allowed for new programs but re-enabling a
program that was disabled/quarantined requires owner authorization. Concretely,
introduce or reuse a quarantine/disabled marker (e.g., a mapping like
e3ProgramQuarantined or consult disableE3Program state) and update
enableE3Program to permit setting e3Programs[e3Program]=true unconditionally
only if the program has never been disabled, otherwise require onlyOwner before
flipping it back on; keep the E3ProgramEnabled event and ensure disableE3Program
still sets the quarantine marker so the owner can veto re-enables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/enclave-contracts/contracts/Enclave.sol`:
- Around line 332-343: The code persists E3 lifecycle/payment state
(e3Payments[e3Id], _e3FeeTokens[e3Id], _e3Stages[e3Id], _e3Requesters[e3Id],
_e3Deadlines[e3Id]) before making external calls feeToken.safeTransferFrom and
e3Program.validate, creating a reentrancy risk; reorder to follow
Checks-Effects-Interactions: perform all external interactions (call
feeToken.safeTransferFrom and e3Program.validate) first, handle their
return/require results, then write the persistent state (assign e3Payments,
_e3FeeTokens, _e3Stages, _e3Requesters, _e3Deadlines.computeDeadline) only after
those calls succeed, or alternatively add a reentrancy guard around the function
if state must be set earlier; reference the variables/functions above when
making the changes.

---

Outside diff comments:
In `@packages/enclave-contracts/contracts/Enclave.sol`:
- Around line 634-641: The enableE3Program function is public which allows any
account to re-enable an E3 program even after the owner has disabled it; add an
owner-veto check so permissionless registration remains allowed for new programs
but re-enabling a program that was disabled/quarantined requires owner
authorization. Concretely, introduce or reuse a quarantine/disabled marker
(e.g., a mapping like e3ProgramQuarantined or consult disableE3Program state)
and update enableE3Program to permit setting e3Programs[e3Program]=true
unconditionally only if the program has never been disabled, otherwise require
onlyOwner before flipping it back on; keep the E3ProgramEnabled event and ensure
disableE3Program still sets the quarantine marker so the owner can veto
re-enables.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ee1e23c-0ab1-4eab-bfeb-ea88de6e95ef

📥 Commits

Reviewing files that changed from the base of the PR and between 2b6cea0 and bd251b0.

📒 Files selected for processing (1)
  • packages/enclave-contracts/contracts/Enclave.sol

Comment thread packages/enclave-contracts/contracts/Enclave.sol
@vercel vercel Bot temporarily deployed to Preview – enclave-docs March 13, 2026 14:48 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp March 13, 2026 14:48 Inactive
@hmzakhalid hmzakhalid merged commit 1cd8ae0 into main Mar 13, 2026
27 checks passed
@github-actions github-actions Bot deleted the feat/remove-e3-oo-modifier branch March 21, 2026 03:07
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.

2 participants