Skip to main content

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 (standard ECDSA.recover).
  • EIP1271: Used for contract accounts (via isValidSignature()).

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 threshold signatures.
  • 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: Uses ECDSA.recover(orderHash, sig) and matches signer.
  • EIP1271: Calls isValidSignature(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) and ThresholdSet(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) and ThresholdSet(uint256 indexed threshold).

View Functions​

FunctionReturns
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 EIP1271 are trusted for contract logic; contracts must not be mutable without governance.