The home for Hyperlane core contracts, sdk packages, and other infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hyperlane-monorepo/solidity/contracts/isms/multisig/AbstractWeightedMultisigIsm...

105 lines
3.4 KiB

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ External Imports ============
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {IStaticWeightedMultisigIsm} from "../../interfaces/isms/IWeightedMultisigIsm.sol";
import {Message} from "../../libs/Message.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {AbstractMultisig} from "./AbstractMultisigIsm.sol";
/**
* @title AbstractStaticWeightedMultisigIsm
* @notice Manages per-domain m-of-n Validator sets with stake weights that are used to verify
* interchain messages.
*/
abstract contract AbstractStaticWeightedMultisigIsm is
AbstractMultisig,
IStaticWeightedMultisigIsm
{
// ============ Constants ============
// total weight of all validators
uint96 public constant TOTAL_WEIGHT = 1e10;
/**
* @inheritdoc IStaticWeightedMultisigIsm
*/
function validatorsAndThresholdWeight(
bytes calldata /* _message*/
) public view virtual returns (ValidatorInfo[] memory, uint96);
/**
* @inheritdoc IInterchainSecurityModule
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) public view virtual returns (bool) {
bytes32 _digest = digest(_metadata, _message);
(
ValidatorInfo[] memory _validators,
uint96 _thresholdWeight
) = validatorsAndThresholdWeight(_message);
require(
_thresholdWeight > 0 && _thresholdWeight <= TOTAL_WEIGHT,
"Invalid threshold weight"
);
uint256 _validatorCount = Math.min(
_validators.length,
signatureCount(_metadata)
);
uint256 _validatorIndex = 0;
uint96 _totalWeight = 0;
// assumes that signatures are ordered by validator
for (
uint256 signatureIndex = 0;
_totalWeight < _thresholdWeight && signatureIndex < _validatorCount;
++signatureIndex
) {
address _signer = ECDSA.recover(
_digest,
signatureAt(_metadata, signatureIndex)
);
// loop through remaining validators until we find a match
while (
_validatorIndex < _validatorCount &&
_signer != _validators[_validatorIndex].signingAddress
) {
++_validatorIndex;
}
// fail if we never found a match
require(_validatorIndex < _validatorCount, "Invalid signer");
// add the weight of the current validator
_totalWeight += _validators[_validatorIndex].weight;
++_validatorIndex;
}
require(
_totalWeight >= _thresholdWeight,
"Insufficient validator weight"
);
return true;
}
}