Commit c5b6f888 authored by Maurelian's avatar Maurelian

refactor(ctb): Move _getNSigners() to inheritable contract

parent 542bc578
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { SignatureDecoder } from "safe-contracts/common/SignatureDecoder.sol";
abstract contract GetSigners is SignatureDecoder {
/// @notice Extract the signers from a set of signatures.
function _getNSigners(bytes32 dataHash, bytes memory signatures) internal pure returns (address[] memory _owners) {
uint256 numSignatures = signatures.length / 65;
_owners = new address[](numSignatures);
/// The following code is extracted from the Safe.checkNSignatures() method. It removes the signature
/// validation code, and keeps only the parsing code necessary to extract the owner addresses from the
/// signatures. We do not double check if the owner derived from a signature is valid. As this is handled
/// in the final require statement of Safe.checkNSignatures().
address currentOwner;
uint8 v;
bytes32 r;
bytes32 s;
uint256 i;
for (i = 0; i < numSignatures; i++) {
(v, r, s) = signatureSplit(signatures, i);
if (v == 0) {
// If v is 0 then it is a contract signature
// When handling contract signatures the address of the contract is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v == 1) {
// If v is 1 then it is an approved hash
// When handling approved hashes the address of the approver is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v > 30) {
// If v > 30 then default va (27,28) has been adjusted for eth_sign flow
// To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix
// before applying ecrecover
currentOwner =
ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
} else {
// Default is the ecrecover flow with the provided data hash
// Use ecrecover with the messageHash for EOA signatures
currentOwner = ecrecover(dataHash, v, r, s);
}
_owners[i] = currentOwner;
}
}
}
......@@ -4,11 +4,11 @@ pragma solidity 0.8.15;
import { Safe } from "safe-contracts/Safe.sol";
import { BaseGuard, GuardManager } from "safe-contracts/base/GuardManager.sol";
import { ModuleManager } from "safe-contracts/base/ModuleManager.sol";
import { SignatureDecoder } from "safe-contracts/common/SignatureDecoder.sol";
import { GetSigners } from "src/Safe/GetSigners.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import { ISemver } from "src/universal/ISemver.sol";
contract LivenessGuard is ISemver, SignatureDecoder, BaseGuard {
contract LivenessGuard is ISemver, GetSigners, BaseGuard {
/// @notice Emitted when a new set of signers is recorded.
/// @param signers An arrary of signer addresses.
event SignersRecorded(bytes32 indexed txHash, address[] signers);
......@@ -30,6 +30,8 @@ contract LivenessGuard is ISemver, SignatureDecoder, BaseGuard {
}
/// @notice Records the most recent time which any owner has signed a transaction.
/// @dev This method is called by the Safe contract, it is critical that it does not revert, otherwise
/// the Safe contract will be unable to execute transactions.
function checkTransaction(
address to,
uint256 value,
......@@ -71,45 +73,6 @@ contract LivenessGuard is ISemver, SignatureDecoder, BaseGuard {
emit SignersRecorded(txHash, signers);
}
/// @notice Exctract the signers from a set of signatures.
function _getNSigners(bytes32 dataHash, bytes memory signatures) internal pure returns (address[] memory _owners) {
uint256 numSignatures = signatures.length / 65;
_owners = new address[](numSignatures);
/// The following code is extracted from the Safe.checkNSignatures() method. It removes the signature
/// validation code, and keeps only the parsing code necessary to extract the owner addresses from the
/// signatures. We do not double check if the owner derived from a signature is valid. As this is handled
/// in the final require statement of Safe.checkNSignatures().
address currentOwner;
uint8 v;
bytes32 r;
bytes32 s;
uint256 i;
for (i = 0; i < numSignatures; i++) {
(v, r, s) = signatureSplit(signatures, i);
if (v == 0) {
// If v is 0 then it is a contract signature
// When handling contract signatures the address of the contract is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v == 1) {
// If v is 1 then it is an approved hash
// When handling approved hashes the address of the approver is encoded into r
currentOwner = address(uint160(uint256(r)));
} else if (v > 30) {
// If v > 30 then default va (27,28) has been adjusted for eth_sign flow
// To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix
// before applying ecrecover
currentOwner =
ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
} else {
// Default is the ecrecover flow with the provided data hash
// Use ecrecover with the messageHash for EOA signatures
currentOwner = ecrecover(dataHash, v, r, s);
}
_owners[i] = currentOwner;
}
}
/// @notice Enables an owner to demonstrate liveness by calling this method directly.
/// This is useful for owners who have not recently signed a transaction via the Safe.
function showLiveness() external {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment