Skip to content

Espresso 1: Contracts#443

Closed
QuentinI wants to merge 28 commits into
celo-org:celo-rebase-18from
EspressoSystems:ag/contracts
Closed

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

Conversation

@QuentinI

@QuentinI QuentinI commented May 7, 2026

Copy link
Copy Markdown
Collaborator

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 3 times, most recently from cbd97f9 to ee2d984 Compare May 8, 2026 00:50
@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

@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: 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 Outdated
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
Comment thread packages/contracts-bedrock/test/L1/BatchAuthenticator.t.sol
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
Comment thread packages/contracts-bedrock/scripts/deploy/DeployEspresso.s.sol Outdated
Comment thread packages/contracts-bedrock/scripts/deploy/DeployBatchAuthenticator.s.sol Outdated
Comment thread packages/contracts-bedrock/scripts/deploy/DeployEspresso.s.sol
Comment thread packages/contracts-bedrock/scripts/checks/strict-pragma/main.go Outdated
Comment thread packages/contracts-bedrock/foundry.toml Outdated
Comment thread packages/contracts-bedrock/scripts/checks/interfaces/main.go Outdated
Comment thread packages/contracts-bedrock/scripts/checks/interfaces/main.go
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol Outdated
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol Outdated
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol Outdated
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol Outdated
Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
@jcortejoso

Copy link
Copy Markdown
Member

Hey @QuentinI!

I have authorized to run CircleCI tests from your fork. May you commit something to trigger execution?

Also I run manually the contract tests and found two are failing:

Ran 717 test suites in 349.71s (2868.40s CPU time): 2299 tests passed, 2 failed, 99 skipped (2400 total tests)
Failing tests:
Encountered 1 failing test in test/L1/BatchAuthenticator.t.sol:BatchAuthenticator_Uncategorized_Test
[FAIL: assertion failed: 3 != 2] test_setEspressoBatcher_sameBlockOverwrites() (gas: 725110)
Encountered 1 failing test in test/vendor/Initializable.t.sol:Initializer_Test
[FAIL: panic: array out-of-bounds access (0x32)] test_cannotReinitialize_succeeds() (gas: 3399) 

Comment thread packages/contracts-bedrock/src/L1/BatchAuthenticator.sol Outdated
QuentinI and others added 14 commits June 12, 2026 11:40
Cherry-picked from piersy's commit 5d0a803 on PR ethereum-optimism#443.

Walks the dual-batcher state machine: Espresso path → switchBatcher →
fallback path → switchBatcher → Espresso path. Asserts every transition
emits the expected event, that signer registration survives the
round-trip, and that re-issuing the same call after a mode flip changes
the outcome (the previously-valid Espresso signature is no longer
consulted on the fallback path).

Co-authored-by: Piers Powlesland <pierspowlesland@gmail.com>
Co-authored-by: OpenCode <noreply@opencode.ai>
Replace the hand-rolled `EspressoBatcherEntry[]` history + binary search
with OpenZeppelin's `Checkpoints.Trace160` (`(uint96 key, uint160 value)`).
`uint160` is exactly an address with no waste, and `uint96` easily covers
L1 block numbers. `upperLookupRecent` replaces the custom binary search
and the same-block-overwrite branch is now handled inside `_insert`.

Co-authored-by: OpenCode <noreply@opencode.ai>
…sed warning codes

Drop the two impl imports (EspressoTEEVerifier, EspressoNitroTEEVerifier) from
DeployEspresso.s.sol and replace direct instantiation with vm.getCode + assembly
create, reading bytecode from the submodule's own out/ directory.

This removes the impl closure (TEEHelper, JournalValidation, and the
aws-nitro-enclave-attestation chain) from OP's solc invocations. The impls
are still parsed/ABI-checked by forge via libs=['lib'], but they no longer
require bytecode emission or the optimizer backend.

