Skip to content

Espresso 1: Contracts#443

Draft
QuentinI wants to merge 10 commits into
celo-org:celo-rebase-17from
EspressoSystems:ag/contracts
Draft

Espresso 1: Contracts#443
QuentinI wants to merge 10 commits into
celo-org:celo-rebase-17from
EspressoSystems:ag/contracts

Conversation

@QuentinI
Copy link
Copy Markdown

@QuentinI QuentinI commented May 7, 2026

This PR pulls in the BatchAuthenticator part of Espresso integration at packages/contracts-bedrock/src/L1/BatchAuthenticator.sol. All other changes are deployment scripts, tests, and other wiring.

BatchAuthenticator is the contract that the batchers will have to authenticate their batches with; corresponding changes for the derivation pipeline and batchers forthcoming as subsequent PRs.

@QuentinI QuentinI force-pushed the ag/contracts branch 2 times, most recently from 4bc5939 to cbd97f9 Compare May 8, 2026 00:42
Adds the Espresso-introduced contracts and the minimum supporting changes
required for them to compile, test, and pass the contract checks.

New contracts and scripts:

- src/L1/BatchAuthenticator.sol and interfaces/L1/IBatchAuthenticator.sol
  (upgradeable contract that authenticates batch transactions, with switching
  between Espresso and fallback batchers)
- scripts/deploy/DeployBatchAuthenticator.s.sol and
  scripts/deploy/DeployEspresso.s.sol
- test/L1/BatchAuthenticator.t.sol and test/mocks/MockEspressoTEEVerifiers.sol
- snapshots/{abi,storageLayout}/BatchAuthenticator.json
- snapshots/semver-lock.json entry for BatchAuthenticator

New submodules:

- lib/espresso-tee-contracts (interfaces required by BatchAuthenticator)
- lib/openzeppelin-contracts-upgradeable-v5 (OZ v5 used by BatchAuthenticator
  via OwnableUpgradeable)

Supporting changes (Espresso-driven):

- foundry.toml: remappings for OZ v5 and espresso-tee-contracts; ignored
  warning codes for vendored libs; OOM-safe jobs settings; via-ir profile.
- justfile: fix-proxy-artifact recipe to handle OZ v5 shadowing Proxy/ProxyAdmin
  artifacts; build/coverage hooks.
- src/universal/Proxy.sol, src/universal/ProxyAdmin.sol: pin pragma to exact
  0.8.15 so they stay in their own compilation group and never emit PUSH0.
- src/universal/ReinitializableBase.sol: loosen pragma to ^0.8.15 so
  BatchAuthenticator (compiled with OZ v5) can import it.
