Consensus
Purpose
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 deposit and redemptions via SignatureQueues.
It supports:
Threshold-based consensus
Two signature modes: EIP712 (EOA) and EIP1271 (contract-based)
Dynamic signer set management
Stateless, reusable verification interface
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())
Storage Layout
struct ConsensusStorage {
uint256 threshold;
EnumerableMap.AddressToUintMap signers;
}threshold: Minimum number of valid signatures required for verification to succeed.signers: Mapping of signer addresses → their configured signature type.
Initialization
function initialize(bytes calldata data)Expects
abi.encode(owner)as input.Sets the initial owner using
OwnableUpgradeable.
Signature Verification
checkSignatures
function checkSignatures(bytes32 orderHash, Signature[] calldata signatures) public view returns (bool)Returns
trueif:At least
thresholdsignatures are presentEach signature is:
From an authorized signer
Valid according to the signer’s configured signature type
Returns
falseotherwise
Signature validation behavior:
EIP712: UsesECDSA.recover(orderHash, sig)and matches signerEIP1271: CallsisValidSignature(orderHash, sig)on the contract
requireValidSignatures
function requireValidSignatures(bytes32 orderHash, Signature[] calldata signatures) external viewSame logic as
checkSignatures, but reverts withInvalidSignatureserror if validation fails
Signer Management (Owner-only)
setThreshold
function setThreshold(uint256 threshold_) external onlyOwnerSets a new threshold
Must be
> 0and≤ signers.length()Emits
ThresholdSet
addSigner
function addSigner(address signer, uint256 threshold_, SignatureType sigType) external onlyOwnerAdds a new signer with specified signature type
Updates threshold (as part of signer addition)
Reverts if:
signer == address(0)Signer already exists
Emits
SignerAddedandThresholdSet
removeSigner
function removeSigner(address signer, uint256 threshold_) external onlyOwnerRemoves signer from consensus set
Updates threshold
Reverts if signer not found
Emits
SignerRemovedandThresholdSet
View Functions
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)ThresholdSet(uint256)SignerAdded(address signer, SignatureType)SignerRemoved(address signer)InvalidSignatures(bytes32 hash, Signature[] signatures)(used in revert)
Security Considerations
Only the owner (via
OwnableUpgradeable) may update signer set or thresholdSignatures are stateless and externally verifiable
Replay protection (e.g., nonce checks) must be handled by upstream systems (nonces)
Signers using
EIP1271are trusted for contract logic – contracts must not be mutable without governance
Last updated