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
true
if:At least
threshold
signatures are presentEach signature is:
From an authorized signer
Valid according to the signer’s configured signature type
Returns
false
otherwise
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 view
Same logic as
checkSignatures
, but reverts withInvalidSignatures
error if validation fails
Signer Management (Owner-only)
setThreshold
function setThreshold(uint256 threshold_) external onlyOwner
Sets a new threshold
Must be
> 0
and≤ signers.length()
Emits
ThresholdSet
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)
Signer already exists
Emits
SignerAdded
andThresholdSet
removeSigner
function removeSigner(address signer, uint256 threshold_) external onlyOwner
Removes signer from consensus set
Updates threshold
Reverts if signer not found
Emits
SignerRemoved
andThresholdSet
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
EIP1271
are trusted for contract logic – contracts must not be mutable without governance
Last updated