Consensus
Overview
The Consensus contract manages a permissioned set of signers and enforces multi-signature validation logic using either EIP 712 or EIP 1271 signatures. It is a lightweight module designed for verifying offchain consensus before executing critical actions such as deposits and redemptions via SignatureQueues.
It supports:
- Threshold-based consensus.
- Two signature modes: EIP 712 (EOA) and EIP 1271 (contract based).
- Dynamic signer set management.
- Stateless, reusable verification interface.
Configuration and State
Storage Layout
struct ConsensusStorage {
EnumerableMap.AddressToUintMap signers;
uint256 threshold;
}
threshold: Minimum number of valid signatures required for verification to succeed.signers: Mapping of signer addresses to their configured signature type.
Initialization
function initialize(bytes calldata data)
- Expects
abi.encode(owner)as input. - Sets the initial owner using
OwnableUpgradeable.
Behavior
Core Concepts
Threshold Based Verification
To validate an action, a set of authorized signers must collectively submit signatures. The number of valid signatures must be greater than or equal to the configured threshold.
Signature Types
Each signer is associated with a SignatureType:
EIP712: Used for externally owned accounts (standardECDSA.recover).EIP1271: Used for contract accounts (viaisValidSignature()).
Functions
Signature Verification
checkSignatures
function checkSignatures(bytes32 orderHash, Signature[] calldata signatures) public view returns (bool)
Returns true if:
- The signature array is non-empty and contains at least
thresholdsignatures. - Signer addresses are strictly ascending, without duplicates.
- Each signature is from an authorized signer.
- Each signature is valid according to the signer's configured signature type.
Returns false for an empty array, insufficient signatures, duplicate or unordered signers, unknown signers, or a validly encoded signature that fails verification. Malformed ECDSA signatures and reverting or malformed EIP-1271 calls revert instead.
Signature validation behavior:
EIP712: UsesECDSA.recover(orderHash, sig)and matches signer.EIP1271: CallsisValidSignature(orderHash, sig)on the contract.
requireValidSignatures
function requireValidSignatures(bytes32 orderHash, Signature[] calldata signatures) external view
Reverts with InvalidSignatures(bytes32 orderHash, Signature[] signatures) when checkSignatures returns false. Reverts from ECDSA or EIP-1271 validation propagate unchanged.
Signer Management (Owner only)
setThreshold
function setThreshold(uint256 threshold_) external onlyOwner
- Sets a new threshold.
- Must be greater than zero and less than or equal to
signers.length(). - Emits
ThresholdSet(uint256 indexed threshold).
addSigner
function addSigner(address signer, uint256 threshold_, SignatureType sigType) external onlyOwner
- Adds a new signer with specified signature type.
- Updates threshold as part of signer addition.
- Reverts if
signer == address(0)or signer already exists. - Emits
SignerAdded(address indexed signer, SignatureType signatureType)andThresholdSet(uint256 indexed threshold).
removeSigner
function removeSigner(address signer, uint256 threshold_) external onlyOwner
- Removes signer from consensus set.
- Updates threshold.
- Reverts if signer not found.
- Emits
SignerRemoved(address indexed signer)andThresholdSet(uint256 indexed threshold).
View Functions
| Function | Returns |
|---|---|
threshold() | Current consensus threshold |
signers() | Total number of signers |
signerAt(uint256) | Signer address and type at index |
isSigner(address) | Boolean indicating if address is a signer |
Events
Initialized(bytes initParams)ThresholdSet(uint256 indexed threshold)SignerAdded(address indexed signer, SignatureType signatureType)SignerRemoved(address indexed signer)
Errors
InvalidSignatures(bytes32 orderHash, Signature[] signatures): Submitted signatures do not satisfy the consensus rules.InvalidThreshold(uint256 threshold): Threshold is zero or exceeds the signer count.ZeroAddress(): A signer address is zero.SignerAlreadyExists(address signer): The signer is already registered.SignerNotFound(address signer): The signer is not registered.
Invariants and Limitations
Security Considerations
- Only the owner (via
OwnableUpgradeable) may update signer set or threshold. - Signatures are stateless and externally verifiable.
- Replay protection (for example nonce checks) must be handled by upstream systems.
- Signers using
EIP1271are trusted for contract logic; contracts must not be mutable without governance.