Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
593c608
feat: add TeeDisputeGame, TeeProofVerifier, and DisputeGameFactoryRouter
doutv Mar 19, 2026
c4a4b7c
refactor: consolidate zone management into single setZone function
doutv Mar 19, 2026
1091a58
refactor: separate deployer and owner in DisputeGameFactoryRouter con…
doutv Mar 19, 2026
b6ce9b3
test: add TEE dispute game integration tests with real contracts
doutv Mar 19, 2026
74944e7
test: add TEE dispute game integration tests with real contracts
doutv Mar 19, 2026
3683087
refactor: remove BatchGamesCreated event from IDisputeGameFactoryRout…
doutv Mar 19, 2026
bcce3cb
fix: cross-chain isolation, audit fixes, and spec docs for TeeDispute…
doutv Mar 23, 2026
f4f097f
docs: update TEE dispute game spec with audit fix details
doutv Mar 23, 2026
bd3c50d
refactor: replace AccessManager with inline PROPOSER/CHALLENGER immut…
doutv Mar 23, 2026
6f12abb
fix: restrict prove() to proposer and replace custom ownership with O…
doutv Mar 23, 2026
1caba77
docs: add final audit report for M-01 and M-02 fix verification
doutv Mar 23, 2026
79258dc
fix: add pause check in closeGame, use getAnchorRoot, and EIP-712 typ…
doutv Mar 23, 2026
d39ab32
refactor: generation-based revocation, journal rebuild, and parameter…
doutv Mar 24, 2026
1feb569
refactor: remove constructor and setter parameter validations from Te…
doutv Mar 24, 2026
69c1f1d
style: apply OP Stack code style and forge fmt to TEE contracts
doutv Mar 24, 2026
bf8a179
docs: add local integration guide and E2E scripts for TEE prover
doutv Mar 25, 2026
8c391c6
refactor: remove DisputeGameFactoryRouter in favor of shared DisputeG…
doutv Mar 25, 2026
206794d
feat: add fork mode scripts for real RiscZero ZK proof testing
doutv Mar 25, 2026
13272b0
docs: update TEE Dispute Game specification with Chinese translations
doutv Mar 26, 2026
c2b317e
refactor: make key parameters immutable in TeeProofVerifier
doutv Mar 26, 2026
68826d8
test: add boundary, invariant, and edge-case tests for TEE dispute game
doutv Mar 26, 2026
39e7499
docs: enhance TEE Dispute Game specification with detailed parameter …
doutv Mar 27, 2026
5c2aca8
chore: remove outdated audit reports and findings documentation
doutv Mar 30, 2026
3601be5
refactor: change GAME_TYPE from immutable to constant, gameType()/gam…
doutv Mar 30, 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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @title IRiscZeroVerifier
/// @notice Minimal interface for the RISC Zero Groth16 verifier.
interface IRiscZeroVerifier {
/// @notice Verify a RISC Zero proof.
/// @param seal The proof seal (Groth16).
/// @param imageId The guest image ID.
/// @param journalDigest The SHA-256 digest of the journal.
function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @title ITeeProofVerifier
/// @notice Interface for the TEE Proof Verifier contract.
interface ITeeProofVerifier {
/// @notice Verify a batch state transition signed by a registered TEE enclave.
/// @param digest The hash of the batch data.
/// @param signature ECDSA signature (65 bytes: r + s + v).
/// @return signer The address of the verified enclave.
function verifyBatch(bytes32 digest, bytes calldata signature) external view returns (address signer);

/// @notice Check if an address is a registered enclave.
/// @param enclaveAddress The address to check.
/// @return True if the address is registered.
function isRegistered(address enclaveAddress) external view returns (bool);
}
73 changes: 73 additions & 0 deletions packages/contracts-bedrock/scripts/deploy/DeployTee.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {Script, console2} from "forge-std/Script.sol";
import {IDisputeGameFactory} from "interfaces/dispute/IDisputeGameFactory.sol";
import {IAnchorStateRegistry} from "interfaces/dispute/IAnchorStateRegistry.sol";
import {Duration} from "src/dispute/lib/Types.sol";
import {IRiscZeroVerifier} from "interfaces/dispute/IRiscZeroVerifier.sol";
import {ITeeProofVerifier} from "interfaces/dispute/ITeeProofVerifier.sol";
import {TeeDisputeGame} from "src/dispute/tee/TeeDisputeGame.sol";
import {TeeProofVerifier} from "src/dispute/tee/TeeProofVerifier.sol";

contract Deploy is Script {
struct DeployConfig {
uint256 deployerKey;
address deployer;
IRiscZeroVerifier riscZeroVerifier;
bytes32 imageId;
bytes nitroRootKey;
IDisputeGameFactory disputeGameFactory;
IAnchorStateRegistry anchorStateRegistry;
uint64 maxChallengeDuration;
uint64 maxProveDuration;
uint256 challengerBond;
address proofVerifierOwner;
address proposer;
address challenger;
}

function run() external returns (TeeProofVerifier teeProofVerifier, TeeDisputeGame teeDisputeGame) {
DeployConfig memory cfg = _readConfig();

vm.startBroadcast(cfg.deployerKey);

teeProofVerifier = new TeeProofVerifier(cfg.riscZeroVerifier, cfg.imageId, cfg.nitroRootKey);
if (cfg.proofVerifierOwner != cfg.deployer) {
teeProofVerifier.transferOwnership(cfg.proofVerifierOwner);
}

teeDisputeGame = new TeeDisputeGame(
Duration.wrap(cfg.maxChallengeDuration),
Duration.wrap(cfg.maxProveDuration),
cfg.disputeGameFactory,
ITeeProofVerifier(address(teeProofVerifier)),
cfg.challengerBond,
cfg.anchorStateRegistry,
cfg.proposer,
cfg.challenger
);

vm.stopBroadcast();

console2.log("deployer", cfg.deployer);
console2.log("teeProofVerifier", address(teeProofVerifier));
console2.log("teeDisputeGame", address(teeDisputeGame));
}

function _readConfig() internal view returns (DeployConfig memory cfg) {
cfg.deployerKey = vm.envUint("PRIVATE_KEY");
cfg.deployer = vm.addr(cfg.deployerKey);
cfg.riscZeroVerifier = IRiscZeroVerifier(vm.envAddress("RISC_ZERO_VERIFIER"));
cfg.imageId = vm.envBytes32("RISC_ZERO_IMAGE_ID");
cfg.nitroRootKey = vm.envBytes("NITRO_ROOT_KEY");
cfg.disputeGameFactory = IDisputeGameFactory(vm.envAddress("DISPUTE_GAME_FACTORY"));
cfg.anchorStateRegistry = IAnchorStateRegistry(vm.envAddress("ANCHOR_STATE_REGISTRY"));
cfg.maxChallengeDuration = uint64(vm.envUint("MAX_CHALLENGE_DURATION"));
cfg.maxProveDuration = uint64(vm.envUint("MAX_PROVE_DURATION"));
cfg.challengerBond = vm.envUint("CHALLENGER_BOND");
cfg.proofVerifierOwner = vm.envOr("PROOF_VERIFIER_OWNER", cfg.deployer);
cfg.proposer = vm.envAddress("PROPOSER");
cfg.challenger = vm.envAddress("CHALLENGER");
}
}
42 changes: 42 additions & 0 deletions packages/contracts-bedrock/scripts/deploy/RegisterTeeGame.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {Script, console2} from "forge-std/Script.sol";
import {IDisputeGameFactory} from "interfaces/dispute/IDisputeGameFactory.sol";
import {IAnchorStateRegistry} from "interfaces/dispute/IAnchorStateRegistry.sol";
import {IDisputeGame} from "interfaces/dispute/IDisputeGame.sol";
import {GameType} from "src/dispute/lib/Types.sol";

contract RegisterTeeGame is Script {
uint32 internal constant TEE_GAME_TYPE = 1960;
string internal constant GAME_ARGS_UNSUPPORTED =
"RegisterTeeGame: GAME_ARGS is unsupported for gameType=1960";

function run() external {
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(vm.envAddress("DISPUTE_GAME_FACTORY"));
IDisputeGame teeDisputeGame = IDisputeGame(vm.envAddress("TEE_DISPUTE_GAME_IMPL"));
uint256 initBond = vm.envUint("INIT_BOND");
bytes memory gameArgs = vm.envOr("GAME_ARGS", bytes(""));
bool setRespectedGameType = vm.envOr("SET_RESPECTED_GAME_TYPE", false);

require(gameArgs.length == 0, GAME_ARGS_UNSUPPORTED);

vm.startBroadcast(deployerKey);

disputeGameFactory.setImplementation(GameType.wrap(TEE_GAME_TYPE), teeDisputeGame);
disputeGameFactory.setInitBond(GameType.wrap(TEE_GAME_TYPE), initBond);

if (setRespectedGameType) {
IAnchorStateRegistry anchorStateRegistry = IAnchorStateRegistry(vm.envAddress("ANCHOR_STATE_REGISTRY"));
anchorStateRegistry.setRespectedGameType(GameType.wrap(TEE_GAME_TYPE));
console2.log("anchorStateRegistry respected game type set", TEE_GAME_TYPE);
}

vm.stopBroadcast();

console2.log("registered gameType", TEE_GAME_TYPE);
console2.log("teeDisputeGame", address(teeDisputeGame));
console2.log("initBond", initBond);
}
}
129 changes: 129 additions & 0 deletions packages/contracts-bedrock/scripts/tee/DeployTeeFork.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import { Script, console2 } from "forge-std/Script.sol";
import { Proxy } from "src/universal/Proxy.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol";
import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol";
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
import { ITeeProofVerifier } from "interfaces/dispute/ITeeProofVerifier.sol";
import { IRiscZeroVerifier } from "interfaces/dispute/IRiscZeroVerifier.sol";
import { TeeDisputeGame, TEE_DISPUTE_GAME_TYPE } from "src/dispute/tee/TeeDisputeGame.sol";
import { TeeProofVerifier } from "src/dispute/tee/TeeProofVerifier.sol";
import { MockSystemConfig } from "test/dispute/tee/mocks/MockSystemConfig.sol";
import { Duration, GameType, Hash, Proposal } from "src/dispute/lib/Types.sol";

/// @title DeployTeeFork
/// @notice Deploys TEE dispute game stack on a forked mainnet, using the real
/// RiscZeroVerifierRouter for ZK proof verification during enclave registration.
///
/// @dev Usage:
/// anvil --fork-url $ETH_RPC_URL --block-time 1
///
/// PRIVATE_KEY=0xac09...ff80 \
/// PROPOSER=0x7099...79C8 \
/// CHALLENGER=0x3C44...93BC \
/// RISC_ZERO_VERIFIER=0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319 \
/// RISC_ZERO_IMAGE_ID=0x<guest image id> \
/// NITRO_ROOT_KEY=0x<96 bytes P384 root key hex> \
/// forge script scripts/tee/DeployTeeFork.s.sol --rpc-url http://localhost:8545 --broadcast
contract DeployTeeFork is Script {
uint256 internal constant DEFENDER_BOND = 0.1 ether;
uint256 internal constant CHALLENGER_BOND = 0.2 ether;
uint64 internal constant MAX_CHALLENGE_DURATION = 300;
uint64 internal constant MAX_PROVE_DURATION = 300;

GameType internal constant TEE_GAME_TYPE = GameType.wrap(TEE_DISPUTE_GAME_TYPE);

bytes32 internal constant ANCHOR_BLOCK_HASH = keccak256("genesis-block");
bytes32 internal constant ANCHOR_STATE_HASH = keccak256("genesis-state");
uint256 internal constant ANCHOR_L2_BLOCK = 0;

function run() external {
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerKey);
address proposer_ = vm.envAddress("PROPOSER");
address challenger_ = vm.envAddress("CHALLENGER");

vm.startBroadcast(deployerKey);

TeeProofVerifier teeProofVerifier = _deployVerifier();
DisputeGameFactory factory = _deployFactory(deployer);
AnchorStateRegistry asr = _deployASR(deployer, factory);
TeeDisputeGame impl = _deployGame(factory, teeProofVerifier, asr, proposer_, challenger_);

vm.stopBroadcast();

console2.log("=== Deployed (fork mode) ===");
console2.log("TeeProofVerifier :", address(teeProofVerifier));
console2.log("DisputeGameFactory :", address(factory));
console2.log("AnchorStateRegistry :", address(asr));
console2.log("TeeDisputeGame impl :", address(impl));
}

function _deployVerifier() internal returns (TeeProofVerifier) {
IRiscZeroVerifier rv = IRiscZeroVerifier(vm.envAddress("RISC_ZERO_VERIFIER"));
bytes32 imageId = vm.envBytes32("RISC_ZERO_IMAGE_ID");
bytes memory rootKey = vm.envBytes("NITRO_ROOT_KEY");
console2.log("RiscZeroVerifier :", address(rv));
console2.log("imageId :", vm.toString(imageId));
return new TeeProofVerifier(rv, imageId, rootKey);
}

function _deployFactory(address deployer) internal returns (DisputeGameFactory) {
DisputeGameFactory factoryImpl = new DisputeGameFactory();
Proxy p = new Proxy(deployer);
p.upgradeToAndCall(address(factoryImpl), abi.encodeCall(factoryImpl.initialize, (deployer)));
return DisputeGameFactory(address(p));
}

function _deployASR(address deployer, DisputeGameFactory factory) internal returns (AnchorStateRegistry) {
MockSystemConfig sc = new MockSystemConfig(deployer);
AnchorStateRegistry asrImpl = new AnchorStateRegistry(0);
Proxy p = new Proxy(deployer);
p.upgradeToAndCall(
address(asrImpl),
abi.encodeCall(
asrImpl.initialize,
(
ISystemConfig(address(sc)),
IDisputeGameFactory(address(factory)),
Proposal({
root: Hash.wrap(keccak256(abi.encode(ANCHOR_BLOCK_HASH, ANCHOR_STATE_HASH))),
l2SequenceNumber: ANCHOR_L2_BLOCK
}),
TEE_GAME_TYPE
)
)
);
return AnchorStateRegistry(address(p));
}

function _deployGame(
DisputeGameFactory factory,
TeeProofVerifier verifier,
AnchorStateRegistry asr,
address proposer_,
address challenger_
)
internal
returns (TeeDisputeGame)
{
TeeDisputeGame impl = new TeeDisputeGame(
Duration.wrap(MAX_CHALLENGE_DURATION),
Duration.wrap(MAX_PROVE_DURATION),
IDisputeGameFactory(address(factory)),
ITeeProofVerifier(address(verifier)),
CHALLENGER_BOND,
IAnchorStateRegistry(address(asr)),
proposer_,
challenger_
);
factory.setImplementation(TEE_GAME_TYPE, IDisputeGame(address(impl)), bytes(""));
factory.setInitBond(TEE_GAME_TYPE, DEFENDER_BOND);
return impl;
}
}
Loading