Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Single signer verification functions for multisig #8

Merged
merged 6 commits into from
Jan 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 58 additions & 7 deletions contracts/signature/MultiSigCheckable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,23 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
usedHashes[salt] = true;
}

/**
@notice Validate signature of message
@param message The message to verify
@param expectedGroupId The expected group ID
@param multiSignature The signatures formatted as a multisig
*/
function validateSignature(
bytes32 message,
uint64 expectedGroupId,
bytes memory multiSignature
) internal view returns (address signer) {
require(multiSignature.length != 0, "MSC: multiSignature required");
(, bool result, address signer) = tryVerifySingleSigner(message, expectedGroupId, multiSignature);
require(result, "MSC: Invalid signature");
return signer;
}

function verifyUniqueSaltWithQuorumId(
bytes32 message,
address expectedQuorumId,
Expand All @@ -368,7 +385,7 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
) internal virtual {
require(multiSignature.length != 0, "MSC: multiSignature required");
bytes32 digest = _hashTypedDataV4(message);
(bool result, address[] memory signers) = tryVerifyDigestWithAddress(digest, expectedGroupId, multiSignature);
(bool result, address[] memory signers) = tryVerifyDigestWithAddress(digest, expectedGroupId, multiSignature, true);
require(result, "MSC: Invalid signature");
require(!usedHashes[salt], "MSC: Message already used");
require(
Expand Down Expand Up @@ -414,7 +431,8 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
(result, ) = tryVerifyDigestWithAddress(
digest,
expectedGroupId,
multiSignature
multiSignature,
true
);
}

Expand All @@ -424,13 +442,15 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
@param expectedGroupId The expected group ID
@param multiSignature The signatures formatted as a multisig. Note that this
format requires signatures to be sorted in the order of signers (as bytes)
@param checkForMinSigs If the minimum number of signatures check should be performed
@return result Identifies success or failure
@return signers Lis of signers.
*/
function tryVerifyDigestWithAddress(
bytes32 digest,
uint64 expectedGroupId,
bytes memory multiSignature
bytes memory multiSignature,
bool checkForMinSigs
) internal view returns (bool result, address[] memory signers) {
require(multiSignature.length != 0, "MSC: multiSignature required");
MultiSigLib.Sig[] memory signatures = MultiSigLib.parseSig(
Expand Down Expand Up @@ -479,10 +499,11 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
// This ensures there are no duplicate signers
require(signers[i - 1] < _signer, "MSC: Sigs not sorted");
}
require(
signatures.length >= q.minSignatures,
"MSC: not enough signatures"
);

if (checkForMinSigs) {
require(signatures.length >= q.minSignatures, "MSC: not enough signatures");
}

return (true, signers);
}

Expand Down Expand Up @@ -510,4 +531,34 @@ abstract contract MultiSigCheckable is WithAdmin, EIP712 {
digest = _hashTypedDataV4(message);
result = tryVerifyDigest(digest, expectedGroupId, multiSignature);
}

/**
@notice Tries to verify a message hash
@dev example message;

bytes32 constant METHOD_SIG =
keccak256("WithdrawSigned(address token,address payee,uint256 amount,bytes32 salt)");
bytes32 message = keccak256(abi.encode(
METHOD_SIG,
token,
payee,
amount,
salt
@param message The message
@param expectedGroupId The expected group ID
@param multiSignature The signatures formatted as a multisig
*/
function tryVerifySingleSigner(
bytes32 message,
uint64 expectedGroupId,
bytes memory multiSignature
) internal view returns (bytes32 digest, bool result, address signer) {
digest = _hashTypedDataV4(message);
(result, signer) = tryVerifyDigestWithAddress(
digest,
expectedGroupId,
multiSignature,
false
);
}
}