Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b3fb718
Enable upgradability
shenkeyao Jan 20, 2026
31d36b6
Fix fmt
shenkeyao Jan 20, 2026
7a6de11
Fix file name
shenkeyao Jan 20, 2026
fc46cc0
Fix tests
shenkeyao Jan 20, 2026
b8a3f8c
Clean up tests
shenkeyao Jan 20, 2026
434a576
Force clean build
shenkeyao Jan 21, 2026
9749ea4
Add temp artifact verification
shenkeyao Jan 21, 2026
f5bccdb
More verification for artifact verification
shenkeyao Jan 21, 2026
24b44b9
Fix build command
shenkeyao Jan 21, 2026
5de916b
Fix artifact
shenkeyao Jan 22, 2026
1e4afdc
Fix artifact
shenkeyao Jan 22, 2026
6e1cb1a
Fix script
shenkeyao Jan 22, 2026
cd24562
Fix and simplify the script
shenkeyao Jan 22, 2026
d9a6723
Fix proxyAdmin as well
shenkeyao Jan 22, 2026
f161833
Add back verification workflow
shenkeyao Jan 22, 2026
a3af9e3
Fix more workflows
shenkeyao Jan 22, 2026
6841b1a
Restore version
shenkeyao Jan 22, 2026
159c8e6
Use EspressoTEEVerifierMock
shenkeyao Jan 22, 2026
6c5ed0a
Fix TeeType conversion
shenkeyao Jan 22, 2026
b25d32b
Fix fmt
shenkeyao Jan 22, 2026
f2b20b3
Fix enum conflict
shenkeyao Jan 22, 2026
8c898af
Fix version in test
shenkeyao Jan 22, 2026
352d296
Fix byte requirement
shenkeyao Jan 22, 2026
6ca777f
Add error
shenkeyao Jan 22, 2026
5d42d14
Merge branch 'celo-integration-rebase-14.2' into keyao/transparent-proxy
shenkeyao Jan 22, 2026
07921cb
Enable batcher address update
shenkeyao Jan 23, 2026
1aec617
Fix typo and remove redundant tests
shenkeyao Jan 23, 2026
4c0dfae
Fix owner
shenkeyao Jan 23, 2026
547cba2
Fix test build
shenkeyao Jan 23, 2026
b1084d6
transfer owner
shenkeyao Jan 23, 2026
e3757bc
Fix more tests
shenkeyao Jan 23, 2026
99d0866
Fix devnet test
shenkeyao Jan 23, 2026
319b1fb
Fix unused param
shenkeyao Jan 23, 2026
6620f4b
Fix ec2 test
shenkeyao Jan 23, 2026
3a805f8
Fix enclave test
shenkeyao Jan 23, 2026
b4b1c9a
Fix fmt
shenkeyao Jan 23, 2026
447291a
Fix circleCI
shenkeyao Jan 23, 2026
f98d7fb
Fix fmt again
shenkeyao Jan 23, 2026
b9cd3cc
Cleanup
shenkeyao Jan 24, 2026
cf77949
Move events and errors to interface
shenkeyao Jan 26, 2026
08d0187
Fix build
shenkeyao Jan 26, 2026
30ddb81
Update proxy admin permission
shenkeyao Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/docker-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:
- name: Compile contracts
run: cd packages/contracts-bedrock && just build

- name: Fix Proxy artifact bytecode
run: cd packages/contracts-bedrock && just fix-proxy-artifact

- name: Prepare allocations
run: |
cd espresso
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/espresso-devnet-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ jobs:
uses: actions/setup-go@v5

- name: Compile contracts
run: just compile-contracts
working-directory: packages/contracts-bedrock
run: just build

- name: Load environment variables
run: |
Expand All @@ -75,7 +76,9 @@ jobs:
cd op-deployer
just
export PATH=$PATH:$PWD/bin
cd ../espresso
cd ../packages/contracts-bedrock
just fix-proxy-artifact
cd ../../espresso
./scripts/prepare-allocs.sh
docker compose build
docker compose pull l1-validator espresso-dev-node l1-data-init
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/espresso-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ jobs:
- name: Compile contracts
run: just compile-contracts

