From f69ec1222aaa3e900214ea3da58e12bbe2ae493f Mon Sep 17 00:00:00 2001 From: Alan Donoso Naumczuk Date: Sun, 29 Dec 2024 15:31:50 -0300 Subject: [PATCH] feat: BaseSource now does source validation using EIP-712 --- contracts/core/base/BaseSource.sol | 43 +++++++++++++++---- .../rules/base/RestrictedSignersRule.sol | 18 +++++--- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/contracts/core/base/BaseSource.sol b/contracts/core/base/BaseSource.sol index 8b6c16e0..f0b52316 100644 --- a/contracts/core/base/BaseSource.sol +++ b/contracts/core/base/BaseSource.sol @@ -6,8 +6,12 @@ import {ISource} from "./../interfaces/ISource.sol"; import {SourceStamp} from "./../types/Types.sol"; abstract contract BaseSource is ISource { - uint256 internal immutable EC_SIGNATURE_LENGTH = 65; - bytes2 internal immutable EIP191_VERSION_BYTE_0X00_HEADER = 0x1900; + bytes2 internal immutable EIP191_VERSION_BYTE_0X01_HEADER = 0x1901; + string constant EIP712_DOMAIN_VERSION = "1"; + bytes32 constant EIP712_DOMAIN_VERSION_HASH = keccak256(bytes(EIP712_DOMAIN_VERSION)); + bytes32 constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 constant SOURCE_STAMP_TYPEHASH = keccak256("SourceStamp(address source,uint256 nonce,uint256 deadline)"); mapping(uint256 => bool) internal _wasSourceStampNonceUsed; @@ -24,13 +28,8 @@ abstract contract BaseSource is ISource { require(!_wasSourceStampNonceUsed[sourceStamp.nonce]); require(sourceStamp.deadline >= block.timestamp); require(sourceStamp.source == address(this)); - require(sourceStamp.signature.length == EC_SIGNATURE_LENGTH); _wasSourceStampNonceUsed[sourceStamp.nonce] = true; - bytes32 sourceStampHash = keccak256( - abi.encodePacked( - EIP191_VERSION_BYTE_0X00_HEADER, sourceStamp.source, sourceStamp.nonce, sourceStamp.deadline - ) - ); + bytes32 digest = _calculateDigest(_calculateHashStruct(sourceStamp)); bytes32 r; bytes32 s; uint8 v; @@ -40,11 +39,37 @@ abstract contract BaseSource is ISource { s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } - address signer = ecrecover(sourceStampHash, v, r, s); + address signer = ecrecover(digest, v, r, s); require(_isValidSourceStampSigner(signer)); } function _isValidSourceStampSigner( address signer ) internal virtual returns (bool); + + function _calculateHashStruct( + SourceStamp memory sourceStamp + ) private pure returns (bytes32) { + return keccak256(abi.encode(SOURCE_STAMP_TYPEHASH, sourceStamp.source, sourceStamp.nonce, sourceStamp.deadline)); + } + + function _calculateDigest( + bytes32 hashStruct + ) private view returns (bytes32) { + return keccak256( + abi.encodePacked(EIP191_VERSION_BYTE_0X01_HEADER, _calculateDomainSeparatorHashStruct(), hashStruct) + ); + } + + function _calculateDomainSeparatorHashStruct() private view returns (bytes32) { + return keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256("Lens Source"), + EIP712_DOMAIN_VERSION_HASH, + block.chainid, + address(this) + ) + ); + } } diff --git a/contracts/rules/base/RestrictedSignersRule.sol b/contracts/rules/base/RestrictedSignersRule.sol index c868dae7..62881477 100644 --- a/contracts/rules/base/RestrictedSignersRule.sol +++ b/contracts/rules/base/RestrictedSignersRule.sol @@ -67,11 +67,15 @@ abstract contract RestrictedSignersRule is MetadataBased { "RestrictedSignerMessage(bytes4 functionSelector,bytes abiEncodedParams,uint256 nonce,uint256 deadline)" ); - constructor(string memory metadataURI) { + constructor( + string memory metadataURI + ) { _setMetadataURI(metadataURI); } - function _emitMetadataURISet(string memory metadataURI) internal override { + function _emitMetadataURISet( + string memory metadataURI + ) internal override { emit Lens_Rule_MetadataURISet(metadataURI); } @@ -125,7 +129,9 @@ abstract contract RestrictedSignersRule is MetadataBased { _validateRecoveredAddress(digest, signature); } - function _calculateMessageHashStruct(RestrictedSignerMessage memory message) private pure returns (bytes32) { + function _calculateMessageHashStruct( + RestrictedSignerMessage memory message + ) private pure returns (bytes32) { return keccak256( abi.encode( RESTRICTED_SIGNER_MESSAGE_TYPEHASH, @@ -137,7 +143,9 @@ abstract contract RestrictedSignersRule is MetadataBased { ); } - function _calculateDigest(bytes32 messageHashStruct) private view returns (bytes32) { + function _calculateDigest( + bytes32 messageHashStruct + ) private view returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _calculateDomainSeparatorHashStruct(), messageHashStruct)); } @@ -148,7 +156,7 @@ abstract contract RestrictedSignersRule is MetadataBased { keccak256("Lens Protocol Restricted Signer Rule"), EIP712_DOMAIN_VERSION_HASH, block.chainid, - msg.sender // This is the address of the primitive, and we assume the primitive calls the rule + msg.sender // TODO: This is using primitive's address, maybe should be address(this), so it's rule addr ) ); }