Skip to content

Commit

Permalink
Add eip-1271 support
Browse files Browse the repository at this point in the history
  • Loading branch information
cristovaoth committed Sep 30, 2023
1 parent 93df3fa commit 805bfe1
Show file tree
Hide file tree
Showing 5 changed files with 341 additions and 94 deletions.
19 changes: 19 additions & 0 deletions contracts/signature/IERC1271.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity >=0.7.0 <0.9.0;

interface IERC1271 {
/**
* @notice EIP1271 method to validate a signature.
* @param hash Hash of the data signed on the behalf of address(this).
* @param signature Signature byte array associated with _data.
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes32 hash,
bytes memory signature
) external view returns (bytes4);
}
68 changes: 59 additions & 9 deletions contracts/signature/SignatureChecker.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0 <0.9.0;

import "./IERC1271.sol";

/// @title SignatureChecker - A contract that extracts and inspects signatures appended to calldata.
/// @notice currently supporting eip-712 and eip-1271 signatures
abstract contract SignatureChecker {
Expand All @@ -24,17 +26,29 @@ abstract contract SignatureChecker {
* @dev When signature present in calldata, returns the address of the signer.
*/
function moduleTxSignedBy() internal view returns (address signer) {
if (msg.data.length >= 4 + 32 + 32 + 1) {
bytes calldata data = msg.data;
if (data.length >= 4 + 65) {
(
bytes calldata dataTrimmed,
uint8 v,
bytes32 r,
bytes32 s
) = _splitSignature(msg.data);
bytes32 s,
uint8 v,
bool isContractSignature,
uint256 start,
uint256 end
) = _splitSignature(data);

bytes32 txHash = _moduleTxHash(dataTrimmed, nonce);
bytes32 hash = _moduleTxHash(data[:start], nonce);

signer = ecrecover(txHash, v, r, s);
if (isContractSignature) {
// When handling contract signatures the address
// of the contract is encoded into r
signer = address(uint160(uint256(r)));
if (!isValidContractSignature(signer, hash, data[start:end])) {
signer = address(0);
}
} else {
signer = ecrecover(hash, v, r, s);
}
}
}

Expand All @@ -47,13 +61,22 @@ abstract contract SignatureChecker {
)
private
pure
returns (bytes calldata dataTrimmed, uint8 v, bytes32 r, bytes32 s)
returns (
bytes32 r,
bytes32 s,
uint8 v,
bool isEIP1271,
uint256 start,
uint256 end
)
{
uint256 length = data.length;
dataTrimmed = data[0:length - 65];
r = bytes32(data[length - 65:]);
s = bytes32(data[length - 33:]);
v = uint8(bytes1(data[length - 1:]));
isEIP1271 = v == 0 && (uint256(s) < (length - 65));
start = isEIP1271 ? uint256(s) : length - 65;
end = isEIP1271 ? length - 65 : length;
}

/**
Expand All @@ -78,6 +101,30 @@ abstract contract SignatureChecker {
return keccak256(moduleTxData);
}

function isValidContractSignature(
address signer,
bytes32 hash,
bytes calldata signature
) internal view returns (bool result) {
uint256 size;
assembly {
size := extcodesize(signer)
}
if (size == 0) {
return false;
}

(bool success, bytes memory returnData) = signer.staticcall(
abi.encodeWithSelector(
IERC1271.isValidSignature.selector,
hash,
signature
)
);

return success == true && bytes4(returnData) == EIP1271_MAGIC_VALUE;
}

// keccak256(
// "EIP712Domain(uint256 chainId,address verifyingContract)"
// );
Expand All @@ -89,4 +136,7 @@ abstract contract SignatureChecker {
// );
bytes32 private constant MODULE_TX_TYPEHASH =
0xd6c6b5df57eef4e79cab990a377d29dc4c5bbb016a6293120d53f49c54144227;

// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 private constant EIP1271_MAGIC_VALUE = 0x1626ba7e;
}
29 changes: 29 additions & 0 deletions contracts/test/TestSignature.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,35 @@ pragma solidity >=0.8.0;

import "../signature/SignatureChecker.sol";

contract ContractSignerYes is IERC1271 {
function isValidSignature(
bytes32,
bytes memory
) external pure override returns (bytes4) {
return 0x1626ba7e;
}
}

contract ContractSignerNo is IERC1271 {
function isValidSignature(
bytes32,
bytes memory
) external pure override returns (bytes4) {
return 0x33333333;
}
}

contract ContractSignerFaulty {}

contract ContractSignerReturnSize {
function isValidSignature(
bytes32,
bytes memory
) external pure returns (bytes2) {
return 0x1626;
}
}

contract TestSignature is SignatureChecker {
event Hello(address signer);

Expand Down
85 changes: 0 additions & 85 deletions test/06_Eip712Signature.spec.ts

This file was deleted.

Loading

0 comments on commit 805bfe1

Please sign in to comment.