- name: Fix Proxy artifact bytecode
run: cd packages/contracts-bedrock && just fix-proxy-artifact

- name: Load environment variables
run: |
while IFS= read -r line; do
Expand Down
27 changes: 25 additions & 2 deletions espresso/devnet-tests/key_rotation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"testing"

"github.com/ethereum-optimism/optimism/op-batcher/bindings"
e2ebindings "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -49,6 +51,27 @@ func TestChangeBatchInboxOwner(t *testing.T) {
bobAddress := d.secrets.Addresses().Bob
require.NotEqual(t, currentOwner, bobAddress)

// Get the ProxyAdmin address from the BatchAuthenticator proxy
proxyContract, err := e2ebindings.NewProxy(config.BatchAuthenticatorAddress, d.L1)
require.NoError(t, err)

var result []interface{}
proxyRaw := &e2ebindings.ProxyRaw{Contract: proxyContract}
err = proxyRaw.Call(&bind.CallOpts{}, &result, "admin")
require.NoError(t, err)
require.Len(t, result, 1, "admin() should return one value")
proxyAdminAddress := result[0].(common.Address)
require.NotEqual(t, proxyAdminAddress, common.Address{}, "ProxyAdmin address should not be zero")

// Get ProxyAdmin contract binding
proxyAdmin, err := e2ebindings.NewProxyAdmin(proxyAdminAddress, d.L1)
require.NoError(t, err)

// Verify current owner matches
proxyAdminOwner, err := proxyAdmin.Owner(&bind.CallOpts{})
require.NoError(t, err)
require.Equal(t, currentOwner, proxyAdminOwner, "BatchAuthenticator owner should match ProxyAdmin owner")

// Use batch authenticator owner key to sign the transaction
batchAuthenticatorPrivateKeyHex := os.Getenv("BATCH_AUTHENTICATOR_OWNER_PRIVATE_KEY")
require.NotEmpty(t, batchAuthenticatorPrivateKeyHex, "BATCH_AUTHENTICATOR_OWNER_PRIVATE_KEY must be set")
Expand All @@ -60,8 +83,8 @@ func TestChangeBatchInboxOwner(t *testing.T) {
batchAuthenticatorOwnerOpts, err := bind.NewKeyedTransactorWithChainID(batchAuthenticatorKey, l1ChainID)
require.NoError(t, err)

// Call TransferOwnership
tx, err := batchAuthenticator.TransferOwnership(batchAuthenticatorOwnerOpts, bobAddress)
// Call TransferOwnership on the ProxyAdmin directly
tx, err := proxyAdmin.TransferOwnership(batchAuthenticatorOwnerOpts, bobAddress)
require.NoError(t, err)

// Wait for transaction receipt and check if it succeeded
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ run-l1-espresso-contracts-tests: compile-contracts
(cd packages/contracts-bedrock && forge test --match-path "/**/test/L1/Batch*.t.sol")

compile-contracts-fast:
(cd packages/contracts-bedrock && forge build --offline --skip "/**/test/**")
(cd packages/contracts-bedrock && forge build --offline --skip "/**/test/**" && just fix-proxy-artifact)

build-batcher-enclave-image:
(cd kurtosis-devnet && just op-batcher-enclave-image)
Expand Down
40 changes: 20 additions & 20 deletions packages/contracts-bedrock/interfaces/L1/IBatchAuthenticator.sol
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IEspressoTEEVerifier } from "@espresso-tee-contracts/interface/IEspressoTEEVerifier.sol";

