diff --git a/contracts/core/FollowNFT.sol b/contracts/core/FollowNFT.sol index 51955d3..7d67608 100644 --- a/contracts/core/FollowNFT.sol +++ b/contracts/core/FollowNFT.sol @@ -249,12 +249,12 @@ contract FollowNFT is HubRestricted, LensNFTBase, ERC2981CollectionRoyalties, IF return _followApprovalByFollowTokenId[followTokenId]; } - function burnWithSig(uint256 followTokenId, DataTypes.EIP712Signature calldata sig) + function burnWithSig(uint256 followTokenId, DataTypes.EIP712Signature calldata signature) public override { _unfollowIfHasFollower(followTokenId); - super.burnWithSig(followTokenId, sig); + super.burnWithSig(followTokenId, signature); } function burn(uint256 followTokenId) public override { diff --git a/contracts/core/LensHub.sol b/contracts/core/LensHub.sol index 486798b..f92278f 100644 --- a/contracts/core/LensHub.sol +++ b/contracts/core/LensHub.sol @@ -36,6 +36,7 @@ import {MetaTxHelpers} from 'contracts/libraries/helpers/MetaTxHelpers.sol'; * 2. Almost every event in the protocol emits the current block timestamp, reducing the need to fetch it manually. */ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHubStorage, ILensHub { + // Constant for upgradeability purposes, see VersionedInitializable. Do not confuse with EIP-712 revision number. uint256 internal constant REVISION = 1; address internal immutable FOLLOW_NFT_IMPL; @@ -70,16 +71,16 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub ) external override initializer { super._initialize(name, symbol); GeneralLib.initState(DataTypes.ProtocolState.Paused); - _setGovernance(newGovernance); + GeneralLib.setGovernance(newGovernance); } - /// *********************** - /// *****GOV FUNCTIONS***** - /// *********************** + ///////////////////////////////// + /// GOV FUNCTIONS /// + ///////////////////////////////// /// @inheritdoc ILensHub function setGovernance(address newGovernance) external override onlyGov { - _setGovernance(newGovernance); + GeneralLib.setGovernance(newGovernance); } /// @inheritdoc ILensHub @@ -128,28 +129,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub emit Events.CollectModuleWhitelisted(collectModule, whitelist, block.timestamp); } - /// ********************************* - /// *****PROFILE OWNER FUNCTIONS***** - /// ********************************* - - /// @inheritdoc ILensNFTBase - function permit( - address spender, - uint256 tokenId, - DataTypes.EIP712Signature calldata sig - ) external override { - GeneralLib.permit(spender, tokenId, sig); - } - - /// @inheritdoc ILensNFTBase - function permitForAll( - address owner, - address operator, - bool approved, - DataTypes.EIP712Signature calldata sig - ) external override { - GeneralLib.permitForAll(owner, operator, approved, sig); - } + /////////////////////////////////////////// + /// PROFILE OWNER FUNCTIONS /// + /////////////////////////////////////////// /// @inheritdoc ILensHub function createProfile(DataTypes.CreateProfileData calldata vars) @@ -322,9 +304,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub ProfileLib.setFollowNFTURI(profileId, followNFTURI); } - /// ********************************* - /// ****** PUBLISHING FUNCTIONS ***** - /// ********************************* + //////////////////////////////////////// + /// PUBLISHING FUNCTIONS /// + //////////////////////////////////////// /// @inheritdoc ILensHub function post(DataTypes.PostParams calldata postParams) @@ -477,9 +459,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub _burn(tokenId); } - /// *************************************** - /// *****PROFILE INTERACTION FUNCTIONS***** - /// *************************************** + ///////////////////////////////////////////////// + /// PROFILE INTERACTION FUNCTIONS /// + ///////////////////////////////////////////////// /// @inheritdoc ILensHub function follow( @@ -683,9 +665,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub emit Events.Unfollowed(unfollowerProfileId, idOfProfileUnfollowed, block.timestamp); } - /// ********************************* - /// *****EXTERNAL VIEW FUNCTIONS***** - /// ********************************* + /////////////////////////////////////////// + /// EXTERNAL VIEW FUNCTIONS /// + /////////////////////////////////////////// function isFollowing(uint256 followerProfileId, uint256 followedProfileId) external @@ -920,7 +902,7 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub * @dev Overrides the LensNFTBase function to compute the domain separator in the GeneralLib. */ function getDomainSeparator() external view override returns (bytes32) { - return GeneralLib.getDomainSeparator(); + return MetaTxHelpers.getDomainSeparator(); } /** @@ -938,13 +920,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub ); } - /// **************************** - /// *****INTERNAL FUNCTIONS***** - /// **************************** - - function _setGovernance(address newGovernance) internal { - GeneralLib.setGovernance(newGovernance); - } + ////////////////////////////////////// + /// INTERNAL FUNCTIONS /// + ////////////////////////////////////// function _beforeTokenTransfer( address from, diff --git a/contracts/core/base/LensNFTBase.sol b/contracts/core/base/LensNFTBase.sol index 8aa3a20..d13632a 100644 --- a/contracts/core/base/LensNFTBase.sol +++ b/contracts/core/base/LensNFTBase.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; -import {ILensNFTBase} from '../../interfaces/ILensNFTBase.sol'; -import {Errors} from '../../libraries/Errors.sol'; -import {DataTypes} from '../../libraries/DataTypes.sol'; -import {Events} from '../../libraries/Events.sol'; -import {MetaTxHelpers} from '../../libraries/helpers/MetaTxHelpers.sol'; +import {ILensNFTBase} from 'contracts/interfaces/ILensNFTBase.sol'; +import {Errors} from 'contracts/libraries/Errors.sol'; +import {DataTypes} from 'contracts/libraries/DataTypes.sol'; +import {Events} from 'contracts/libraries/Events.sol'; +import {MetaTxHelpers} from 'contracts/libraries/helpers/MetaTxHelpers.sol'; import {ERC721Time} from './ERC721Time.sol'; -import {ERC721Enumerable} from './ERC721Enumerable.sol'; +import {ERC721Enumerable} from 'contracts/core/base/ERC721Enumerable.sol'; /** * @title LensNFTBase @@ -20,20 +20,6 @@ import {ERC721Enumerable} from './ERC721Enumerable.sol'; * constructor with an initializer. */ abstract contract LensNFTBase is ERC721Enumerable, ILensNFTBase { - bytes32 internal constant EIP712_REVISION_HASH = keccak256('1'); - bytes32 internal constant PERMIT_TYPEHASH = - keccak256('Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)'); - bytes32 internal constant PERMIT_FOR_ALL_TYPEHASH = - keccak256( - 'PermitForAll(address owner,address operator,bool approved,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant BURN_TYPEHASH = - keccak256('BurnWithSig(uint256 tokenId,uint256 nonce,uint256 deadline)'); - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ); - mapping(address => uint256) public sigNonces; /** @@ -55,62 +41,21 @@ abstract contract LensNFTBase is ERC721Enumerable, ILensNFTBase { function permit( address spender, uint256 tokenId, - DataTypes.EIP712Signature calldata sig + DataTypes.EIP712Signature calldata signature ) external virtual override { - if (spender == address(0)) revert Errors.ZeroSpender(); - address owner = ownerOf(tokenId); - unchecked { - MetaTxHelpers._validateRecoveredAddress( - _calculateDigest( - keccak256( - abi.encode( - PERMIT_TYPEHASH, - spender, - tokenId, - sigNonces[owner]++, - sig.deadline - ) - ) - ), - owner, - sig - ); + if (spender == address(0)) { + revert Errors.ZeroSpender(); } + if (signature.signer != ownerOf(tokenId)) { + revert Errors.NotProfileOwner(); + } + MetaTxHelpers.validatePermitSignature(signature, spender, tokenId); _approve(spender, tokenId); } - /// @inheritdoc ILensNFTBase - function permitForAll( - address owner, - address operator, - bool approved, - DataTypes.EIP712Signature calldata sig - ) external virtual override { - if (operator == address(0)) revert Errors.ZeroSpender(); - unchecked { - MetaTxHelpers._validateRecoveredAddress( - _calculateDigest( - keccak256( - abi.encode( - PERMIT_FOR_ALL_TYPEHASH, - owner, - operator, - approved, - sigNonces[owner]++, - sig.deadline - ) - ) - ), - owner, - sig - ); - } - _setOperatorApproval(owner, operator, approved); - } - /// @inheritdoc ILensNFTBase function getDomainSeparator() external view virtual override returns (bytes32) { - return _calculateDomainSeparator(); + return MetaTxHelpers.getDomainSeparator(); } /// @inheritdoc ILensNFTBase @@ -120,54 +65,15 @@ abstract contract LensNFTBase is ERC721Enumerable, ILensNFTBase { } /// @inheritdoc ILensNFTBase - function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) + function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata signature) public virtual override { - address owner = ownerOf(tokenId); - unchecked { - MetaTxHelpers._validateRecoveredAddress( - _calculateDigest( - keccak256(abi.encode(BURN_TYPEHASH, tokenId, sigNonces[owner]++, sig.deadline)) - ), - owner, - sig - ); + if (_isApprovedOrOwner(signature.signer, tokenId)) { + revert Errors.NotOwnerOrApproved(); } + MetaTxHelpers.validateBurnSignature(signature, tokenId); _burn(tokenId); } - - /** - * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. - */ - function _calculateDomainSeparator() internal view returns (bytes32) { - return - keccak256( - abi.encode( - EIP712_DOMAIN_TYPEHASH, - keccak256(bytes(name())), - EIP712_REVISION_HASH, - block.chainid, - address(this) - ) - ); - } - - /** - * @dev Calculates EIP712 digest based on the current DOMAIN_SEPARATOR. - * - * @param hashedMessage The message hash from which the digest should be calculated. - * - * @return bytes32 A 32-byte output representing the EIP712 digest. - */ - function _calculateDigest(bytes32 hashedMessage) internal view returns (bytes32) { - bytes32 digest; - unchecked { - digest = keccak256( - abi.encodePacked('\x19\x01', _calculateDomainSeparator(), hashedMessage) - ); - } - return digest; - } } diff --git a/contracts/interfaces/ILensNFTBase.sol b/contracts/interfaces/ILensNFTBase.sol index 54da496..8da2a06 100644 --- a/contracts/interfaces/ILensNFTBase.sol +++ b/contracts/interfaces/ILensNFTBase.sol @@ -20,28 +20,12 @@ interface ILensNFTBase { * * @param spender The NFT spender. * @param tokenId The NFT token ID to approve. - * @param sig The EIP712 signature struct. + * @param signature The EIP712 signature struct. */ function permit( address spender, uint256 tokenId, - DataTypes.EIP712Signature calldata sig - ) external; - - /** - * @notice Implementation of an EIP-712 permit-style function for ERC-721 operator approvals. Allows - * an operator address to control all NFTs a given owner owns. - * - * @param owner The owner to set operator approvals for. - * @param operator The operator to approve. - * @param approved Whether to approve or revoke approval from the operator. - * @param sig The EIP712 signature struct. - */ - function permitForAll( - address owner, - address operator, - bool approved, - DataTypes.EIP712Signature calldata sig + DataTypes.EIP712Signature calldata signature ) external; /** @@ -57,9 +41,9 @@ interface ILensNFTBase { * a token on behalf of the owner with a signature. * * @param tokenId The token ID of the token to burn. - * @param sig The EIP712 signature struct. + * @param signature The EIP712 signature struct. */ - function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) external; + function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata signature) external; /** * @notice Returns the domain separator for this NFT contract. diff --git a/contracts/libraries/Constants.sol b/contracts/libraries/Constants.sol index 2430e47..a661888 100644 --- a/contracts/libraries/Constants.sol +++ b/contracts/libraries/Constants.sol @@ -6,7 +6,6 @@ string constant FOLLOW_NFT_NAME_SUFFIX = '-Follower'; string constant FOLLOW_NFT_SYMBOL_SUFFIX = '-Fl'; string constant COLLECT_NFT_NAME_INFIX = '-Collect-'; string constant COLLECT_NFT_SYMBOL_INFIX = '-Cl-'; -uint64 constant FIRST_DELEGATED_EXECUTORS_CONFIG_NUMBER = 1; uint8 constant MAX_HANDLE_LENGTH = 31; uint16 constant MAX_PROFILE_IMAGE_URI_LENGTH = 6000; @@ -37,19 +36,6 @@ uint256 constant PROFILE_METADATA_MAPPING_SLOT = 26; uint256 constant BLOCK_STATUS_MAPPING_SLOT = 27; uint256 constant NAME_SLOT_GT_31 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563; -// We store the polygon chain ID and domain separator as constants to save gas. -uint256 constant POLYGON_CHAIN_ID = 137; -bytes32 constant POLYGON_DOMAIN_SEPARATOR = 0x78e10b2874b1a1d4436464e65903d3bdc28b68f8d023df2e47b65f8caa45c4bb; -// keccak256( -// abi.encode( -// EIP712_DOMAIN_TYPEHASH, -// keccak256('Lens Protocol Profiles'), -// EIP712_REVISION_HASH, -// POLYGON_CHAIN_ID, -// address(0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d) -// ) -// ); - // Profile struct offsets // uint256 pubCount; // offset 0 uint256 constant PROFILE_FOLLOW_MODULE_OFFSET = 1; @@ -66,56 +52,4 @@ uint256 constant PUBLICATION_REFERENCE_MODULE_OFFSET = 3; // offset 3 uint256 constant PUBLICATION_COLLECT_MODULE_OFFSET = 4; // offset 4 uint256 constant PUBLICATION_COLLECT_NFT_OFFSET = 5; // offset 4 -// We also store typehashes here -bytes32 constant EIP712_REVISION_HASH = keccak256('1'); -bytes32 constant PERMIT_TYPEHASH = keccak256( - 'Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)' -); -bytes32 constant PERMIT_FOR_ALL_TYPEHASH = keccak256( - 'PermitForAll(address owner,address operator,bool approved,uint256 nonce,uint256 deadline)' -); -bytes32 constant BURN_TYPEHASH = keccak256('Burn(uint256 tokenId,uint256 nonce,uint256 deadline)'); -bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' -); -bytes32 constant SET_FOLLOW_MODULE_TYPEHASH = keccak256( - 'SetFollowModule(uint256 profileId,address followModule,bytes followModuleInitData,uint256 nonce,uint256 deadline)' -); -bytes32 constant SET_FOLLOW_NFT_URI_TYPEHASH = keccak256( - 'SetFollowNFTURI(uint256 profileId,string followNFTURI,uint256 nonce,uint256 deadline)' -); -bytes32 constant CHANGE_DELEGATED_EXECUTORS_CONFIG_TYPEHASH = keccak256( - 'ChangeDelegatedExecutorsConfig(uint256 delegatorProfileId,address[] executors,bool[] approvals,uint64 configNumber,bool switchToGivenConfig,uint256 nonce,uint256 deadline)' -); -bytes32 constant SET_PROFILE_IMAGE_URI_TYPEHASH = keccak256( - 'SetProfileImageURI(uint256 profileId,string imageURI,uint256 nonce,uint256 deadline)' -); -bytes32 constant POST_TYPEHASH = keccak256( - 'Post(uint256 profileId,string contentURI,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' -); -bytes32 constant COMMENT_TYPEHASH = keccak256( - 'Comment(uint256 profileId,string contentURI,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' -); -bytes32 constant MIRROR_TYPEHASH = keccak256( - 'Mirror(uint256 profileId,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,uint256 nonce,uint256 deadline)' -); -bytes32 constant QUOTE_TYPEHASH = keccak256( - 'Quote(uint256 profileId,string contentURI,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' -); -bytes32 constant FOLLOW_TYPEHASH = keccak256( - 'Follow(uint256 followerProfileId,uint256[] idsOfProfilesToFollow,uint256[] followTokenIds,bytes[] datas,uint256 nonce,uint256 deadline)' -); -bytes32 constant UNFOLLOW_TYPEHASH = keccak256( - 'Unfollow(uint256 unfollowerProfileId,uint256[] idsOfProfilesToUnfollow,uint256 nonce,uint256 deadline)' -); -bytes32 constant SET_BLOCK_STATUS_TYPEHASH = keccak256( - 'SetBlockStatus(uint256 byProfileId,uint256[] idsOfProfilesToSetBlockStatus,bool[] blockStatus,uint256 nonce,uint256 deadline)' -); -bytes32 constant COLLECT_TYPEHASH = keccak256( - 'Collect(uint256 publicationCollectedProfileId,uint256 publicationCollectedId,uint256 collectorProfileId,uint256 referrerProfileId,uint256 referrerPubId,bytes collectModuleData,uint256 nonce,uint256 deadline)' -); -bytes32 constant SET_PROFILE_METADATA_URI_TYPEHASH = keccak256( - 'SetProfileMetadataURI(uint256 profileId,string metadata,uint256 nonce,uint256 deadline)' -); - bytes4 constant EIP1271_MAGIC_VALUE = 0x1626ba7e; diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index 381a8e6..7f48804 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -113,14 +113,14 @@ library DataTypes { * @param profileId The token ID of the profile to change the followModule for. * @param followModule The followModule to set for the given profile, must be whitelisted. * @param followModuleInitData The data to be passed to the followModule for initialization. - * @param sig The EIP712Signature struct containing the profile owner's signature. + * @param signature The EIP712Signature struct containing the profile owner's signature. */ struct SetFollowModuleWithSigData { address delegatedSigner; uint256 profileId; address followModule; bytes followModuleInitData; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -133,7 +133,7 @@ library DataTypes { * @param switchToGivenConfig A boolean indicanting if the configuration will be switched to the one with the given * number. - * @param sig The EIP712Signature struct containing to the signer setting the approval's signature. + * @param signature The EIP712Signature struct containing to the signer setting the approval's signature. */ struct ChangeDelegatedExecutorsConfigWithSigData { uint256 delegatorProfileId; @@ -141,7 +141,7 @@ library DataTypes { bool[] approvals; uint64 configNumber; bool switchToGivenConfig; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -151,13 +151,13 @@ library DataTypes { * @param delegatedSigner The delegated executor signer, must be either zero, defaulting to the profile owner, or a delegated executor. * @param profileId The token ID of the profile to set the URI for. * @param imageURI The URI to set for the given profile image. - * @param sig The EIP712Signature struct containing the profile owner's signature. + * @param signature The EIP712Signature struct containing the profile owner's signature. */ struct SetProfileImageURIWithSigData { address delegatedSigner; uint256 profileId; string imageURI; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -167,13 +167,13 @@ library DataTypes { * @param delegatedSigner The delegated executor signer, must be either zero, defaulting to the profile owner, or a delegated executor. * @param profileId The token ID of the profile for which to set the followNFT URI. * @param followNFTURI The follow NFT URI to set. - * @param sig The EIP712Signature struct containing the followNFT's associated profile owner's signature. + * @param signature The EIP712Signature struct containing the followNFT's associated profile owner's signature. */ struct SetFollowNFTURIWithSigData { address delegatedSigner; uint256 profileId; string followNFTURI; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -309,7 +309,7 @@ library DataTypes { * @param idsOfProfilesToFollow The array of IDs of profiles to follow. * @param followTokenIds The array of follow token IDs to use for each follow. * @param datas The arbitrary data array to pass to the follow module for each profile if needed. - * @param sig The EIP712Signature struct containing the follower's signature. + * @param signature The EIP712Signature struct containing the follower's signature. */ struct FollowWithSigData { address delegatedSigner; @@ -317,7 +317,7 @@ library DataTypes { uint256[] idsOfProfilesToFollow; uint256[] followTokenIds; bytes[] datas; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -328,13 +328,13 @@ library DataTypes { * or a delegated executor. * @param unfollowerProfileId The ID of the profile the unfollows are being executed for. * @param idsOfProfilesToUnfollow The array of IDs of profiles to unfollow. - * @param sig The EIP712Signature struct containing the follower's signature. + * @param signature The EIP712Signature struct containing the follower's signature. */ struct UnfollowWithSigData { address delegatedSigner; uint256 unfollowerProfileId; uint256[] idsOfProfilesToUnfollow; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -346,14 +346,14 @@ library DataTypes { * @param byProfileId The ID of the profile the block status sets are being executed for. * @param idsOfProfilesToSetBlockStatus The array of IDs of profiles to set block status. * @param blockStatus The array of block status to use for each setting. - * @param sig The EIP712Signature struct containing the blocker's signature. + * @param signature The EIP712Signature struct containing the blocker's signature. */ struct SetBlockStatusWithSigData { address delegatedSigner; uint256 byProfileId; uint256[] idsOfProfilesToSetBlockStatus; bool[] blockStatus; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -381,13 +381,13 @@ library DataTypes { * @param delegatedSigner The delegated executor signer, must be either zero, defaulting to the profile owner, or a delegated executor. * @param profileId The profile ID for which to set the metadata. * @param metadataURI The metadata string to set for the profile and user. - * @param sig The EIP712Signature struct containing the user's signature. + * @param signature The EIP712Signature struct containing the user's signature. */ struct SetProfileMetadataURIWithSigData { address delegatedSigner; uint256 profileId; string metadataURI; - EIP712Signature sig; + EIP712Signature signature; } /** @@ -398,13 +398,13 @@ library DataTypes { * @param follower The follower which is the message signer. * @param profileIds The token ID array of the profiles. * @param enables The array of booleans to enable/disable follows. - * @param sig The EIP712Signature struct containing the follower's signature. + * @param signature The EIP712Signature struct containing the follower's signature. */ struct ToggleFollowWithSigData { address follower; uint256[] profileIds; bool[] enables; - EIP712Signature sig; + EIP712Signature signature; } /** diff --git a/contracts/libraries/GeneralLib.sol b/contracts/libraries/GeneralLib.sol index dea9fe6..67f27d0 100644 --- a/contracts/libraries/GeneralLib.sol +++ b/contracts/libraries/GeneralLib.sol @@ -206,67 +206,6 @@ library GeneralLib { return InteractionHelpers.collect(collectParams, transactionExecutor, collectNFTImpl); } - /** - * @notice Approves an address to spend a token using via signature. - * - * @param spender The spender to approve. - * @param tokenId The token ID to approve the spender for. - * @param sig the EIP712Signature struct containing the token owner's signature. - */ - function permit( - address spender, - uint256 tokenId, - DataTypes.EIP712Signature calldata sig - ) external { - // The `Approved()` event is emitted from `basePermit()`. - MetaTxHelpers.basePermit(spender, tokenId, sig); - - // Store the approved address in the token's approval mapping slot. - assembly { - mstore(0, tokenId) - mstore(32, TOKEN_APPROVAL_MAPPING_SLOT) - let slot := keccak256(0, 64) - sstore(slot, spender) - } - } - - /** - * @notice Approves a user to operate on all of an owner's tokens via signature. - * - * @param owner The owner to approve the operator for, this is the signer. - * @param operator The operator to approve for the owner. - * @param approved Whether or not the operator should be approved. - * @param sig the EIP712Signature struct containing the token owner's signature. - */ - function permitForAll( - address owner, - address operator, - bool approved, - DataTypes.EIP712Signature calldata sig - ) external { - // The `ApprovedForAll()` event is emitted from `basePermitForAll()`. - MetaTxHelpers.basePermitForAll(owner, operator, approved, sig); - - // Store whether the operator is approved in the appropriate mapping slot. - assembly { - mstore(0, owner) - mstore(32, OPERATOR_APPROVAL_MAPPING_SLOT) - mstore(32, keccak256(0, 64)) - mstore(0, operator) - let slot := keccak256(0, 64) - sstore(slot, approved) - } - } - - /** - * @notice Returns the domain separator. - * - * @return bytes32 The domain separator. - */ - function getDomainSeparator() external view returns (bytes32) { - return MetaTxHelpers.getDomainSeparator(); - } - function getContentURI(uint256 profileId, uint256 pubId) external view returns (string memory) { (uint256 rootProfileId, uint256 rootPubId, ) = GeneralHelpers.getPointedIfMirror( profileId, diff --git a/contracts/libraries/constants/TypehashConstants.sol b/contracts/libraries/constants/TypehashConstants.sol new file mode 100644 index 0000000..c2f645b --- /dev/null +++ b/contracts/libraries/constants/TypehashConstants.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.15; + +library TypehashConstants { + + bytes32 constant BURN = keccak256('Burn(uint256 tokenId,uint256 nonce,uint256 deadline)'); + + bytes32 constant CHANGE_DELEGATED_EXECUTORS_CONFIG = keccak256('ChangeDelegatedExecutorsConfig(uint256 delegatorProfileId,address[] executors,bool[] approvals,uint64 configNumber,bool switchToGivenConfig,uint256 nonce,uint256 deadline)'); + + bytes32 constant COLLECT = keccak256('Collect(uint256 publicationCollectedProfileId,uint256 publicationCollectedId,uint256 collectorProfileId,uint256 referrerProfileId,uint256 referrerPubId,bytes collectModuleData,uint256 nonce,uint256 deadline)'); + + bytes32 constant COMMENT = keccak256('Comment(uint256 profileId,string contentURI,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)'); + + bytes32 constant EIP712_DOMAIN = keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); + + bytes32 constant FOLLOW = keccak256('Follow(uint256 followerProfileId,uint256[] idsOfProfilesToFollow,uint256[] followTokenIds,bytes[] datas,uint256 nonce,uint256 deadline)'); + + bytes32 constant MIRROR = keccak256('Mirror(uint256 profileId,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,uint256 nonce,uint256 deadline)'); + + bytes32 constant PERMIT = keccak256('Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)'); + + bytes32 constant POST = keccak256('Post(uint256 profileId,string contentURI,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)'); + + bytes32 constant QUOTE = keccak256('Quote(uint256 profileId,string contentURI,uint256 pointedProfileId,uint256 pointedPubId,uint256 referrerProfileId,uint256 referrerPubId,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)'); + + bytes32 constant SET_BLOCK_STATUS = keccak256('SetBlockStatus(uint256 byProfileId,uint256[] idsOfProfilesToSetBlockStatus,bool[] blockStatus,uint256 nonce,uint256 deadline)'); + + bytes32 constant SET_FOLLOW_MODULE = keccak256('SetFollowModule(uint256 profileId,address followModule,bytes followModuleInitData,uint256 nonce,uint256 deadline)'); + + bytes32 constant SET_FOLLOW_NFT_URI = keccak256('SetFollowNFTURI(uint256 profileId,string followNFTURI,uint256 nonce,uint256 deadline)'); + + bytes32 constant SET_PROFILE_IMAGE_URI = keccak256('SetProfileImageURI(uint256 profileId,string imageURI,uint256 nonce,uint256 deadline)'); + + bytes32 constant SET_PROFILE_METADATA_URI = keccak256('SetProfileMetadataURI(uint256 profileId,string metadata,uint256 nonce,uint256 deadline)'); + + bytes32 constant UNFOLLOW = keccak256('Unfollow(uint256 unfollowerProfileId,uint256[] idsOfProfilesToUnfollow,uint256 nonce,uint256 deadline)'); +} diff --git a/contracts/libraries/helpers/MetaTxHelpers.sol b/contracts/libraries/helpers/MetaTxHelpers.sol index b7b3e6b..a995b47 100644 --- a/contracts/libraries/helpers/MetaTxHelpers.sol +++ b/contracts/libraries/helpers/MetaTxHelpers.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import {IEIP1271Implementer} from '../../interfaces/IEIP1271Implementer.sol'; -import {DataTypes} from '../DataTypes.sol'; -import {Errors} from '../Errors.sol'; -import {DataTypes} from '../DataTypes.sol'; -import {GeneralHelpers} from './GeneralHelpers.sol'; -import '../Constants.sol'; +import {IEIP1271Implementer} from 'contracts/interfaces/IEIP1271Implementer.sol'; +import {DataTypes} from 'contracts/libraries/DataTypes.sol'; +import {Errors} from 'contracts/libraries/Errors.sol'; +import {DataTypes} from 'contracts/libraries/DataTypes.sol'; +import {GeneralHelpers} from 'contracts/libraries/helpers/GeneralHelpers.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; +import 'contracts/libraries/Constants.sol'; /** * @title MetaTxHelpers @@ -22,62 +23,25 @@ import '../Constants.sol'; * are incremented from this library as well. */ library MetaTxHelpers { - /// Permit and PermitForAll emit these ERC721 events here an optimization. - event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); - event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + bytes32 constant EIP712_REVISION_HASH = keccak256('2'); /** - * @notice Validates parameters and increments the nonce for a given owner using the `permit()` - * function. + * @dev We store the domain separator and LensHub Proxy address as constants to save gas. * - * @param spender The spender to approve. - * @param tokenId The token ID to approve the spender for. - * @param sig the EIP712Signature struct containing the token owner's signature. + * keccak256( + * abi.encode( + * keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), + * keccak256('Lens Protocol Profiles') // Contract Name + * keccak256('2'), // Revision Hash + * 137, // Polygon Chain ID + * address(0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d) // Verifying Contract Address - LensHub Address + * ) + * ); */ - function basePermit( - address spender, - uint256 tokenId, - DataTypes.EIP712Signature calldata sig - ) internal { - if (spender == address(0)) revert Errors.ZeroSpender(); - address owner = GeneralHelpers.unsafeOwnerOf(tokenId); - _validateRecoveredAddress( - _calculateDigest( - keccak256( - abi.encode(PERMIT_TYPEHASH, spender, tokenId, _sigNonces(owner), sig.deadline) - ) - ), - owner, - sig - ); - emit Approval(owner, spender, tokenId); - } + bytes32 constant LENS_HUB_CACHED_POLYGON_DOMAIN_SEPARATOR = + 0x78e10b2874b1a1d4436464e65903d3bdc28b68f8d023df2e47b65f8caa45c4bb; - function basePermitForAll( - address owner, - address operator, - bool approved, - DataTypes.EIP712Signature calldata sig - ) internal { - if (operator == address(0)) revert Errors.ZeroSpender(); - _validateRecoveredAddress( - _calculateDigest( - keccak256( - abi.encode( - PERMIT_FOR_ALL_TYPEHASH, - owner, - operator, - approved, - _sigNonces(owner), - sig.deadline - ) - ) - ), - owner, - sig - ); - emit ApprovalForAll(owner, operator, approved); - } + address constant LENS_HUB_ADDRESS = 0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d; // TODO: Check later function validateSetProfileMetadataURISignature( DataTypes.EIP712Signature calldata signature, @@ -88,7 +52,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - SET_PROFILE_METADATA_URI_TYPEHASH, + TypehashConstants.SET_PROFILE_METADATA_URI, profileId, keccak256(bytes(metadataURI)), _sigNonces(signature.signer), @@ -96,7 +60,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -111,7 +74,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - SET_FOLLOW_MODULE_TYPEHASH, + TypehashConstants.SET_FOLLOW_MODULE, profileId, followModule, keccak256(followModuleInitData), @@ -120,7 +83,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -139,7 +101,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - CHANGE_DELEGATED_EXECUTORS_CONFIG_TYPEHASH, + TypehashConstants.CHANGE_DELEGATED_EXECUTORS_CONFIG, delegatorProfileId, abi.encodePacked(executors), abi.encodePacked(approvals), @@ -150,7 +112,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -164,7 +125,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - SET_PROFILE_IMAGE_URI_TYPEHASH, + TypehashConstants.SET_PROFILE_IMAGE_URI, profileId, keccak256(bytes(imageURI)), _sigNonces(signature.signer), @@ -172,7 +133,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -186,7 +146,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - SET_FOLLOW_NFT_URI_TYPEHASH, + TypehashConstants.SET_FOLLOW_NFT_URI, profileId, keccak256(bytes(followNFTURI)), _sigNonces(signature.signer), @@ -194,47 +154,45 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } function validatePostSignature( - DataTypes.EIP712Signature calldata sig, + DataTypes.EIP712Signature calldata signature, DataTypes.PostParams calldata postParams ) internal { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( - POST_TYPEHASH, + TypehashConstants.POST, postParams.profileId, keccak256(bytes(postParams.contentURI)), postParams.collectModule, keccak256(postParams.collectModuleInitData), postParams.referenceModule, keccak256(postParams.referenceModuleInitData), - _sigNonces(sig.signer), - sig.deadline + _sigNonces(signature.signer), + signature.deadline ) ) ), - sig.signer, - sig + signature ); } function validateCommentSignature( - DataTypes.EIP712Signature calldata sig, + DataTypes.EIP712Signature calldata signature, DataTypes.CommentParams calldata commentParams ) internal { - uint256 nonce = _sigNonces(sig.signer); - uint256 deadline = sig.deadline; + uint256 nonce = _sigNonces(signature.signer); + uint256 deadline = signature.deadline; _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( - COMMENT_TYPEHASH, + TypehashConstants.COMMENT, commentParams.profileId, keccak256(bytes(commentParams.contentURI)), commentParams.pointedProfileId, @@ -251,21 +209,21 @@ library MetaTxHelpers { ) ) ), - sig + signature ); } function validateQuoteSignature( - DataTypes.EIP712Signature calldata sig, + DataTypes.EIP712Signature calldata signature, DataTypes.QuoteParams calldata quoteParams ) internal { - uint256 nonce = _sigNonces(sig.signer); - uint256 deadline = sig.deadline; + uint256 nonce = _sigNonces(signature.signer); + uint256 deadline = signature.deadline; _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( - COMMENT_TYPEHASH, + TypehashConstants.COMMENT, quoteParams.profileId, keccak256(bytes(quoteParams.contentURI)), quoteParams.pointedProfileId, @@ -282,32 +240,31 @@ library MetaTxHelpers { ) ) ), - sig + signature ); } function validateMirrorSignature( - DataTypes.EIP712Signature calldata sig, + DataTypes.EIP712Signature calldata signature, DataTypes.MirrorParams calldata mirrorParams ) internal { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( - MIRROR_TYPEHASH, + TypehashConstants.MIRROR, mirrorParams.profileId, mirrorParams.pointedProfileId, mirrorParams.pointedPubId, mirrorParams.referrerProfileId, mirrorParams.referrerPubId, keccak256(mirrorParams.referenceModuleData), - _sigNonces(sig.signer), - sig.deadline + _sigNonces(signature.signer), + signature.deadline ) ) ), - sig.signer, - sig + signature ); } @@ -318,14 +275,13 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - BURN_TYPEHASH, + TypehashConstants.BURN, tokenId, _sigNonces(signature.signer), signature.deadline ) ) ), - signature.signer, signature ); } @@ -352,7 +308,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - FOLLOW_TYPEHASH, + TypehashConstants.FOLLOW, followerProfileId, keccak256(abi.encodePacked(idsOfProfilesToFollow)), keccak256(abi.encodePacked(followTokenIds)), @@ -362,7 +318,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -376,7 +331,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - UNFOLLOW_TYPEHASH, + TypehashConstants.UNFOLLOW, unfollowerProfileId, keccak256(abi.encodePacked(idsOfProfilesToUnfollow)), _sigNonces(signature.signer), @@ -384,7 +339,6 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } @@ -399,7 +353,7 @@ library MetaTxHelpers { _calculateDigest( keccak256( abi.encode( - SET_BLOCK_STATUS_TYPEHASH, + TypehashConstants.SET_BLOCK_STATUS, byProfileId, keccak256(abi.encodePacked(idsOfProfilesToSetBlockStatus)), keccak256(abi.encodePacked(blockStatus)), @@ -408,32 +362,52 @@ library MetaTxHelpers { ) ) ), - signature.signer, signature ); } function validateCollectSignature( - DataTypes.EIP712Signature calldata sig, + DataTypes.EIP712Signature calldata signature, DataTypes.CollectParams calldata collectParams ) internal { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( - COLLECT_TYPEHASH, + TypehashConstants.COLLECT, collectParams.publicationCollectedProfileId, collectParams.publicationCollectedId, collectParams.collectorProfileId, collectParams.referrerProfileId, collectParams.referrerPubId, keccak256(collectParams.collectModuleData), - _sigNonces(sig.signer), - sig.deadline + _sigNonces(signature.signer), + signature.deadline ) ) ), - sig + signature + ); + } + + function validatePermitSignature( + DataTypes.EIP712Signature calldata signature, + address spender, + uint256 tokenId + ) internal { + _validateRecoveredAddress( + _calculateDigest( + keccak256( + abi.encode( + TypehashConstants.PERMIT, + spender, + tokenId, + _sigNonces(signature.signer), + signature.deadline + ) + ) + ), + signature ); } @@ -444,50 +418,23 @@ library MetaTxHelpers { /** * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. */ - function _validateRecoveredAddress(bytes32 digest, DataTypes.EIP712Signature calldata sig) + function _validateRecoveredAddress(bytes32 digest, DataTypes.EIP712Signature calldata signature) internal view { - if (sig.deadline < block.timestamp) revert Errors.SignatureExpired(); + if (signature.deadline < block.timestamp) revert Errors.SignatureExpired(); // If the expected address is a contract, check the signature there. - if (sig.signer.code.length != 0) { - bytes memory concatenatedSig = abi.encodePacked(sig.r, sig.s, sig.v); + if (signature.signer.code.length != 0) { + bytes memory concatenatedSig = abi.encodePacked(signature.r, signature.s, signature.v); if ( - IEIP1271Implementer(sig.signer).isValidSignature(digest, concatenatedSig) != + IEIP1271Implementer(signature.signer).isValidSignature(digest, concatenatedSig) != EIP1271_MAGIC_VALUE ) { revert Errors.SignatureInvalid(); } } else { - address recoveredAddress = ecrecover(digest, sig.v, sig.r, sig.s); - if (recoveredAddress == address(0) || recoveredAddress != sig.signer) { - revert Errors.SignatureInvalid(); - } - } - } - - // TODO: Remove this duplicate when we refactor all functions to use signer inside the sig - /** - * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. - */ - function _validateRecoveredAddress( - bytes32 digest, - address signer, - DataTypes.EIP712Signature calldata sig - ) internal view { - if (sig.deadline < block.timestamp) revert Errors.SignatureExpired(); - // If the expected address is a contract, check the signature there. - if (signer.code.length != 0) { - bytes memory concatenatedSig = abi.encodePacked(sig.r, sig.s, sig.v); - if ( - IEIP1271Implementer(signer).isValidSignature(digest, concatenatedSig) != - EIP1271_MAGIC_VALUE - ) { - revert Errors.SignatureInvalid(); - } - } else { - address recoveredAddress = ecrecover(digest, sig.v, sig.r, sig.s); - if (recoveredAddress == address(0) || recoveredAddress != signer) { + address recoveredAddress = ecrecover(digest, signature.v, signature.r, signature.s); + if (recoveredAddress == address(0) || recoveredAddress != signature.signer) { revert Errors.SignatureInvalid(); } } @@ -497,15 +444,13 @@ library MetaTxHelpers { * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. */ function _calculateDomainSeparator() private view returns (bytes32) { - if (block.chainid == POLYGON_CHAIN_ID) { - // Note that this only works on the canonical Polygon mainnet deployment, and should the - // name change, a contract upgrade would be necessary. - return POLYGON_DOMAIN_SEPARATOR; + if (address(this) == LENS_HUB_ADDRESS) { + return LENS_HUB_CACHED_POLYGON_DOMAIN_SEPARATOR; } return keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256(_nameBytes()), EIP712_REVISION_HASH, block.chainid, diff --git a/contracts/misc/LensPeriphery.sol b/contracts/misc/LensPeriphery.sol deleted file mode 100644 index c0ec852..0000000 --- a/contracts/misc/LensPeriphery.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.15; - -import {IERC721Time} from '../interfaces/IERC721Time.sol'; -import {ILensHub} from '../interfaces/ILensHub.sol'; -import {DataTypes} from '../libraries/DataTypes.sol'; -import {Events} from '../libraries/Events.sol'; -import {Errors} from '../libraries/Errors.sol'; - -/** - * @notice This is a peripheral contract that acts as a source of truth for profile metadata and allows - * for users to emit an event demonstrating whether or not they explicitly want a follow to be shown. - * - * @dev This is useful because it allows clients to filter out follow NFTs that were transferred to - * a recipient by another user (i.e. Not a mint) and not register them as "following" unless - * the recipient explicitly toggles the follow here. - */ -contract LensPeriphery { - string public constant NAME = 'LensPeriphery'; - bytes32 internal constant EIP712_REVISION_HASH = keccak256('1'); - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = - keccak256( - 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' - ); - bytes32 internal constant TOGGLE_FOLLOW_TYPEHASH = - keccak256( - 'ToggleFollowWithSig(uint256[] profileIds,bool[] enables,uint256 nonce,uint256 deadline)' - ); - - ILensHub public immutable HUB; - - mapping(address => uint256) public sigNonces; - - mapping(uint256 => string) internal _metadataByProfile; - - constructor(ILensHub hub) { - HUB = hub; - } - - /** - * @notice Toggle Follows on the given profiles, emiting toggle event for each FollowNFT. - * - * NOTE: `profileIds`, `followNFTIds` and `enables` arrays must be of the same length. - * - * @param profileIds The token ID array of the profiles. - * @param enables The array of booleans to enable/disable follows. - */ - function toggleFollow(uint256[] calldata profileIds, bool[] calldata enables) external { - _toggleFollow(msg.sender, profileIds, enables); - } - - /** - * @notice Toggle Follows a given profiles via signature with the specified parameters. - * - * @param vars A ToggleFollowWithSigData struct containing the regular parameters as well as the signing follower's address - * and an EIP712Signature struct. - */ - function toggleFollowWithSig(DataTypes.ToggleFollowWithSigData calldata vars) external { - unchecked { - _validateRecoveredAddress( - _calculateDigest( - keccak256( - abi.encode( - TOGGLE_FOLLOW_TYPEHASH, - keccak256(abi.encodePacked(vars.profileIds)), - keccak256(abi.encodePacked(vars.enables)), - sigNonces[vars.follower]++, - vars.sig.deadline - ) - ) - ), - vars.follower, - vars.sig - ); - } - - _toggleFollow(vars.follower, vars.profileIds, vars.enables); - } - - function _toggleFollow( - address follower, - uint256[] calldata profileIds, - bool[] calldata enables - ) internal { - if (profileIds.length != enables.length) revert Errors.ArrayMismatch(); - uint256 profileIdsLength = profileIds.length; - for (uint256 i = 0; i < profileIdsLength; ) { - address followNFT = HUB.getFollowNFT(profileIds[i]); - if (followNFT == address(0)) revert Errors.FollowInvalid(); - if (!IERC721Time(address(HUB)).exists(profileIds[i])) revert Errors.TokenDoesNotExist(); - if (IERC721Time(followNFT).balanceOf(follower) == 0) revert Errors.FollowInvalid(); - unchecked { - ++i; - } - } - emit Events.FollowsToggled(follower, profileIds, enables, block.timestamp); - } - - /** - * @dev Wrapper for ecrecover to reduce code size, used in meta-tx specific functions. - * - * @notice In order to use the MetaTXHelpers here, we will need to re-deploy. - */ - function _validateRecoveredAddress( - bytes32 digest, - address expectedAddress, - DataTypes.EIP712Signature memory sig - ) internal view { - if (sig.deadline < block.timestamp) revert Errors.SignatureExpired(); - address recoveredAddress = ecrecover(digest, sig.v, sig.r, sig.s); - if (recoveredAddress == address(0) || recoveredAddress != expectedAddress) - revert Errors.SignatureInvalid(); - } - - /** - * @dev Calculates EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID. - */ - function _calculateDomainSeparator() internal view returns (bytes32) { - return - keccak256( - abi.encode( - EIP712_DOMAIN_TYPEHASH, - keccak256(bytes(NAME)), - EIP712_REVISION_HASH, - block.chainid, - address(this) - ) - ); - } - - /** - * @dev Calculates EIP712 digest based on the current DOMAIN_SEPARATOR. - * - * @param hashedMessage The message hash from which the digest should be calculated. - * - * @return bytes32 A 32-byte output representing the EIP712 digest. - */ - function _calculateDigest(bytes32 hashedMessage) internal view returns (bytes32) { - bytes32 digest; - unchecked { - digest = keccak256( - abi.encodePacked('\x19\x01', _calculateDomainSeparator(), hashedMessage) - ); - } - return digest; - } -} diff --git a/test/foundry/ChangeDelegatedExecutorsConfigTest.t.sol b/test/foundry/ChangeDelegatedExecutorsConfigTest.t.sol index 91a3f06..b15838d 100644 --- a/test/foundry/ChangeDelegatedExecutorsConfigTest.t.sol +++ b/test/foundry/ChangeDelegatedExecutorsConfigTest.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; import './MetaTxNegatives.t.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; contract ChangeDelegatedExecutorsConfigTest_CurrentConfig is BaseTest { uint256 constant testDelegatorProfileOwnerPk = 0xDE1E6A708; @@ -523,7 +524,7 @@ contract ChangeDelegatedExecutorsConfigTest_MetaTx is _calculateDigest( keccak256( abi.encode( - CHANGE_DELEGATED_EXECUTORS_CONFIG_TYPEHASH, + TypehashConstants.CHANGE_DELEGATED_EXECUTORS_CONFIG, delegatorProfileId, abi.encodePacked(executors), abi.encodePacked(approvals), diff --git a/test/foundry/FollowTest.t.sol b/test/foundry/FollowTest.t.sol index bd0f623..4b7fe94 100644 --- a/test/foundry/FollowTest.t.sol +++ b/test/foundry/FollowTest.t.sol @@ -5,7 +5,8 @@ import './base/BaseTest.t.sol'; import './MetaTxNegatives.t.sol'; import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; import {IFollowNFT} from 'contracts/interfaces/IFollowNFT.sol'; -import '../../contracts/mocks/MockFollowModuleWithRevertFlag.sol'; +import 'contracts/mocks/MockFollowModuleWithRevertFlag.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; contract FollowTest is BaseTest { using Strings for uint256; @@ -525,7 +526,7 @@ contract FollowMetaTxTest is FollowTest, MetaTxNegatives { _calculateDigest( keccak256( abi.encode( - FOLLOW_TYPEHASH, + TypehashConstants.FOLLOW, followerProfileId, keccak256(abi.encodePacked(idsOfProfilesToFollow)), keccak256(abi.encodePacked(followTokenIds)), diff --git a/test/foundry/MetaTxNegatives.t.sol b/test/foundry/MetaTxNegatives.t.sol index 0184f05..308217d 100644 --- a/test/foundry/MetaTxNegatives.t.sol +++ b/test/foundry/MetaTxNegatives.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; abstract contract MetaTxNegatives is BaseTest { uint256 private constant NO_DEADLINE = type(uint256).max; @@ -83,7 +84,7 @@ abstract contract MetaTxNegatives is BaseTest { { domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256(_getDomainName()), keccak256('69696969696969696969696969969696'), block.chainid, @@ -101,7 +102,7 @@ abstract contract MetaTxNegatives is BaseTest { function testCannotExecuteMetaTxWhenSignatureDomainWasGeneratedWithWrongChainId() public { domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256(_getDomainName()), keccak256(_getRevisionNumber()), type(uint256).max, @@ -121,7 +122,7 @@ abstract contract MetaTxNegatives is BaseTest { { domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256(_getDomainName()), keccak256(_getRevisionNumber()), block.chainid, @@ -139,7 +140,7 @@ abstract contract MetaTxNegatives is BaseTest { function testCannotExecuteMetaTxWhenSignatureDomainWasGeneratedWithWrongName() public { domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256('This should be an invalid name :)'), keccak256(_getRevisionNumber()), block.chainid, @@ -158,7 +159,7 @@ abstract contract MetaTxNegatives is BaseTest { return keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256(_getDomainName()), keccak256(_getRevisionNumber()), block.chainid, diff --git a/test/foundry/MultiStateHubTest.t.sol b/test/foundry/MultiStateHubTest.t.sol index b0b6a89..e16d891 100644 --- a/test/foundry/MultiStateHubTest.t.sol +++ b/test/foundry/MultiStateHubTest.t.sol @@ -332,7 +332,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ profileId: newProfileId, followModule: address(0), followModuleInitData: '', - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -370,7 +370,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ _setProfileImageURIWithSig({ profileId: newProfileId, imageURI: MOCK_URI, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -380,7 +380,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ _setFollowNFTURIWithSig({ profileId: newProfileId, followNFTURI: MOCK_URI, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -418,7 +418,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ _burnWithSig({ profileId: newProfileId, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -437,7 +437,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ idOfProfileToFollow: newProfileId, followTokenId: 0, data: '', - sig: _getSigStruct(otherSigner, otherSignerKey, digest, deadline) + signature: _getSigStruct(otherSigner, otherSignerKey, digest, deadline) }); } @@ -450,7 +450,7 @@ contract MultiStateHubTest_PausedState_WithSig is MultiStateHubTest_PausedState_ ); } - // Methods that cannot be called with sig + // Methods that cannot be called with signature function testCannotTransferProfileWhilePaused() public override {} function testCannotCreateProfileWhilePaused() public override {} @@ -627,7 +627,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is profileId: newProfileId, followModule: address(0), followModuleInitData: '', - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -665,7 +665,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is _setProfileImageURIWithSig({ profileId: newProfileId, imageURI: MOCK_URI, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -675,7 +675,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is _setFollowNFTURIWithSig({ profileId: newProfileId, followNFTURI: MOCK_URI, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -713,7 +713,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is _burnWithSig({ profileId: newProfileId, - sig: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) + signature: _getSigStruct(profileOwner, profileOwnerKey, digest, deadline) }); } @@ -733,7 +733,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is idOfProfileToFollow: newProfileId, followTokenId: 0, data: '', - sig: _getSigStruct(otherSigner, otherSignerKey, digest, deadline) + signature: _getSigStruct(otherSigner, otherSignerKey, digest, deadline) }); } @@ -746,7 +746,7 @@ contract MultiStateHubTest_PublishingPausedState_WithSig is ); } - // Methods that cannot be called with sig + // Methods that cannot be called with signature function testCanTransferProfileWhilePublishingPaused() public override {} function testCanCreateProfileWhilePublishingPaused() public override {} diff --git a/test/foundry/SetBlockStatusTest.t.sol b/test/foundry/SetBlockStatusTest.t.sol index ed1494f..0f8fd2c 100644 --- a/test/foundry/SetBlockStatusTest.t.sol +++ b/test/foundry/SetBlockStatusTest.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.13; import './base/BaseTest.t.sol'; import './MetaTxNegatives.t.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; contract SetBlockStatusTest is BaseTest { address constant PROFILE_OWNER = address(0); @@ -336,7 +337,7 @@ contract SetBlockStatusMetaTxTest is SetBlockStatusTest, MetaTxNegatives { _calculateDigest( keccak256( abi.encode( - SET_BLOCK_STATUS_TYPEHASH, + TypehashConstants.SET_BLOCK_STATUS, byProfileId, keccak256(abi.encodePacked(idsOfProfilesToSetBlockStatus)), keccak256(abi.encodePacked(blockStatus)), @@ -362,7 +363,7 @@ contract SetBlockStatusMetaTxTest is SetBlockStatusTest, MetaTxNegatives { byProfileId: byProfileId, idsOfProfilesToSetBlockStatus: idsOfProfilesToSetBlockStatus, blockStatus: blockStatus, - sig: _getSigStruct({ + signature: _getSigStruct({ pKey: signerPk, digest: _calculateSetBlockStatusWithSigDigest( byProfileId, diff --git a/test/foundry/UnfollowTest.t.sol b/test/foundry/UnfollowTest.t.sol index fc5fe1d..08b1f93 100644 --- a/test/foundry/UnfollowTest.t.sol +++ b/test/foundry/UnfollowTest.t.sol @@ -5,6 +5,7 @@ import './base/BaseTest.t.sol'; import './MetaTxNegatives.t.sol'; import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; import {IFollowNFT} from 'contracts/interfaces/IFollowNFT.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; contract UnfollowTest is BaseTest { uint256 constant MINT_NEW_TOKEN = 0; @@ -276,7 +277,7 @@ contract UnfollowMetaTxTest is UnfollowTest, MetaTxNegatives { _calculateDigest( keccak256( abi.encode( - UNFOLLOW_TYPEHASH, + TypehashConstants.UNFOLLOW, unfollowerProfileId, keccak256(abi.encodePacked(idsOfProfilesToUnfollow)), nonce, diff --git a/test/foundry/base/BaseTest.t.sol b/test/foundry/base/BaseTest.t.sol index fb8d000..f90dc52 100644 --- a/test/foundry/base/BaseTest.t.sol +++ b/test/foundry/base/BaseTest.t.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.13; import './TestSetup.t.sol'; -import '../../../contracts/libraries/DataTypes.sol'; +import 'contracts/libraries/DataTypes.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; contract BaseTest is TestSetup { function _getSetProfileMetadataURITypedDataHash( @@ -13,7 +14,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - SET_PROFILE_METADATA_URI_TYPEHASH, + TypehashConstants.SET_PROFILE_METADATA_URI, profileId, keccak256(bytes(metadataURI)), nonce, @@ -32,7 +33,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - SET_FOLLOW_MODULE_TYPEHASH, + TypehashConstants.SET_FOLLOW_MODULE, profileId, followModule, keccak256(followModuleInitData), @@ -54,7 +55,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - CHANGE_DELEGATED_EXECUTORS_CONFIG_TYPEHASH, + TypehashConstants.CHANGE_DELEGATED_EXECUTORS_CONFIG, delegatorProfileId, abi.encodePacked(executors), abi.encodePacked(approvals), @@ -75,7 +76,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - SET_PROFILE_IMAGE_URI_TYPEHASH, + TypehashConstants.SET_PROFILE_IMAGE_URI, profileId, keccak256(bytes(imageURI)), nonce, @@ -93,7 +94,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - SET_FOLLOW_NFT_URI_TYPEHASH, + TypehashConstants.SET_FOLLOW_NFT_URI, profileId, keccak256(bytes(followNFTURI)), nonce, @@ -108,7 +109,9 @@ contract BaseTest is TestSetup { uint256 nonce, uint256 deadline ) internal view returns (bytes32) { - bytes32 structHash = keccak256(abi.encode(BURN_TYPEHASH, profileId, nonce, deadline)); + bytes32 structHash = keccak256( + abi.encode(TypehashConstants.BURN, profileId, nonce, deadline) + ); return _calculateDigest(structHash); } @@ -124,7 +127,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - POST_TYPEHASH, + TypehashConstants.POST, profileId, keccak256(bytes(contentURI)), collectModule, @@ -173,7 +176,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - COMMENT_TYPEHASH, + TypehashConstants.COMMENT, profileId, keccak256(bytes(contentURI)), pointedProfileId, @@ -227,7 +230,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - MIRROR_TYPEHASH, + TypehashConstants.MIRROR, profileId, pointedProfileId, pointedPubId, @@ -278,7 +281,7 @@ contract BaseTest is TestSetup { bytes32 structHash = keccak256( abi.encode( - FOLLOW_TYPEHASH, + TypehashConstants.FOLLOW, followerProfileId, keccak256(abi.encodePacked(idsOfProfilesToFollow)), keccak256(abi.encodePacked(followTokenIds)), @@ -297,7 +300,7 @@ contract BaseTest is TestSetup { ) internal view returns (bytes32) { bytes32 structHash = keccak256( abi.encode( - COLLECT_TYPEHASH, + TypehashConstants.COLLECT, collectParams.publicationCollectedProfileId, collectParams.publicationCollectedId, collectParams.collectorProfileId, @@ -398,7 +401,7 @@ contract BaseTest is TestSetup { address[] memory executors, bool[] memory approvals, bool switchToGivenConfig, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal pure returns (DataTypes.ChangeDelegatedExecutorsConfigWithSigData memory) { return DataTypes.ChangeDelegatedExecutorsConfigWithSigData( @@ -407,7 +410,7 @@ contract BaseTest is TestSetup { approvals, configNumber, switchToGivenConfig, - sig + signature ); } @@ -444,30 +447,30 @@ contract BaseTest is TestSetup { function _postWithSig( DataTypes.PostParams memory postParams, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal returns (uint256) { - return hub.postWithSig(postParams, sig); + return hub.postWithSig(postParams, signature); } function _commentWithSig( DataTypes.CommentParams memory commentParams, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal returns (uint256) { - return hub.commentWithSig(commentParams, sig); + return hub.commentWithSig(commentParams, signature); } function _mirrorWithSig( DataTypes.MirrorParams memory mirrorParams, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal returns (uint256) { - return hub.mirrorWithSig(mirrorParams, sig); + return hub.mirrorWithSig(mirrorParams, signature); } function _collectWithSig( DataTypes.CollectParams memory collectParams, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal returns (uint256) { - return hub.collectWithSig(collectParams, sig); + return hub.collectWithSig(collectParams, signature); } function _follow( @@ -492,7 +495,7 @@ contract BaseTest is TestSetup { uint256 idOfProfileToFollow, uint256 followTokenId, bytes memory data, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal returns (uint256[] memory) { return hub.followWithSig( @@ -500,7 +503,7 @@ contract BaseTest is TestSetup { _toUint256Array(idOfProfileToFollow), _toUint256Array(followTokenId), _toBytesArray(data), - sig + signature ); } @@ -566,9 +569,9 @@ contract BaseTest is TestSetup { uint256 profileId, address followModule, bytes memory followModuleInitData, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal { - hub.setFollowModuleWithSig(profileId, followModule, followModuleInitData, sig); + hub.setFollowModuleWithSig(profileId, followModule, followModuleInitData, signature); } function _setProfileImageURI( @@ -583,9 +586,9 @@ contract BaseTest is TestSetup { function _setProfileImageURIWithSig( uint256 profileId, string memory imageURI, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal { - hub.setProfileImageURIWithSig(profileId, imageURI, sig); + hub.setProfileImageURIWithSig(profileId, imageURI, signature); } function _setFollowNFTURI( @@ -600,9 +603,9 @@ contract BaseTest is TestSetup { function _setFollowNFTURIWithSig( uint256 profileId, string memory followNFTURI, - DataTypes.EIP712Signature memory sig + DataTypes.EIP712Signature memory signature ) internal { - hub.setFollowNFTURIWithSig(profileId, followNFTURI, sig); + hub.setFollowNFTURIWithSig(profileId, followNFTURI, signature); } function _burn(address msgSender, uint256 profileId) internal { @@ -610,8 +613,8 @@ contract BaseTest is TestSetup { hub.burn(profileId); } - function _burnWithSig(uint256 profileId, DataTypes.EIP712Signature memory sig) internal { - hub.burnWithSig(profileId, sig); + function _burnWithSig(uint256 profileId, DataTypes.EIP712Signature memory signature) internal { + hub.burnWithSig(profileId, signature); } function _getPub(uint256 profileId, uint256 pubId) diff --git a/test/foundry/base/TestSetup.t.sol b/test/foundry/base/TestSetup.t.sol index f5dd289..0304f3a 100644 --- a/test/foundry/base/TestSetup.t.sol +++ b/test/foundry/base/TestSetup.t.sol @@ -20,6 +20,8 @@ import {MockCollectModule} from 'contracts/mocks/MockCollectModule.sol'; import {MockReferenceModule} from 'contracts/mocks/MockReferenceModule.sol'; import '../helpers/ForkManagement.sol'; import '../Constants.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; +import {MetaTxHelpers} from 'contracts/libraries/helpers/MetaTxHelpers.sol'; contract TestSetup is Test, ForkManagement { using stdJson for string; @@ -215,9 +217,9 @@ contract TestSetup is Test, ForkManagement { // Compute the domain separator. domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256('Lens Protocol Profiles'), - EIP712_REVISION_HASH, + MetaTxHelpers.EIP712_REVISION_HASH, block.chainid, hubProxyAddr ) diff --git a/test/foundry/fork/UpgradeForkTest.t.sol b/test/foundry/fork/UpgradeForkTest.t.sol index 3ec7474..95ca844 100644 --- a/test/foundry/fork/UpgradeForkTest.t.sol +++ b/test/foundry/fork/UpgradeForkTest.t.sol @@ -6,14 +6,15 @@ import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol'; import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import 'forge-std/console2.sol'; import '../base/BaseTest.t.sol'; -import '../../../contracts/mocks/MockReferenceModule.sol'; -import '../../../contracts/mocks/MockDeprecatedReferenceModule.sol'; -import '../../../contracts/mocks/MockCollectModule.sol'; -import '../../../contracts/mocks/MockDeprecatedCollectModule.sol'; -import '../../../contracts/mocks/MockFollowModule.sol'; -import '../../../contracts/mocks/MockDeprecatedFollowModule.sol'; -import '../../../contracts/interfaces/IERC721Time.sol'; -import '../../../contracts/interfaces/ILensMultiState.sol'; +import 'contracts/mocks/MockReferenceModule.sol'; +import 'contracts/mocks/MockDeprecatedReferenceModule.sol'; +import 'contracts/mocks/MockCollectModule.sol'; +import 'contracts/mocks/MockDeprecatedCollectModule.sol'; +import 'contracts/mocks/MockFollowModule.sol'; +import 'contracts/mocks/MockDeprecatedFollowModule.sol'; +import 'contracts/interfaces/IERC721Time.sol'; +import 'contracts/interfaces/ILensMultiState.sol'; +import {TypehashConstants} from 'contracts/libraries/constants/TypehashConstants.sol'; struct OldCreateProfileData { address to; @@ -405,9 +406,9 @@ contract UpgradeForkTest is BaseTest { // Compute the domain separator. domainSeparator = keccak256( abi.encode( - EIP712_DOMAIN_TYPEHASH, + TypehashConstants.EIP712_DOMAIN, keccak256('Lens Protocol Profiles'), - EIP712_REVISION_HASH, + MetaTxHelpers.EIP712_REVISION_HASH, block.chainid, hubProxyAddr )