Skip to content

Commit

Permalink
Refactoring validateSignatures() to share the part common to several …
Browse files Browse the repository at this point in the history
…modules in RelayerModule
  • Loading branch information
olivdb committed Apr 1, 2020
1 parent 6cf62a0 commit 3640d72
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 83 deletions.
25 changes: 1 addition & 24 deletions contracts/modules/ApprovedTransfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,7 @@ contract ApprovedTransfer is BaseModule, RelayerModule, BaseTransfer {
view
returns (bool)
{
address lastSigner = address(0);
address[] memory guardians = guardianStorage.getGuardians(_wallet);
bool isGuardian = false;
for (uint8 i = 0; i < _signatures.length / 65; i++) {
address signer = recoverSigner(_signHash, _signatures, i);
if (i == 0) {
// AT: first signer must be owner
if (!isOwner(_wallet, signer)) {
return false;
}
} else {
// "AT: signers must be different"
if (signer <= lastSigner) {
return false;
}
lastSigner = signer;
(isGuardian, guardians) = GuardianUtils.isGuardian(guardians, signer);
// "AT: signatures not valid"
if (!isGuardian) {
return false;
}
}
}
return true;
return validateSignatures(_wallet, _signHash, _signatures, OwnerSignature.Required);
}

function getRequiredSignatures(BaseWallet _wallet, bytes memory /* _data */) internal view returns (uint256) {
Expand Down
3 changes: 1 addition & 2 deletions contracts/modules/GuardianManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,7 @@ contract GuardianManager is BaseModule, RelayerModule {
view
returns (bool)
{
address signer = recoverSigner(_signHash, _signatures, 0);
return isOwner(_wallet, signer); // "GM: signer must be owner"
return validateSignatures(_wallet, _signHash, _signatures, OwnerSignature.Required);
}

function getRequiredSignatures(BaseWallet /* _wallet */, bytes memory _data) internal view returns (uint256) {
Expand Down
3 changes: 1 addition & 2 deletions contracts/modules/LockManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ contract LockManager is BaseModule, RelayerModule {
view
returns (bool)
{
(bool isGuardian, ) = GuardianUtils.isGuardian(guardianStorage.getGuardians(_wallet), recoverSigner(_signHash, _signatures, 0));
return isGuardian; // "LM: must be a guardian to lock or unlock"
return validateSignatures(_wallet, _signHash, _signatures, OwnerSignature.Disallowed);
}

function getRequiredSignatures(BaseWallet /* _wallet */, bytes memory /* _data */) internal view returns (uint256) {
Expand Down
47 changes: 0 additions & 47 deletions contracts/modules/RecoveryManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import "./common/BaseModule.sol";
import "./common/RelayerModule.sol";
import "../storage/GuardianStorage.sol";
import "../../lib/utils/SafeMath.sol";
import "../utils/GuardianUtils.sol";

/**
* @title RecoveryManager
Expand All @@ -45,12 +44,6 @@ contract RecoveryManager is BaseModule, RelayerModule {
uint32 guardianCount;
}

enum OwnerSignature {
Required,
Optional,
Disallowed
}

// Wallet specific storage
mapping (address => RecoveryConfig) internal recoveryConfigs;

Expand Down Expand Up @@ -200,46 +193,6 @@ contract RecoveryManager is BaseModule, RelayerModule {
}
}

function validateSignatures(
BaseWallet _wallet,
bytes32 _signHash,
bytes memory _signatures,
OwnerSignature _option
) internal view returns (bool)
{
address lastSigner = address(0);
address[] memory guardians = guardianStorage.getGuardians(_wallet);
bool isGuardian = false;

for (uint8 i = 0; i < _signatures.length / 65; i++) {
address signer = recoverSigner(_signHash, _signatures, i);

if (i == 0) {
if (_option == OwnerSignature.Required) {
// First signer must be owner
if (isOwner(_wallet, signer)) {
continue;
}
return false;
} else if (_option == OwnerSignature.Optional) {
// First signer can be owner
if (isOwner(_wallet, signer)) {
continue;
}
}
}
if (signer <= lastSigner) {
return false;
} // Signers must be different
lastSigner = signer;
(isGuardian, guardians) = GuardianUtils.isGuardian(guardians, signer);
if (!isGuardian) {
return false;
}
}
return true;
}

function getRequiredSignatures(BaseWallet _wallet, bytes memory _data) internal view returns (uint256) {
bytes4 methodId = functionPrefix(_data);
if (methodId == EXECUTE_RECOVERY_PREFIX) {
Expand Down
3 changes: 1 addition & 2 deletions contracts/modules/common/OnlyOwnerModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ contract OnlyOwnerModule is BaseModule, RelayerModule {
view
returns (bool)
{
address signer = recoverSigner(_signHash, _signatures, 0);
return isOwner(_wallet, signer); // "OOM: signer must be owner"
return validateSignatures(_wallet, _signHash, _signatures, OwnerSignature.Required);
}

function getRequiredSignatures(BaseWallet /* _wallet */, bytes memory /* _data */) internal view returns (uint256) {
Expand Down
72 changes: 66 additions & 6 deletions contracts/modules/common/RelayerModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
pragma solidity ^0.5.4;
import "../../wallet/BaseWallet.sol";
import "../../interfaces/Module.sol";
import "../../utils/GuardianUtils.sol";
import "./BaseModule.sol";

/**
Expand All @@ -34,6 +35,12 @@ contract RelayerModule is BaseModule {
mapping (bytes32 => bool) executedTx;
}

enum OwnerSignature {
Required,
Optional,
Disallowed
}

event TransactionExecuted(address indexed wallet, bool indexed success, bytes32 signedHash);

/**
Expand Down Expand Up @@ -67,7 +74,60 @@ contract RelayerModule is BaseModule {
BaseWallet _wallet,
bytes memory _data,
bytes32 _signHash,
bytes memory _signatures) internal view returns (bool);
bytes memory _signatures
)
internal view returns (bool);

/**
* @dev Validates the signatures provided with a relayed transaction.
* The method MUST throw if one or more signatures are not valid.
* @param _wallet The target wallet.
* @param _signHash The signed hash representing the relayed transaction.
* @param _signatures The signatures as a concatenated byte array.
* @param _option An enum indicating whether the owner is required, optional or disallowed.
*/
function validateSignatures(
BaseWallet _wallet,
bytes32 _signHash,
bytes memory _signatures,
OwnerSignature _option
)
internal view returns (bool)
{
address lastSigner = address(0);
address[] memory guardians;
if (_signatures.length > 65 || _option != OwnerSignature.Required)
guardians = guardianStorage.getGuardians(_wallet); // guardians are read only if they may be needed
bool isGuardian;

for (uint8 i = 0; i < _signatures.length / 65; i++) {
address signer = recoverSigner(_signHash, _signatures, i);

if (i == 0) {
if (_option == OwnerSignature.Required) {
// First signer must be owner
if (isOwner(_wallet, signer)) {
continue;
}
return false;
} else if (_option == OwnerSignature.Optional) {
// First signer can be owner
if (isOwner(_wallet, signer)) {
continue;
}
}
}
if (signer <= lastSigner) {
return false; // Signers must be different
}
lastSigner = signer;
(isGuardian, guardians) = GuardianUtils.isGuardian(guardians, signer);
if (!isGuardian) {
return false;
}
}
return true;
}

/* ************************************************************ */

Expand Down Expand Up @@ -100,11 +160,11 @@ contract RelayerModule is BaseModule {
require(requiredSignatures == 0 || validateSignatures(_wallet, _data, signHash, _signatures), "RM: Invalid signatures");
// The correctness of the refund is checked on the next line using an `if` instead of a `require`
// in order to prevent a failing refund from being replayable in the future.
if (verifyRefund(_wallet, _gasLimit, _gasPrice, requiredSignatures)) {
// solium-disable-next-line security/no-call-value
(success,) = address(this).call(_data);
refund(_wallet, startGas - gasleft(), _gasPrice, _gasLimit, requiredSignatures, msg.sender);
}
if (verifyRefund(_wallet, _gasLimit, _gasPrice, requiredSignatures)) {
// solium-disable-next-line security/no-call-value
(success,) = address(this).call(_data);
refund(_wallet, startGas - gasleft(), _gasPrice, _gasLimit, requiredSignatures, msg.sender);
}
emit TransactionExecuted(address(_wallet), success, signHash);
}

Expand Down

0 comments on commit 3640d72

Please sign in to comment.