interface IBatchAuthenticator {
event Initialized(uint8 version);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/// @notice Error thrown when an invalid address (zero address) is provided.
error InvalidAddress(address contract_);

/// @notice Emitted when a batch info is authenticated.
event BatchInfoAuthenticated(bytes32 indexed commitment, address indexed signer);

/// @notice Emitted when a signer registration is initiated through this contract.
event SignerRegistrationInitiated(address indexed caller);

/// @notice Emitted when the TEE batcher address is updated.
event TeeBatcherUpdated(address indexed oldTeeBatcher, address indexed newTeeBatcher);

/// @notice Emitted when the non-TEE batcher address is updated.
event NonTeeBatcherUpdated(address indexed oldNonTeeBatcher, address indexed newNonTeeBatcher);

function authenticateBatchInfo(
bytes32 commitment,
bytes memory _signature
) external;

function decodeAttestationTbs(
bytes memory attestation
) external view returns (bytes memory, bytes memory);

function espressoTEEVerifier() external view returns (address);
function espressoTEEVerifier() external view returns (IEspressoTEEVerifier);

function nitroValidator() external view returns (address);

Expand All @@ -32,20 +39,13 @@ interface IBatchAuthenticator {
bytes memory signature
) external;

function renounceOwnership() external;

function transferOwnership(address newOwner) external;

function validBatchInfo(bytes32) external view returns (bool);

function activeIsTee() external view returns (bool);

function switchBatcher() external;

function __constructor__(
address _espressoTEEVerifier,
address _teeBatcher,
address _nonTeeBatcher,
address _owner
) external;
function setTeeBatcher(address _newTeeBatcher) external;

function setNonTeeBatcher(address _newNonTeeBatcher) external;
}
14 changes: 14 additions & 0 deletions packages/contracts-bedrock/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ build-go-ffi:
clean:
rm -rf ./artifacts ./forge-artifacts ./cache ./scripts/go-ffi/go-ffi ./deployments/hardhat/*

# Fixes Proxy and ProxyAdmin artifact bytecode if empty or missing.
# Foundry generates .json files with empty bytecode when multiple compiler versions are used.
fix-proxy-artifact:
@sh -c 'for contract in Proxy ProxyAdmin; do \
if [ -f "forge-artifacts/${contract}.sol/${contract}.0.8.15.json" ]; then \
if [ ! -f "forge-artifacts/${contract}.sol/${contract}.json" ]; then \
cp "forge-artifacts/${contract}.sol/${contract}.0.8.15.json" "forge-artifacts/${contract}.sol/${contract}.json"; \
echo "Created ${contract}.json from ${contract}.0.8.15.json"; \
else \
python3 -c "import json; main = json.load(open(\"forge-artifacts/${contract}.sol/${contract}.json\")); versioned = json.load(open(\"forge-artifacts/${contract}.sol/${contract}.0.8.15.json\")); bytecode_obj = main.get(\"bytecode\", {}).get(\"object\", \"0x\"); (main.update({\"bytecode\": versioned[\"bytecode\"], \"deployedBytecode\": versioned[\"deployedBytecode\"]}) or json.dump(main, open(\"forge-artifacts/${contract}.sol/${contract}.json\", \"w\"), indent=2) or print(\"Fixed ${contract}.json bytecode from ${contract}.0.8.15.json\")) if len(bytecode_obj) <= 2 else print(\"${contract}.json already has bytecode, skipping fix\")"; \
fi; \
fi; \
done'


########################################################
# TEST #
Expand Down
77 changes: 58 additions & 19 deletions packages/contracts-bedrock/scripts/deploy/DeployEspresso.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { IEspressoNitroTEEVerifier } from "@espresso-tee-contracts/interface/IEs
import { IEspressoSGXTEEVerifier } from "@espresso-tee-contracts/interface/IEspressoSGXTEEVerifier.sol";
import { IEspressoTEEVerifier } from "@espresso-tee-contracts/interface/IEspressoTEEVerifier.sol";
import { EspressoTEEVerifier } from "@espresso-tee-contracts/EspressoTEEVerifier.sol";
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol";
import { IProxy } from "interfaces/universal/IProxy.sol";
import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";
import { Proxy } from "src/universal/Proxy.sol";
import { BatchAuthenticator } from "src/L1/BatchAuthenticator.sol";
import { console2 as console } from "forge-std/console2.sol";

contract DeployEspressoInput is BaseDeployIO {
Expand Down Expand Up @@ -82,7 +87,7 @@ contract DeployEspressoOutput is BaseDeployIO {

contract DeployEspresso is Script {
function run(DeployEspressoInput input, DeployEspressoOutput output, address deployerAddress) public {
IEspressoTEEVerifier teeVerifier = deployTEEVerifier(input);
IEspressoTEEVerifier teeVerifier = deployTEEVerifier(input, deployerAddress);
IBatchAuthenticator batchAuthenticator = deployBatchAuthenticator(input, output, teeVerifier, deployerAddress);
deployBatchInbox(input, output, batchAuthenticator, deployerAddress);
checkOutput(output);
Expand All @@ -92,32 +97,66 @@ contract DeployEspresso is Script {
DeployEspressoInput input,
DeployEspressoOutput output,
IEspressoTEEVerifier teeVerifier,
address owner
address deployerAddress
)
public
returns (IBatchAuthenticator)
{
bytes32 salt = input.salt();
// Deploy the proxy admin, the proxy, and the batch authenticator implementation.
// We create ProxyAdmin with msg.sender as the owner to ensure broadcasts come from
// the expected address, then transfer ownership to deployerAddress afterward.
// Use DeployUtils.create1 to ensure artifacts are available for vm.getCode calls.
vm.broadcast(msg.sender);
IBatchAuthenticator impl = IBatchAuthenticator(
DeployUtils.create2({
_name: "BatchAuthenticator",
_salt: salt,
_args: DeployUtils.encodeConstructor(
abi.encodeCall(
IBatchAuthenticator.__constructor__,
(address(teeVerifier), input.teeBatcher(), input.nonTeeBatcher(), owner)
)
)
})
ProxyAdmin proxyAdmin = ProxyAdmin(
payable(
DeployUtils.create1({
_name: "ProxyAdmin",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProxyAdmin.__constructor__, (msg.sender)))
})
)
);
vm.label(address(proxyAdmin), "BatchAuthenticatorProxyAdmin");
vm.broadcast(msg.sender);
Proxy proxy = Proxy(
payable(
DeployUtils.create1({
_name: "Proxy",
_args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(proxyAdmin))))
})
)
);
vm.label(address(proxy), "BatchAuthenticatorProxy");
vm.broadcast(msg.sender);
proxyAdmin.setProxyType(address(proxy), ProxyAdmin.ProxyType.ERC1967);
vm.broadcast(msg.sender);
BatchAuthenticator impl = new BatchAuthenticator();
vm.label(address(impl), "BatchAuthenticatorImpl");

output.set(output.batchAuthenticatorAddress.selector, address(impl));
return impl;
// Initialize the proxy.
bytes memory initData =
abi.encodeCall(BatchAuthenticator.initialize, (teeVerifier, input.teeBatcher(), input.nonTeeBatcher()));
vm.broadcast(msg.sender);
proxyAdmin.upgradeAndCall(payable(address(proxy)), address(impl), initData);

// Transfer ownership to the desired deployerAddress if it differs from msg.sender.
if (deployerAddress != msg.sender) {
vm.broadcast(msg.sender);
proxyAdmin.transferOwnership(deployerAddress);
}

// Return the proxied contract.
IBatchAuthenticator batchAuthenticator = IBatchAuthenticator(address(proxy));
output.set(output.batchAuthenticatorAddress.selector, address(batchAuthenticator));
return batchAuthenticator;
}

function deployTEEVerifier(DeployEspressoInput input) public returns (IEspressoTEEVerifier) {
function deployTEEVerifier(
DeployEspressoInput input,
address /* deployerAddress */
)
public
returns (IEspressoTEEVerifier)
{
IEspressoNitroTEEVerifier nitroTEEVerifier = IEspressoNitroTEEVerifier(input.nitroTEEVerifier());
vm.broadcast(msg.sender);
IEspressoTEEVerifier impl = new EspressoTEEVerifier(
Expand All @@ -133,7 +172,7 @@ contract DeployEspresso is Script {
DeployEspressoInput input,
DeployEspressoOutput output,
IBatchAuthenticator batchAuthenticator,
address owner
address deployerAddress
)
public
{
Expand All @@ -144,7 +183,7 @@ contract DeployEspresso is Script {
_name: "BatchInbox",
_salt: salt,
_args: DeployUtils.encodeConstructor(
abi.encodeCall(IBatchInbox.__constructor__, (address(batchAuthenticator), owner))
abi.encodeCall(IBatchInbox.__constructor__, (address(batchAuthenticator), deployerAddress))
)
})
);
Expand Down
Loading
Loading