- scripts/* and test/*: disambiguate Proxy artifact lookups to
  src/universal/Proxy.sol:Proxy (avoids OZ v5 proxy/Proxy.sol shadow).
- scripts/checks: bypass interface checks for artifacts originating from lib/;
  add Espresso-related contract names to exclude lists; pragma exclusions for
  Proxy/ProxyAdmin/BatchAuthenticator.
- test/vendor/Initializable.t.sol: exclude BatchAuthenticator (deployed by a
  separate Espresso script).

Co-authored-by: OpenCode <noreply@opencode.ai>
@QuentinI QuentinI changed the title [WIP] Espresso Contracts Espresso 1: Contracts May 8, 2026
@jcortejoso
Copy link
Copy Markdown
Member

@codex review

@jcortejoso jcortejoso requested a review from piersy May 11, 2026 14:12
Copy link
Copy Markdown

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

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: ee2d984108

ℹ️ 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 packages/contracts-bedrock/scripts/deploy/DeployEspresso.s.sol
Comment thread packages/contracts-bedrock/test/mocks/MockEspressoTEEVerifiers.sol Outdated
Comment thread packages/contracts-bedrock/test/L1/BatchAuthenticator.t.sol Outdated
Comment thread packages/contracts-bedrock/foundry.toml Outdated
vm.prank(proxyAdminOwner);
authenticator.switchBatcher();
assertFalse(authenticator.activeIsEspresso());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The tests currently seem to be missing tests of batch authentication behaviour when running in fallback mode and also a test of authentication behaviour when in fallback and paused.

I've added two tests which I think covers these cases in this commit 5d0a803

Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
@@ -0,0 +1,287 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
Copy link
Copy Markdown

@Mc01 Mc01 May 20, 2026

Choose a reason for hiding this comment

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

I would recommend to double check versioning in each file for consistency.

OP source contracts follow 0.8.15, but files like BatchAuthenticator.sol & contracts in espresso-tee-contracts follow ^0.8.0 (which is fine I guess).

OP scripts usually follow ^0.8.0, but here scripts follow 0.8.25 - could you tell more about the motivation for it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Relaxed to ^0.8.0 - I don't remember any specific reason for us doing this, going to assume there wasn't one since nothing seems to break doing this.

address payable _addr;
assembly { _addr := create(0, add(_initCode, 0x20), mload(_initCode)) }
require(_addr != address(0), "DeployBatchAuthenticator: ProxyAdmin deployment failed");
proxyAdmin = IProxyAdmin(_addr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should separate ProxyAdmin be deployed just for BatchAuthenticator or would it be possible to re-use existing ProxyAdmin from our OP Stack deployment?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't think there's a technical reason
cc @shenkeyao is there a governance reason for this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think technically we can reuse the existing ProxyAdmin, but that would require the OP stack to participate in every future batchAuthenticator upgrade, which is an undesirable governance dependency. Looks like this was introduced in this commit, so cc @jjeangal, who might have more context.

checkOutput(_output);
}

function deployBatchAuthenticator(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I see this is the second place that can deploy BatchAuthenticator, so the same question: should separate ProxyAdmin be freshly deployed just for this contract? Or is it possible to use already deployed ProxyAdmin for Celo's OP Stack?

Comment on lines +43 to +45
// Upstream OP stack contracts that intentionally use ^ for broad compatibility.
"src/universal/Proxy.sol",
"src/universal/ProxyAdmin.sol",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This looks unnecessary, as these files use strict pragmas already:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed in 452a1cb

Comment thread packages/contracts-bedrock/foundry.toml Outdated
Comment on lines +172 to +173
optimizer_runs = 200
use_literal_content = false
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why do you set these? To match some verification settings?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Oh, there was some verification changes we did in our fork that I dropped for this PR, didn't catch this. Fixed

// Generic interfaces
"IHasSuperchainConfig",

// Espresso dependencies
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: It would be good to move this to the Celo contracts sections, to remove future rebase conflicts.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in 452a1cb

return nil, []error{fmt.Errorf("%s: Interface does not start with 'I'", contractName)}
}

// Espresso: skip interface artifacts that originate from lib/ (e.g. OZ v5 interfaces
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm not the biggest fan of all this artifact handling.

I think there's a way around it: 0322873

Let me know what you think.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This makes sense to me
cc @shenkeyao I think you have more context here

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Makes sense to cherry-pick 0322873! This would help clean up many artifact-related changes.

However, the lib/ skip in this file would still be necessary, because OZ v5 interfaces compiled transitively from espresso-tee-contracts would still land in forge-artifacts/.

address _owner
)
external
reinitializer(initVersion())
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

initialize() is non-idempotent: activeIsEspresso = true on L73 re-runs on every reinitializer(initVersion()) bump and silently undoes any prior switchBatcher() (e.g. a guardian flip to Fallback).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 0ba3285

}

/// @notice Toggles the active batcher between the Espresso and fallback batcher.
function switchBatcher() external onlyGuardianOrOwner {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It might be better to make this a setter instead of a toggle.

function setActiveIsEspresso(bool _desired) external onlyGuardianOrOwner {
      if (activeIsEspresso == _desired) return;        // idempotent no-op
      activeIsEspresso = _desired;
      emit BatcherSwitched(_desired);
  }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, but I'll need to clear that w/ the rest of the team.

QuentinI and others added 4 commits May 20, 2026 21:14
- strict-pragma: remove unneeded exclusions for src/universal/Proxy.sol
  and src/universal/ProxyAdmin.sol — both already use strict
  'pragma solidity 0.8.15;', so the entries (and their misleading
  comment claiming '^') were dead.
- interfaces: move the Espresso excludeContracts block out of the
  upstream-shared area and down next to the Celo block, with one
  entry per line to match the surrounding style. Localizes future
  rebase deltas.

Co-authored-by: OpenCode <noreply@opencode.ai>
Comment on lines +82 to +85
function paused() public view returns (bool) {
return systemConfig.paused();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think the pause should be removed, I can't see any reason to want to stop batches reaching the L1. Also this is delegating to systemConfig.paused() which is intended to pause the bridge, not stop the chain from progressing.

if (activeIsEspresso) {
// TEE batcher path: verify via registered TEE signer.
// Setting TEEType as Nitro because OP integration only supports AWS Nitro currently.
espressoTEEVerifier.verify(_signature, _commitment, IEspressoTEEVerifier.TeeType.NITRO);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we assume espressoTEEVerifier.verify() will always revert if there is a problem with the signature? Or should we check here the returned value and explicitly revert here if it's not true?

/// An attacker would need to compromise governance (to whitelist a malicious enclave hash), forge
/// an AWS Nitro signature, or break the Succinct ZK proof — all outside the contract's threat model.
function registerSigner(bytes calldata _verificationData, bytes calldata _data) external {
if (paused()) revert BatchAuthenticator_Paused();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is there a reason to not allow registering signers when the contract is paused?

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.

6 participants