Since OP's build no longer compiles the submodule's impl files, the three
error codes those files triggered (6321 unnamed return, 5667 unused param,
1878 missing SPDX) can be removed from ignored_error_codes. OP's own code
does not trigger any of them. The lint_on_build=false workaround is also
removed for the same reason — with the impl closure gone, forge lint reports
283 warnings (all from OP's own code), none of which cause a build failure.

Adds fs_permissions read access for lib/espresso-tee-contracts/out/ so
vm.getCode can locate the pre-built artifacts. The submodule must be built
(forge build --root lib/espresso-tee-contracts) before OP's main build.

Co-authored-by: OpenCode <noreply@opencode.ai>
Deploy the BatchAuthenticator and TEEVerifier proxies behind the existing
OP Stack ProxyAdmin instead of dedicated ones (celo-org#443).
Both proxies use the deployer as a transient admin to initialize directly,
then changeAdmin to the shared ProxyAdmin (DeployAltDA/DeployFeesDepositor
pattern). Reorder TEE deploy so the Nitro verifier is wired via initialize,
removing the post-init onlyOwner call and ownership-transfer dance. Rename
inputs to espressoOwner/sharedProxyAdmin and drop the teeVerifierProxyAdmin
output.

Co-authored-by: OpenCode <noreply@opencode.ai>
Co-authored-by: OpenCode <noreply@opencode.ai>
The Go script host's getArtifact translated a fully-qualified Foundry
name like "src/universal/Proxy.sol:Proxy" into the artifact path
"src/universal/Proxy.sol/Proxy.json", which does not exist because the
artifacts FS is keyed by the source-file basename. Reduce any
directory-qualified path to its basename before ReadArtifact so that
both "File.sol:Contract" and "path/to/File.sol:Contract" resolve to the
same artifact.

This unblocks the deploy scripts that use
getCode("src/universal/Proxy.sol:Proxy") to disambiguate from the
OpenZeppelin v5 proxy/Proxy.sol artifact, fixing TestNewDeployAltDAScript,
TestNewDeployImplementationsScript, TestNewDeploySuperchainScript and the
op-e2e proofs actions that hit the same DeploySuperchain code path.

Co-authored-by: OpenCode <noreply@opencode.ai>
Resolve the 16 findings flagged by the contracts-bedrock-checks-fast
semgrep job:

- sol-safety-use-deployutils-getcode: replace vm.getCode(...) with
  DeployUtils.getCode(...) in DeployBatchAuthenticator, DeployEspresso,
  DeployPeriphery, BatchAuthenticator.t, and FeesDepositor.t (add the
  DeployUtils import where missing).
- sol-style-use-abi-encodecall: add a justified nosemgrep on the
  EspressoTEEVerifier initialize encoding in DeployEspresso; encodeCall
  would pull the EspressoTEEVerifier impl closure into OP's compile group,
  which deploying from the submodule artifact is meant to avoid.
- sol-style-input-arg-fmt / sol-style-return-arg-fmt: rename interface and
  contract args (index -> _index, l1Block -> _l1Block) and name returns
  (batcher_, fromBlock_) on BatchAuthenticator and IBatchAuthenticator.

forge build, the semgrep scan (0 blocking findings), and the
BatchAuthenticator/FeesDepositor test suites all pass.

Co-authored-by: OpenCode <noreply@opencode.ai>
@QuentinI QuentinI changed the base branch from celo-rebase-17 to celo-rebase-18 June 12, 2026 11:04
@QuentinI

Copy link
Copy Markdown
Collaborator Author

Re-opened as a PR from an in-repo branch at #455

@QuentinI QuentinI closed this Jun 12, 2026
piersy pushed a commit that referenced this pull request Jun 15, 2026
Adapts the derivation pipeline to PR #443's updated BatchAuthenticator
event and enforces that a batch is submitted by the same address that
authenticated it.

The contract event changed from BatchInfoAuthenticated(bytes32 indexed
commitment) to BatchInfoAuthenticated(bytes32 commitment, address indexed
caller): the signature hash (Topics[0]) changes, the commitment moves into
the unindexed log data, and the caller becomes the indexed Topics[1]. The
event scanner is updated accordingly (new ABI string, commitment read from
Data[:32], with a length guard).

CollectAuthenticatedBatches and collectAuthEventsFromReceipts now return
map[commitment]caller instead of a commitment set. Post-fork,
isBatchTxAuthorized recovers the batch transaction's L1 sender and accepts
the batch only if it equals the caller that emitted the auth event. This
binds each batch to the address that authenticated it, so a batch
authenticated by one batcher cannot be submitted by another. When the same
commitment is authenticated in more than one block within the lookback
window, the newest event's caller is retained.

Removes FindBatchAuthEvent and its test: it had no production caller (the
pipeline uses CollectAuthenticatedBatches) and, lacking a caller check,
diverged from the enforced sender-equals-caller semantics.

Updates the data-source tests to set the auth event caller to the batch
tx sender, and adds cases covering acceptance for a non-batcher sender
matching its caller, rejection when the sender differs from the caller,
and newest-caller-wins on duplicate authentication.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Cherry-picked from piersy's commit 5d0a803 on PR #443.

Walks the dual-batcher state machine: Espresso path → switchBatcher →
fallback path → switchBatcher → Espresso path. Asserts every transition
emits the expected event, that signer registration survives the
round-trip, and that re-issuing the same call after a mode flip changes
the outcome (the previously-valid Espresso signature is no longer
consulted on the fallback path).

Co-authored-by: Piers Powlesland <pierspowlesland@gmail.com>
Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Deploy the BatchAuthenticator and TEEVerifier proxies behind the existing
OP Stack ProxyAdmin instead of dedicated ones (#443).
Both proxies use the deployer as a transient admin to initialize directly,
then changeAdmin to the shared ProxyAdmin (DeployAltDA/DeployFeesDepositor
pattern). Reorder TEE deploy so the Nitro verifier is wired via initialize,
removing the post-init onlyOwner call and ownership-transfer dance. Rename
inputs to espressoOwner/sharedProxyAdmin and drop the teeVerifierProxyAdmin
output.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Adapts the derivation pipeline to PR #443's updated BatchAuthenticator
event and enforces that a batch is submitted by the same address that
authenticated it.

The contract event changed from BatchInfoAuthenticated(bytes32 indexed
commitment) to BatchInfoAuthenticated(bytes32 commitment, address indexed
caller): the signature hash (Topics[0]) changes, the commitment moves into
the unindexed log data, and the caller becomes the indexed Topics[1]. The
event scanner is updated accordingly (new ABI string, commitment read from
Data[:32], with a length guard).

CollectAuthenticatedBatches and collectAuthEventsFromReceipts now return
map[commitment]caller instead of a commitment set. Post-fork,
isBatchTxAuthorized recovers the batch transaction's L1 sender and accepts
the batch only if it equals the caller that emitted the auth event. This
binds each batch to the address that authenticated it, so a batch
authenticated by one batcher cannot be submitted by another. When the same
commitment is authenticated in more than one block within the lookback
window, the newest event's caller is retained.

Removes FindBatchAuthEvent and its test: it had no production caller (the
pipeline uses CollectAuthenticatedBatches) and, lacking a caller check,
diverged from the enforced sender-equals-caller semantics.

Updates the data-source tests to set the auth event caller to the batch
tx sender, and adds cases covering acceptance for a non-batcher sender
matching its caller, rejection when the sender differs from the caller,
and newest-caller-wins on duplicate authentication.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Regenerated against PR #443's BatchAuthenticator.sol via forge build +
abigen. Includes the new history-based API (espressoBatcherAt,
espressoBatcherAtBlock, espressoBatcherHistoryLength, setEspressoBatcher)
and the EspressoBatcherUpdated(address,address,uint64) event with the
fromBlock parameter; drops the removed paused() function.

Consumed by the fallback batcher (next commit) to read activeIsEspresso
and pack authenticateBatchInfo calldata. The TEE batcher in a follow-up
PR will use the same binding.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Adapts the derivation pipeline to PR #443's updated BatchAuthenticator
event and enforces that a batch is submitted by the same address that
authenticated it.

The contract event changed from BatchInfoAuthenticated(bytes32 indexed
commitment) to BatchInfoAuthenticated(bytes32 commitment, address indexed
caller): the signature hash (Topics[0]) changes, the commitment moves into
the unindexed log data, and the caller becomes the indexed Topics[1]. The
event scanner is updated accordingly (new ABI string, commitment read from
Data[:32], with a length guard).

CollectAuthenticatedBatches and collectAuthEventsFromReceipts now return
map[commitment]caller instead of a commitment set. Post-fork,
isBatchTxAuthorized recovers the batch transaction's L1 sender and accepts
the batch only if it equals the caller that emitted the auth event. This
binds each batch to the address that authenticated it, so a batch
authenticated by one batcher cannot be submitted by another. When the same
commitment is authenticated in more than one block within the lookback
window, the newest event's caller is retained.

Removes FindBatchAuthEvent and its test: it had no production caller (the
pipeline uses CollectAuthenticatedBatches) and, lacking a caller check,
diverged from the enforced sender-equals-caller semantics.

Updates the data-source tests to set the auth event caller to the batch
tx sender, and adds cases covering acceptance for a non-batcher sender
matching its caller, rejection when the sender differs from the caller,
and newest-caller-wins on duplicate authentication.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 17, 2026
Regenerated against PR #443's BatchAuthenticator.sol via forge build +
abigen. Includes the new history-based API (espressoBatcherAt,
espressoBatcherAtBlock, espressoBatcherHistoryLength, setEspressoBatcher)
and the EspressoBatcherUpdated(address,address,uint64) event with the
fromBlock parameter; drops the removed paused() function.

Consumed by the fallback batcher (next commit) to read activeIsEspresso
and pack authenticateBatchInfo calldata. The TEE batcher in a follow-up
PR will use the same binding.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 18, 2026
Adapts the derivation pipeline to PR #443's updated BatchAuthenticator
event and enforces that a batch is submitted by the same address that
authenticated it.

The contract event changed from BatchInfoAuthenticated(bytes32 indexed
commitment) to BatchInfoAuthenticated(bytes32 commitment, address indexed
caller): the signature hash (Topics[0]) changes, the commitment moves into
the unindexed log data, and the caller becomes the indexed Topics[1]. The
event scanner is updated accordingly (new ABI string, commitment read from
Data[:32], with a length guard).

CollectAuthenticatedBatches and collectAuthEventsFromReceipts now return
map[commitment]caller instead of a commitment set. Post-fork,
isBatchTxAuthorized recovers the batch transaction's L1 sender and accepts
the batch only if it equals the caller that emitted the auth event. This
binds each batch to the address that authenticated it, so a batch
authenticated by one batcher cannot be submitted by another. When the same
commitment is authenticated in more than one block within the lookback
window, the newest event's caller is retained.

Removes FindBatchAuthEvent and its test: it had no production caller (the
pipeline uses CollectAuthenticatedBatches) and, lacking a caller check,
diverged from the enforced sender-equals-caller semantics.

Updates the data-source tests to set the auth event caller to the batch
tx sender, and adds cases covering acceptance for a non-batcher sender
matching its caller, rejection when the sender differs from the caller,
and newest-caller-wins on duplicate authentication.

Co-authored-by: OpenCode <noreply@opencode.ai>
QuentinI added a commit that referenced this pull request Jun 18, 2026
Regenerated against PR #443's BatchAuthenticator.sol via forge build +
abigen. Includes the new history-based API (espressoBatcherAt,
espressoBatcherAtBlock, espressoBatcherHistoryLength, setEspressoBatcher)
and the EspressoBatcherUpdated(address,address,uint64) event with the
fromBlock parameter; drops the removed paused() function.

Consumed by the fallback batcher (next commit) to read activeIsEspresso
and pack authenticateBatchInfo calldata. The TEE batcher in a follow-up
PR will use the same binding.

Co-authored-by: OpenCode <noreply@opencode.ai>
piersy pushed a commit that referenced this pull request Jun 18, 2026
Introduces the on-chain BatchAuthenticator, the first piece of the Espresso
integration. Batchers authenticate batch commitments here; the contract emits
BatchInfoAuthenticated events that the forthcoming derivation pipeline scans
from L1 receipts to decide batch authenticity. Re-host of #443.

Contract (src/L1/BatchAuthenticator.sol, semver 1.2.0): upgradeable L1 contract
with two batcher modes selected by activeIsEspresso — an Espresso/TEE path
(caller must be the active espressoBatcher AND the signature must verify
against the EspressoTEEVerifier) and a fallback path (caller must be the
SystemConfig batcher, no signature). Owner rotates the espressoBatcher;
guardian-or-owner flips the active mode. The espressoBatcher history is an
append-only OZ Checkpoints.Trace160 keyed by L1 block, with a same-block guard
so rotations can't overwrite history. registerSigner is permissionless,
delegating safety to the TEE verifier. Adds IBatchAuthenticator, ~1100 lines of
unit/fork tests, and TEE verifier mocks.

Deploy: DeployBatchAuthenticator (standalone) and DeployEspresso (also deploys
the TEE/Nitro verifiers), both using the transient-admin → initialize →
changeAdmin-to-shared-ProxyAdmin pattern.

Dependencies: adds espresso-tee-contracts (v1.3.0) and
openzeppelin-contracts-upgradeable-v5 submodules, plus OZ v5 remappings — the
repo now carries OZ v4 and v5 side by side.

Cross-cutting: OZ v5 ships its own proxy/Proxy.sol, so every "Proxy" artifact
reference across deploy scripts and tests is path-qualified to
"src/universal/Proxy.sol:Proxy", and the Go getCode cheatcode now resolves
directory-qualified names. CI/tooling adjustments: BatchAuthenticator
grandfathered into the floating-pragma allowlist, Espresso interfaces excluded
from the interface-ABI check, justfile/CircleCI tweaks to avoid OOM and solc
auto-detect issues, and regenerated ABI/storage/semver snapshots.
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.

7 participants