Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
72 changes: 72 additions & 0 deletions l1-contracts/contracts/state-transition/MultisigCommiter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol";

Check failure on line 4 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name Ownable2StepUpgradeable is not used

Check failure on line 4 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name Ownable2StepUpgradeable is not used

Check failure on line 4 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name Ownable2StepUpgradeable is not used
import {LibMap} from "./libraries/LibMap.sol";

Check failure on line 5 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name LibMap is not used

Check failure on line 5 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name LibMap is not used

Check failure on line 5 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name LibMap is not used
import {IZKChain} from "./chain-interfaces/IZKChain.sol";

Check failure on line 6 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IZKChain is not used

Check failure on line 6 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IZKChain is not used

Check failure on line 6 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IZKChain is not used
import {TimeNotReached, NotAZKChain} from "../common/L1ContractErrors.sol";

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name NotAZKChain is not used

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name TimeNotReached is not used

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name NotAZKChain is not used

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name TimeNotReached is not used

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name NotAZKChain is not used

Check failure on line 7 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name TimeNotReached is not used
import {IBridgehub} from "../bridgehub/IBridgehub.sol";

Check failure on line 8 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IBridgehub is not used

Check failure on line 8 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IBridgehub is not used

Check failure on line 8 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IBridgehub is not used
import {IValidatorTimelock} from "./IValidatorTimelock.sol";

Check failure on line 9 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IValidatorTimelock is not used

Check failure on line 9 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IValidatorTimelock is not used

Check failure on line 9 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

imported name IValidatorTimelock is not used
import {IExecutor} from "./chain-interfaces/IExecutor.sol";
import {ValidatorTimelock} from "./ValidatorTimelock.sol";
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable-v4/utils/cryptography/EIP712Upgradeable.sol";
import {SignatureCheckerUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/utils/cryptography/SignatureCheckerUpgradeable.sol";


//TODO proper errors
//TODO maybe combine with ValidatorTimelock
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a good point to discuss. In my opinion, unless there's a reason to have two separate contracts (i.e. MultisigCommiter and ValidatorTimelock) I'd do one. Having different ValidatorTimelocks on different CTMs will make things more complex (e.g. explaining people why we have two contracts; but also keeping track which CTM has which contract).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also if a CTM owner wants to use the 2FA feature at some point it's easy to turn on in case the feature is already there (vs upgrading the implementation).

contract MultisigCommiter is ValidatorTimelock, EIP712Upgradeable {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need a new name for this contract (I mean ValidatorTimelock) since it's not just a timelock after we introduce this change

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe ValidatorRegistry

/// @dev EIP-712 TypeHash for commitBatchesMultisig
bytes32 internal constant COMMIT_BATCHES_MULTISIG_TYPEHASH =
keccak256("CommitBatchesMultisig(address chainAddress, uint256 processBatchFrom, uint256 processBatchTo, bytes batchData)");

bytes32 internal constant COMMIT_VERIFIER_ROLE = keccak256("COMMIT_VERIFIER_ROLE");

mapping(address chainAddress => uint256 signingThreshold) internal signingThreshold;

constructor(address _bridgehubAddr) ValidatorTimelock(_bridgehubAddr) {}

//TODO __EIP712_init

function commitBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _batchData

Check failure on line 35 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "_batchData" is unused

Check failure on line 35 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "_batchData" is unused

Check failure on line 35 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "_batchData" is unused
) external override {
Copy link
Collaborator

Choose a reason for hiding this comment

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

no access control

require(signingThreshold[_chainAddress] == 0, "Chain requires verifiers signatures for commit");

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

GC: Use Custom Errors instead of require statements

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Error message for require is too long: 46 counted / 32 allowed

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

GC: Use Custom Errors instead of require statements

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Error message for require is too long: 46 counted / 32 allowed

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

GC: Use Custom Errors instead of require statements

Check failure on line 37 in l1-contracts/contracts/state-transition/MultisigCommiter.sol

View workflow job for this annotation

GitHub Actions / lint

Error message for require is too long: 46 counted / 32 allowed
_recordBatchCommitment(_chainAddress, _processBatchFrom, _processBatchTo);
_propagateToZKChain(_chainAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: it would be nice if you used inheritance here i.e. invoked super.

}

function commitBatchesMultisig(
address chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _batchData,
address[] calldata signers,
bytes[] calldata signatures
) external onlyRole(chainAddress, COMMITTER_ROLE) {
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(COMMIT_BATCHES_MULTISIG_TYPEHASH, chainAddress, _processBatchFrom, _processBatchTo, _batchData)));

_checkSignatures(chainAddress, signers, signatures, digest);

_recordBatchCommitment(chainAddress, _processBatchFrom, _processBatchTo);
// we cannot use _propagateToZKChain here, becouse function signature is altered
IExecutor(chainAddress).commitBatchesSharedBridge(chainAddress, _processBatchFrom, _processBatchTo, _batchData);
Copy link
Collaborator

Choose a reason for hiding this comment

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

it is a bit unfortunate that we do a full ABI-encoding here. It will come at a cost, but hopefully it wont be too much:

  • for rollups we'd use blobs and their commitments are small
  • for validiums/alt-DA we'd use some small commitments too

}

function _checkSignatures(address chainAddress, address[] calldata signers, bytes[] calldata signatures, bytes32 digest) internal view {
require(signers.length == signatures.length, "Mismatching signatures length");
require(signers.length >= signingThreshold[chainAddress], "Not enough signers");

// signers must be sorted in order to cheaply validate they are not duplicated
address previousSigner = address(0);
for (uint256 i = 0; i < signers.length; i++) {
require(signers[i] > previousSigner, "Signers must be sorted");
require(hasRole(chainAddress, COMMIT_VERIFIER_ROLE, signers[i]), "Invalid signature");
require(SignatureCheckerUpgradeable.isValidSignatureNow(signers[i], digest, signatures[i]), "Invalid signature");
previousSigner = signers[i];
}
}
}
10 changes: 8 additions & 2 deletions l1-contracts/contracts/state-transition/ValidatorTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,14 @@ contract ValidatorTimelock is
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata // _batchData (unused in this specific implementation)
) external onlyRole(_chainAddress, COMMITTER_ROLE) {
) external virtual onlyRole(_chainAddress, COMMITTER_ROLE) {
_recordBatchCommitment(_chainAddress, _processBatchFrom, _processBatchTo);
_propagateToZKChain(_chainAddress);
}

/// @dev Records the timestamp of batch commitment for the given chain address.
/// To be used from `commitBatchesSharedBridge`
function _recordBatchCommitment(address _chainAddress, uint256 _processBatchFrom, uint256 _processBatchTo) internal {
unchecked {
// This contract is only a temporary solution, that hopefully will be disabled until 2106 year, so...
// It is safe to cast.
Expand All @@ -208,7 +215,6 @@ contract ValidatorTimelock is
committedBatchTimestamp[_chainAddress].set(i, timestamp);
}
}
_propagateToZKChain(_chainAddress);
}

/// @inheritdoc IValidatorTimelock
Expand Down
Loading