From bf83bf21606e64c6d42aa8718df560a8191a4d8b Mon Sep 17 00:00:00 2001 From: Peter Michael Date: Fri, 3 Jun 2022 18:14:52 -0400 Subject: [PATCH] refactor: Consolidated libraries into GeneralLib, WIP. --- contracts/core/FollowNFT.sol | 6 +- contracts/core/LensHub.sol | 83 ++--- contracts/core/storage/LensHubStorage.sol | 2 +- contracts/libraries/Constants.sol | 78 +++- contracts/libraries/GeneralLib.sol | 346 ++++++++++++++++-- contracts/libraries/Helpers.sol | 25 ++ ...actionLogic.sol => InteractionHelpers.sol} | 40 +- .../{MetaTxLib.sol => MetaTxHelpers.sol} | 276 +++----------- contracts/mocks/MockLensHubV2.sol | 7 - contracts/mocks/MockLensHubV2BadRevision.sol | 7 - package.json | 2 +- tasks/full-deploy-verify.ts | 15 - tasks/full-deploy.ts | 11 - tasks/list-storage.ts | 10 - tasks/testnet-full-deploy-verify.ts | 15 - test/__setup.spec.ts | 6 - 16 files changed, 488 insertions(+), 441 deletions(-) rename contracts/libraries/{InteractionLogic.sol => InteractionHelpers.sol} (78%) rename contracts/libraries/{MetaTxLib.sol => MetaTxHelpers.sol} (58%) diff --git a/contracts/core/FollowNFT.sol b/contracts/core/FollowNFT.sol index e9d1d1a..623281e 100644 --- a/contracts/core/FollowNFT.sol +++ b/contracts/core/FollowNFT.sol @@ -8,8 +8,8 @@ import {ILensHub} from '../interfaces/ILensHub.sol'; import {Errors} from '../libraries/Errors.sol'; import {Events} from '../libraries/Events.sol'; import {DataTypes} from '../libraries/DataTypes.sol'; -import {Constants} from '../libraries/Constants.sol'; import {LensNFTBase} from './base/LensNFTBase.sol'; +import '../libraries/Constants.sol'; /** * @title FollowNFT @@ -127,13 +127,13 @@ contract FollowNFT is LensNFTBase, IFollowNFT { function name() public view override returns (string memory) { string memory handle = ILensHub(HUB).getHandle(_profileId); - return string(abi.encodePacked(handle, Constants.FOLLOW_NFT_NAME_SUFFIX)); + return string(abi.encodePacked(handle, FOLLOW_NFT_NAME_SUFFIX)); } function symbol() public view override returns (string memory) { string memory handle = ILensHub(HUB).getHandle(_profileId); bytes4 firstBytes = bytes4(bytes(handle)); - return string(abi.encodePacked(firstBytes, Constants.FOLLOW_NFT_SYMBOL_SUFFIX)); + return string(abi.encodePacked(firstBytes, FOLLOW_NFT_SYMBOL_SUFFIX)); } function _getSnapshotValueByBlockNumber( diff --git a/contracts/core/LensHub.sol b/contracts/core/LensHub.sol index b040c89..603b24a 100644 --- a/contracts/core/LensHub.sol +++ b/contracts/core/LensHub.sol @@ -7,20 +7,18 @@ import {ILensHub} from '../interfaces/ILensHub.sol'; import {Events} from '../libraries/Events.sol'; import {Helpers} from '../libraries/Helpers.sol'; -import {Constants} from '../libraries/Constants.sol'; import {DataTypes} from '../libraries/DataTypes.sol'; import {Errors} from '../libraries/Errors.sol'; import {GeneralLib} from '../libraries/GeneralLib.sol'; import {ProfileTokenURILogic} from '../libraries/ProfileTokenURILogic.sol'; -import {InteractionLogic} from '../libraries/InteractionLogic.sol'; -import {MetaTxLib} from '../libraries/MetaTxLib.sol'; - import {LensHubNFTBase} from './base/LensHubNFTBase.sol'; import {LensMultiState} from './base/LensMultiState.sol'; import {LensHubStorage} from './storage/LensHubStorage.sol'; import {VersionedInitializable} from '../upgradeability/VersionedInitializable.sol'; import {IERC721Enumerable} from '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol'; +import '../libraries/Constants.sol'; + /** * @title LensHub * @author Lens Protocol @@ -142,7 +140,7 @@ contract LensHub is uint256 tokenId, DataTypes.EIP712Signature calldata sig ) external override { - MetaTxLib.basePermit(spender, tokenId, sig); + GeneralLib.permit(spender, tokenId, sig); _approve(spender, tokenId); } @@ -153,7 +151,7 @@ contract LensHub is bool approved, DataTypes.EIP712Signature calldata sig ) external override { - MetaTxLib.basePermitForAll(owner, operator, approved, sig); + GeneralLib.permitForAll(owner, operator, approved, sig); _setOperatorApproval(owner, operator, approved); } @@ -174,7 +172,8 @@ contract LensHub is /// @inheritdoc ILensHub function setDefaultProfile(uint256 profileId) external override whenNotPaused { - _setDefaultProfile(msg.sender, profileId); + // _setDefaultProfile(msg.sender, profileId); + GeneralLib.setDefaultProfile(msg.sender, profileId); } /// @inheritdoc ILensHub @@ -183,8 +182,9 @@ contract LensHub is override whenNotPaused { - MetaTxLib.baseSetDefaultProfileWithSig(vars); - _setDefaultProfile(vars.wallet, vars.profileId); + GeneralLib.setDefaultProfileWithSig(vars); + // GeneralLib.baseSetDefaultProfileWithSig(vars); + // _setDefaultProfile(vars.wallet, vars.profileId); } /// @inheritdoc ILensHub @@ -208,7 +208,7 @@ contract LensHub is override whenNotPaused { - MetaTxLib.baseSetFollowModuleWithSig(vars); + GeneralLib.setFollowModuleWithSig(vars); GeneralLib.setFollowModule( vars.profileId, vars.followModule, @@ -229,7 +229,7 @@ contract LensHub is override whenNotPaused { - MetaTxLib.baseSetDispatcherWithSig(vars); + GeneralLib.setDispatcherWithSig(vars); _setDispatcher(vars.profileId, vars.dispatcher); } @@ -249,7 +249,7 @@ contract LensHub is override whenNotPaused { - MetaTxLib.baseSetProfileImageURIWithSig(vars); + GeneralLib.setProfileImageURIWithSig(vars); _setProfileImageURI(vars.profileId, vars.imageURI); } @@ -269,7 +269,7 @@ contract LensHub is override whenNotPaused { - MetaTxLib.baseSetFollowNFTURIWithSig(vars); + GeneralLib.setFollowNFTURIWithSig(vars); _setFollowNFTURI(vars.profileId, vars.followNFTURI); } @@ -299,7 +299,7 @@ contract LensHub is whenPublishingEnabled returns (uint256) { - MetaTxLib.basePostWithSig(vars); + GeneralLib.postWithSig(vars); return _createPost( vars.profileId, @@ -329,7 +329,7 @@ contract LensHub is whenPublishingEnabled returns (uint256) { - MetaTxLib.baseCommentWithSig(vars); + GeneralLib.commentWithSig(vars); return _createComment( DataTypes.CommentData( @@ -364,7 +364,7 @@ contract LensHub is whenPublishingEnabled returns (uint256) { - MetaTxLib.baseMirrorWithSig(vars); + GeneralLib.mirrorWithSig(vars); return _createMirror( DataTypes.MirrorData( @@ -396,7 +396,7 @@ contract LensHub is external whenNotPaused { - MetaTxLib.baseBurnWithSig(tokenId, sig); + GeneralLib.burnWithSig(tokenId, sig); _burn(tokenId); _clearHandleHash(tokenId); } @@ -413,13 +413,7 @@ contract LensHub is returns (uint256[] memory) { return - InteractionLogic.follow( - msg.sender, - profileIds, - datas, - _profileById, - _profileIdByHandleHash - ); + GeneralLib.follow(msg.sender, profileIds, datas, _profileById, _profileIdByHandleHash); } /// @inheritdoc ILensHub @@ -429,15 +423,7 @@ contract LensHub is whenNotPaused returns (uint256[] memory) { - MetaTxLib.baseFollowWithSig(vars); - return - InteractionLogic.follow( - vars.follower, - vars.profileIds, - vars.datas, - _profileById, - _profileIdByHandleHash - ); + return GeneralLib.followWithSig(vars, _profileById, _profileIdByHandleHash); } /// @inheritdoc ILensHub @@ -447,7 +433,7 @@ contract LensHub is bytes calldata data ) external override whenNotPaused returns (uint256) { return - InteractionLogic.collect( + GeneralLib.collect( msg.sender, profileId, pubId, @@ -465,17 +451,7 @@ contract LensHub is whenNotPaused returns (uint256) { - MetaTxLib.baseCollectWithSig(vars); - return - InteractionLogic.collect( - vars.collector, - vars.profileId, - vars.pubId, - vars.data, - COLLECT_NFT_IMPL, - _pubByIdByProfile, - _profileById - ); + return GeneralLib.collectWithSig(vars, COLLECT_NFT_IMPL, _pubByIdByProfile, _profileById); } /// @inheritdoc ILensHub @@ -701,7 +677,7 @@ contract LensHub is } function getDomainSeparator() external view returns (bytes32) { - return MetaTxLib.getDomainSeparator(); + return GeneralLib.getDomainSeparator(); } /** @@ -751,19 +727,6 @@ contract LensHub is } } - /* - * If the profile ID is zero, this is the equivalent of "unsetting" a default profile. - * Note that the wallet address should either be the message sender or validated via a signature - * prior to this function call. - */ - function _setDefaultProfile(address wallet, uint256 profileId) internal { - if (profileId > 0 && wallet != ownerOf(profileId)) revert Errors.NotProfileOwner(); - - _defaultProfileByAddress[wallet] = profileId; - - emit Events.DefaultProfileSet(wallet, profileId, block.timestamp); - } - function _createComment(DataTypes.CommentData memory vars) internal returns (uint256) { unchecked { uint256 pubId = ++_profileById[vars.profileId].pubCount; @@ -786,7 +749,7 @@ contract LensHub is } function _setProfileImageURI(uint256 profileId, string calldata imageURI) internal { - if (bytes(imageURI).length > Constants.MAX_PROFILE_IMAGE_URI_LENGTH) + if (bytes(imageURI).length > MAX_PROFILE_IMAGE_URI_LENGTH) revert Errors.ProfileImageURILengthInvalid(); _profileById[profileId].imageURI = imageURI; emit Events.ProfileImageURISet(profileId, imageURI, block.timestamp); diff --git a/contracts/core/storage/LensHubStorage.sol b/contracts/core/storage/LensHubStorage.sol index 8b560e4..c31b5e6 100644 --- a/contracts/core/storage/LensHubStorage.sol +++ b/contracts/core/storage/LensHubStorage.sol @@ -23,7 +23,7 @@ abstract contract LensHubStorage { mapping(uint256 => DataTypes.ProfileStruct) internal _profileById; mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct)) internal _pubByIdByProfile; - mapping(address => uint256) internal _defaultProfileByAddress; + mapping(address => uint256) internal _defaultProfileByAddress; // slot 21 uint256 internal _profileCounter; address internal _governance; // slot 23 diff --git a/contracts/libraries/Constants.sol b/contracts/libraries/Constants.sol index 7fb7906..f7da873 100644 --- a/contracts/libraries/Constants.sol +++ b/contracts/libraries/Constants.sol @@ -2,11 +2,73 @@ pragma solidity 0.8.10; -library Constants { - string internal constant FOLLOW_NFT_NAME_SUFFIX = '-Follower'; - string internal constant FOLLOW_NFT_SYMBOL_SUFFIX = '-Fl'; - string internal constant COLLECT_NFT_NAME_INFIX = '-Collect-'; - string internal constant COLLECT_NFT_SYMBOL_INFIX = '-Cl-'; - uint8 internal constant MAX_HANDLE_LENGTH = 31; - uint16 internal constant MAX_PROFILE_IMAGE_URI_LENGTH = 6000; -} +// library Constants { +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-'; +uint8 constant MAX_HANDLE_LENGTH = 31; +uint16 constant MAX_PROFILE_IMAGE_URI_LENGTH = 6000; + +// We store constants equal to the storage slots here to later access via inline +// assembly without needing to pass storage pointers. The NAME_SLOT_GT_31 slot +// is equivalent to keccak256(NAME_SLOT) and is where the name string is stored +// if the length is greater than 31 bytes. +uint256 constant NAME_SLOT = 0; +uint256 constant SIG_NONCES_MAPPING_SLOT = 10; +uint256 constant PROTOCOL_STATE_SLOT = 12; +uint256 constant PROFILE_CREATOR_WHITELIST_MAPPING_SLOT = 13; +uint256 constant FOLLOW_MODULE_WHITELIST_MAPPING_SLOT = 14; +uint256 constant COLLECT_MODULE_WHITELIST_MAPPING_SLOT = 15; +uint256 constant REFERENCE_MODULE_WHITELIST_MAPPING_SLOT = 16; +uint256 constant DEFAULT_PROFILE_MAPPING_SLOT = 21; +uint256 constant GOVERNANCE_SLOT = 23; +uint256 constant EMERGENCY_ADMIN_SLOT = 24; +uint256 constant TOKEN_DATA_MAPPING_SLOT = 2; +uint256 constant NAME_SLOT_GT_31 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563; + +// 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_WITH_SIG_TYPEHASH = keccak256( + 'BurnWithSig(uint256 tokenId,uint256 nonce,uint256 deadline)' +); +bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256( + 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' +); +bytes32 constant SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH = keccak256( + 'SetDefaultProfileWithSig(address wallet,uint256 profileId,uint256 nonce,uint256 deadline)' +); +bytes32 constant SET_FOLLOW_MODULE_WITH_SIG_TYPEHASH = keccak256( + 'SetFollowModuleWithSig(uint256 profileId,address followModule,bytes followModuleInitData,uint256 nonce,uint256 deadline)' +); +bytes32 constant SET_FOLLOW_NFT_URI_WITH_SIG_TYPEHASH = keccak256( + 'SetFollowNFTURIWithSig(uint256 profileId,string followNFTURI,uint256 nonce,uint256 deadline)' +); +bytes32 constant SET_DISPATCHER_WITH_SIG_TYPEHASH = keccak256( + 'SetDispatcherWithSig(uint256 profileId,address dispatcher,uint256 nonce,uint256 deadline)' +); +bytes32 constant SET_PROFILE_IMAGE_URI_WITH_SIG_TYPEHASH = keccak256( + 'SetProfileImageURIWithSig(uint256 profileId,string imageURI,uint256 nonce,uint256 deadline)' +); +bytes32 constant POST_WITH_SIG_TYPEHASH = keccak256( + 'PostWithSig(uint256 profileId,string contentURI,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' +); +bytes32 constant COMMENT_WITH_SIG_TYPEHASH = keccak256( + 'CommentWithSig(uint256 profileId,string contentURI,uint256 profileIdPointed,uint256 pubIdPointed,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' +); +bytes32 constant MIRROR_WITH_SIG_TYPEHASH = keccak256( + 'MirrorWithSig(uint256 profileId,uint256 profileIdPointed,uint256 pubIdPointed,bytes referenceModuleData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' +); +bytes32 constant FOLLOW_WITH_SIG_TYPEHASH = keccak256( + 'FollowWithSig(uint256[] profileIds,bytes[] datas,uint256 nonce,uint256 deadline)' +); +bytes32 constant COLLECT_WITH_SIG_TYPEHASH = keccak256( + 'CollectWithSig(uint256 profileId,uint256 pubId,bytes data,uint256 nonce,uint256 deadline)' +); +// } diff --git a/contracts/libraries/GeneralLib.sol b/contracts/libraries/GeneralLib.sol index 1656ebd..d4e9c6f 100644 --- a/contracts/libraries/GeneralLib.sol +++ b/contracts/libraries/GeneralLib.sol @@ -4,13 +4,17 @@ pragma solidity 0.8.10; import {Helpers} from './Helpers.sol'; import {DataTypes} from './DataTypes.sol'; +import {Helpers} from './Helpers.sol'; import {Errors} from './Errors.sol'; import {Events} from './Events.sol'; -import {Constants} from './Constants.sol'; import {IFollowModule} from '../interfaces/IFollowModule.sol'; import {ICollectModule} from '../interfaces/ICollectModule.sol'; import {IReferenceModule} from '../interfaces/IReferenceModule.sol'; +import './Constants.sol'; +import {MetaTxHelpers} from './MetaTxHelpers.sol'; +import {InteractionHelpers} from './InteractionHelpers.sol'; + // TODO: Migrate governance/admin logic here. (incl events) // TODO: Migrate complex storage here. (incl events) @@ -18,22 +22,14 @@ import {IReferenceModule} from '../interfaces/IReferenceModule.sol'; * @title GeneralLib * @author Lens Protocol * - * @notice This is the library that contains the logic for profile creation, publication, + * @notice This is the library that contains the logic for profile creation, publication, * admin, and governance functionality. * - * @dev The functions are external, so they are called from the hub via `delegateCall` under + * @dev The functions are external, so they are called from the hub via `delegateCall` under * the hood. Furthermore, expected events are emitted from this library instead of from the * hub to alleviate code size concerns. */ library GeneralLib { - uint256 constant PROTOCOL_STATE_SLOT = 12; - uint256 constant PROFILE_CREATOR_WHITELIST_MAPPING_SLOT = 13; - uint256 constant FOLLOW_MODULE_WHITELIST_MAPPING_SLOT = 14; - uint256 constant COLLECT_MODULE_WHITELIST_MAPPING_SLOT = 15; - uint256 constant REFERENCE_MODULE_WHITELIST_MAPPING_SLOT = 16; - uint256 constant GOVERNANCE_SLOT = 23; - uint256 constant EMERGENCY_ADMIN_SLOT = 24; - /** * @notice Sets the governance address. * @@ -50,7 +46,7 @@ library GeneralLib { /** * @notice Sets the emergency admin address. - * + * * @param newEmergencyAdmin The new governance address to set. */ function setEmergencyAdmin(address newEmergencyAdmin) external { @@ -86,7 +82,7 @@ library GeneralLib { /** * @notice Sets the protocol state and validates the caller. The emergency admin can only * pause further (Unpaused => PublishingPaused => Paused). Whereas governance can set any - * state. + * state. * * @param newState The new protocol state to set. */ @@ -110,6 +106,10 @@ library GeneralLib { emit Events.StateSet(msg.sender, prevState, newState, block.timestamp); } + function setDefaultProfile(address wallet, uint256 profileId) external { + _setDefaultProfile(wallet, profileId); + } + /** * @notice Executes the logic to create a profile with the given parameters to the given address. * @@ -133,7 +133,7 @@ library GeneralLib { _validateProfileCreatorWhitelisted(); _validateHandle(vars.handle); - if (bytes(vars.imageURI).length > Constants.MAX_PROFILE_IMAGE_URI_LENGTH) + if (bytes(vars.imageURI).length > MAX_PROFILE_IMAGE_URI_LENGTH) revert Errors.ProfileImageURILengthInvalid(); bytes32 handleHash = keccak256(bytes(vars.handle)); @@ -369,6 +369,280 @@ library GeneralLib { ); } + /** + * @notice Follows the given profiles, executing the necessary logic and module calls before minting the follow + * NFT(s) to the follower. + * + * @param follower The address executing the follow. + * @param profileIds The array of profile token IDs to follow. + * @param followModuleDatas The array of follow module data parameters to pass to each profile's follow module. + * @param _profileById A pointer to the storage mapping of profile structs by profile ID. + * @param _profileIdByHandleHash A pointer to the storage mapping of profile IDs by handle hash. + * + * @return uint256[] An array of integers representing the minted follow NFTs token IDs. + */ + function follow( + address follower, + uint256[] calldata profileIds, + bytes[] calldata followModuleDatas, + mapping(uint256 => DataTypes.ProfileStruct) storage _profileById, + mapping(bytes32 => uint256) storage _profileIdByHandleHash + ) external returns (uint256[] memory) { + return + InteractionHelpers.follow( + follower, + profileIds, + followModuleDatas, + _profileById, + _profileIdByHandleHash + ); + } + + /** + * @notice Collects the given publication, executing the necessary logic and module call before minting the + * collect NFT to the collector. + * + * @param collector The address executing the collect. + * @param profileId The token ID of the publication being collected's parent profile. + * @param pubId The publication ID of the publication being collected. + * @param collectModuleData The data to pass to the publication's collect module. + * @param collectNFTImpl The address of the collect NFT implementation, which has to be passed because it's an immutable in the hub. + * @param _pubByIdByProfile A pointer to the storage mapping of publications by pubId by profile ID. + * @param _profileById A pointer to the storage mapping of profile structs by profile ID. + * + * @return uint256 An integer representing the minted token ID. + */ + function collect( + address collector, + uint256 profileId, + uint256 pubId, + bytes calldata collectModuleData, + address collectNFTImpl, + mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct)) + storage _pubByIdByProfile, + mapping(uint256 => DataTypes.ProfileStruct) storage _profileById + ) external returns (uint256) { + return + InteractionHelpers.collect( + collector, + profileId, + pubId, + collectModuleData, + collectNFTImpl, + _pubByIdByProfile, + _profileById + ); + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the `permit()` + * function. + * + * @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 { + MetaTxHelpers.basePermit(spender, tokenId, sig); + //approve + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the `permitForAll()` + * function. + * + * @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 { + MetaTxHelpers.basePermitForAll(owner, operator, approved, sig); + // set opp + } + + /** + * @notice Sets the default profile for a given owner using the `setDefaultProfileWithSig()` + * function. + * + * @param vars the SetDefaultProfileWithSigData struct containing the relevant parameters. + */ + function setDefaultProfileWithSig(DataTypes.SetDefaultProfileWithSigData calldata vars) + external + { + MetaTxHelpers.baseSetDefaultProfileWithSig(vars); + _setDefaultProfile(vars.wallet, vars.profileId); + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `setFollowModuleWithSig()` function. + * + * @param vars the SetFollowModuleWithSigData struct containing the relevant parameters. + */ + function setFollowModuleWithSig(DataTypes.SetFollowModuleWithSigData calldata vars) external { + MetaTxHelpers.baseSetFollowModuleWithSig(vars); + // set follow module + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `setDispatcherWithSig()` function. + * + * @param vars the setDispatcherWithSigData struct containing the relevant parameters. + */ + function setDispatcherWithSig(DataTypes.SetDispatcherWithSigData calldata vars) external { + MetaTxHelpers.baseSetDispatcherWithSig(vars); + // set dispatcher + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `setProfileImageURIWithSig()` function. + * + * @param vars the SetProfileImageURIWithSigData struct containing the relevant parameters. + */ + function setProfileImageURIWithSig(DataTypes.SetProfileImageURIWithSigData calldata vars) + external + { + MetaTxHelpers.baseSetProfileImageURIWithSig(vars); + // Set profile image URI + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `setFollowNFTURIWithSig()` function. + * + * @param vars the SetFollowNFTURIWithSigData struct containing the relevant parameters. + */ + function setFollowNFTURIWithSig(DataTypes.SetFollowNFTURIWithSigData calldata vars) external { + MetaTxHelpers.baseSetFollowNFTURIWithSig(vars); + // set follow NFT URI + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `postWithSig()` function. + * + * @param vars the PostWithSigData struct containing the relevant parameters. + */ + function postWithSig(DataTypes.PostWithSigData calldata vars) external { + MetaTxHelpers.basePostWithSig(vars); + // create post + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `commentWithSig()` function. + * + * @param vars the CommentWithSig struct containing the relevant parameters. + */ + function commentWithSig(DataTypes.CommentWithSigData calldata vars) external { + MetaTxHelpers.baseCommentWithSig(vars); + // create comment + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `mirrorWithSig()` function. + * + * @param vars the MirrorWithSigData struct containing the relevant parameters. + */ + function mirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external { + MetaTxHelpers.baseMirrorWithSig(vars); + // create mirror + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `burnWithSig()` function. + * + * @param tokenId The token ID to burn. + * @param sig the EIP712Signature struct containing the token owner's signature. + */ + function burnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) external { + MetaTxHelpers.baseBurnWithSig(tokenId, sig); + // burn profile + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `followWithSig()` function. + * + * @param vars the FollowWithSigData struct containing the relevant parameters. + */ + function followWithSig( + DataTypes.FollowWithSigData calldata vars, + mapping(uint256 => DataTypes.ProfileStruct) storage _profileById, + mapping(bytes32 => uint256) storage _profileIdByHandleHash + ) external returns (uint256[] memory) { + MetaTxHelpers.baseFollowWithSig(vars); + return + InteractionHelpers.follow( + vars.follower, + vars.profileIds, + vars.datas, + _profileById, + _profileIdByHandleHash + ); + } + + /** + * @notice Validates parameters and increments the nonce for a given owner using the + * `collectWithSig()` function. + * + * @param vars the CollectWithSigData struct containing the relevant parameters. + */ + function collectWithSig( + DataTypes.CollectWithSigData calldata vars, + address collectNFTImpl, + mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct)) + storage _pubByIdByProfile, + mapping(uint256 => DataTypes.ProfileStruct) storage _profileById + ) external returns (uint256) { + MetaTxHelpers.baseCollectWithSig(vars); + return + InteractionHelpers.collect( + vars.collector, + vars.profileId, + vars.pubId, + vars.data, + collectNFTImpl, + _pubByIdByProfile, + _profileById + ); + } + + /** + * @notice Returns the domain separator. + * + * @return bytes32 The domain separator. + */ + function getDomainSeparator() external view returns (bytes32) { + return MetaTxHelpers.getDomainSeparator(); + } + + function _setDefaultProfile(address wallet, uint256 profileId) private { + if (profileId > 0 && wallet != Helpers.unsafeOwnerOf(profileId)) + revert Errors.NotProfileOwner(); + assembly { + mstore(0, wallet) + mstore(32, DEFAULT_PROFILE_MAPPING_SLOT) + let slot := keccak256(0, 64) + sstore(slot, profileId) + } + emit Events.DefaultProfileSet(wallet, profileId, block.timestamp); + } + function _initFollowModule( uint256 profileId, address followModule, @@ -459,6 +733,27 @@ library GeneralLib { if (!whitelisted) revert Errors.ReferenceModuleNotWhitelisted(); } + function _validateHandle(string calldata handle) private pure { + bytes memory byteHandle = bytes(handle); + if (byteHandle.length == 0 || byteHandle.length > MAX_HANDLE_LENGTH) + revert Errors.HandleLengthInvalid(); + + uint256 byteHandleLength = byteHandle.length; + for (uint256 i = 0; i < byteHandleLength; ) { + if ( + (byteHandle[i] < '0' || + byteHandle[i] > 'z' || + (byteHandle[i] > '9' && byteHandle[i] < 'a')) && + byteHandle[i] != '.' && + byteHandle[i] != '-' && + byteHandle[i] != '_' + ) revert Errors.HandleContainsInvalidCharacters(); + unchecked { + ++i; + } + } + } + function _emitCommentCreated( DataTypes.CommentData memory vars, uint256 pubId, @@ -484,7 +779,7 @@ library GeneralLib { uint256 profileId, DataTypes.CreateProfileData calldata vars, bytes memory followModuleReturnData - ) internal { + ) private { emit Events.ProfileCreated( profileId, msg.sender, // Creator is always the msg sender @@ -497,25 +792,4 @@ library GeneralLib { block.timestamp ); } - - function _validateHandle(string calldata handle) private pure { - bytes memory byteHandle = bytes(handle); - if (byteHandle.length == 0 || byteHandle.length > Constants.MAX_HANDLE_LENGTH) - revert Errors.HandleLengthInvalid(); - - uint256 byteHandleLength = byteHandle.length; - for (uint256 i = 0; i < byteHandleLength; ) { - if ( - (byteHandle[i] < '0' || - byteHandle[i] > 'z' || - (byteHandle[i] > '9' && byteHandle[i] < 'a')) && - byteHandle[i] != '.' && - byteHandle[i] != '-' && - byteHandle[i] != '_' - ) revert Errors.HandleContainsInvalidCharacters(); - unchecked { - ++i; - } - } - } } diff --git a/contracts/libraries/Helpers.sol b/contracts/libraries/Helpers.sol index 785f3c3..84c32aa 100644 --- a/contracts/libraries/Helpers.sol +++ b/contracts/libraries/Helpers.sol @@ -13,6 +13,8 @@ import {Errors} from './Errors.sol'; * both the publishing logic and interaction logic libraries. */ library Helpers { + uint256 internal constant TOKEN_DATA_MAPPING_SLOT = 2; + /** * @notice This helper function just returns the pointed publication if the passed publication is a mirror, * otherwise it returns the passed publication. @@ -54,4 +56,27 @@ library Helpers { return (pointedTokenId, pointedPubId, pointedCollectModule); } } + + /** + * @dev This fetches the owner address for a given token ID. Note that this does not check + * and revert upon receiving a zero address. + * + * However, this function is always followed by a call to `_validateRecoveredAddress()` with + * the returned address from this function as the signer, and since `_validateRecoveredAddress()` + * reverts upon recovering the zero address, the execution will always revert if the owner returned + * is the zero address. + */ + function unsafeOwnerOf(uint256 tokenId) internal view returns (address) { + // Note that this does *not* include a zero address check, but this is acceptable because + // _validateRecoveredAddress reverts on recovering a zero address. + address owner; + assembly { + mstore(0, tokenId) + mstore(32, TOKEN_DATA_MAPPING_SLOT) + let slot := keccak256(0, 64) + // this weird bit shift is necessary to remove the packing from the variable + owner := shr(96, shl(96, sload(slot))) + } + return owner; + } } diff --git a/contracts/libraries/InteractionLogic.sol b/contracts/libraries/InteractionHelpers.sol similarity index 78% rename from contracts/libraries/InteractionLogic.sol rename to contracts/libraries/InteractionHelpers.sol index 98b3fc7..d33f51a 100644 --- a/contracts/libraries/InteractionLogic.sol +++ b/contracts/libraries/InteractionHelpers.sol @@ -7,7 +7,6 @@ import {Helpers} from './Helpers.sol'; import {DataTypes} from './DataTypes.sol'; import {Errors} from './Errors.sol'; import {Events} from './Events.sol'; -import {Constants} from './Constants.sol'; import {IFollowNFT} from '../interfaces/IFollowNFT.sol'; import {ICollectNFT} from '../interfaces/ICollectNFT.sol'; import {IFollowModule} from '../interfaces/IFollowModule.sol'; @@ -15,6 +14,8 @@ import {ICollectModule} from '../interfaces/ICollectModule.sol'; import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol'; import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; +import './Constants.sol'; + /** * @title InteractionLogic * @author Lens Protocol @@ -23,30 +24,19 @@ import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; * @dev The functions are external, so they are called from the hub via `delegateCall` under the hood. */ -library InteractionLogic { +library InteractionHelpers { using Strings for uint256; - /** - * @notice Follows the given profiles, executing the necessary logic and module calls before minting the follow - * NFT(s) to the follower. - * - * @param follower The address executing the follow. - * @param profileIds The array of profile token IDs to follow. - * @param followModuleDatas The array of follow module data parameters to pass to each profile's follow module. - * @param _profileById A pointer to the storage mapping of profile structs by profile ID. - * @param _profileIdByHandleHash A pointer to the storage mapping of profile IDs by handle hash. - * - * @return uint256[] An array of integers representing the minted follow NFTs token IDs. - */ function follow( address follower, uint256[] calldata profileIds, bytes[] calldata followModuleDatas, mapping(uint256 => DataTypes.ProfileStruct) storage _profileById, mapping(bytes32 => uint256) storage _profileIdByHandleHash - ) external returns (uint256[] memory) { + ) internal returns (uint256[] memory) { if (profileIds.length != followModuleDatas.length) revert Errors.ArrayMismatch(); uint256[] memory tokenIds = new uint256[](profileIds.length); + for (uint256 i = 0; i < profileIds.length; ) { string memory handle = _profileById[profileIds[i]].handle; if (_profileIdByHandleHash[keccak256(bytes(handle))] != profileIds[i]) @@ -77,20 +67,6 @@ library InteractionLogic { return tokenIds; } - /** - * @notice Collects the given publication, executing the necessary logic and module call before minting the - * collect NFT to the collector. - * - * @param collector The address executing the collect. - * @param profileId The token ID of the publication being collected's parent profile. - * @param pubId The publication ID of the publication being collected. - * @param collectModuleData The data to pass to the publication's collect module. - * @param collectNFTImpl The address of the collect NFT implementation, which has to be passed because it's an immutable in the hub. - * @param _pubByIdByProfile A pointer to the storage mapping of publications by pubId by profile ID. - * @param _profileById A pointer to the storage mapping of profile structs by profile ID. - * - * @return uint256 An integer representing the minted token ID. - */ function collect( address collector, uint256 profileId, @@ -100,7 +76,7 @@ library InteractionLogic { mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct)) storage _pubByIdByProfile, mapping(uint256 => DataTypes.ProfileStruct) storage _profileById - ) external returns (uint256) { + ) internal returns (uint256) { (uint256 rootProfileId, uint256 rootPubId, address rootCollectModule) = Helpers .getPointedIfMirror(profileId, pubId, _pubByIdByProfile); @@ -178,10 +154,10 @@ library InteractionLogic { bytes4 firstBytes = bytes4(bytes(handle)); string memory collectNFTName = string( - abi.encodePacked(handle, Constants.COLLECT_NFT_NAME_INFIX, pubId.toString()) + abi.encodePacked(handle, COLLECT_NFT_NAME_INFIX, pubId.toString()) ); string memory collectNFTSymbol = string( - abi.encodePacked(firstBytes, Constants.COLLECT_NFT_SYMBOL_INFIX, pubId.toString()) + abi.encodePacked(firstBytes, COLLECT_NFT_SYMBOL_INFIX, pubId.toString()) ); ICollectNFT(collectNFT).initialize(profileId, pubId, collectNFTName, collectNFTSymbol); diff --git a/contracts/libraries/MetaTxLib.sol b/contracts/libraries/MetaTxHelpers.sol similarity index 58% rename from contracts/libraries/MetaTxLib.sol rename to contracts/libraries/MetaTxHelpers.sol index 129b71d..0281dc7 100644 --- a/contracts/libraries/MetaTxLib.sol +++ b/contracts/libraries/MetaTxHelpers.sol @@ -1,92 +1,14 @@ // SPDX-License-Identifier: MIT - pragma solidity 0.8.10; import {DataTypes} from './DataTypes.sol'; import {Errors} from './Errors.sol'; +import {DataTypes} from './DataTypes.sol'; +import {Helpers} from './Helpers.sol'; -import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol'; - -/** - * @title MetaTxLib - * - * @author Lens Protocol (Zer0dot) - * - * @notice This library includes functions pertaining to meta-transactions to be called - * specifically from the LensHub. - * - * @dev Meta-transaction functions have had their signature validation delegated to this library, but - * their consequences (e.g: approval, operator approval, profile creation, etc) remain in the hub. - * - * NOTE: This relies on the storage layout of the hub remaining static. Forks/migrations should be aware - * of this. - */ -library MetaTxLib { - // We store constants equal to the storage slots here to later access via inline - // assembly without needing to pass storage pointers. The NAME_SLOT_GT_31 slot - // is equivalent to keccak256(NAME_SLOT) and is where the name string is stored - // if the length is greater than 31 bytes. - uint256 internal constant NAME_SLOT = 0; - uint256 internal constant TOKEN_DATA_MAPPING_SLOT = 2; - uint256 internal constant SIG_NONCES_MAPPING_SLOT = 10; - uint256 internal constant NAME_SLOT_GT_31 = - 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563; - - // We also store typehashes here - 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_WITH_SIG_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)' - ); - bytes32 internal constant SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH = - keccak256( - 'SetDefaultProfileWithSig(address wallet,uint256 profileId,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant SET_FOLLOW_MODULE_WITH_SIG_TYPEHASH = - keccak256( - 'SetFollowModuleWithSig(uint256 profileId,address followModule,bytes followModuleInitData,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant SET_FOLLOW_NFT_URI_WITH_SIG_TYPEHASH = - keccak256( - 'SetFollowNFTURIWithSig(uint256 profileId,string followNFTURI,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant SET_DISPATCHER_WITH_SIG_TYPEHASH = - keccak256( - 'SetDispatcherWithSig(uint256 profileId,address dispatcher,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant SET_PROFILE_IMAGE_URI_WITH_SIG_TYPEHASH = - keccak256( - 'SetProfileImageURIWithSig(uint256 profileId,string imageURI,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant POST_WITH_SIG_TYPEHASH = - keccak256( - 'PostWithSig(uint256 profileId,string contentURI,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant COMMENT_WITH_SIG_TYPEHASH = - keccak256( - 'CommentWithSig(uint256 profileId,string contentURI,uint256 profileIdPointed,uint256 pubIdPointed,bytes referenceModuleData,address collectModule,bytes collectModuleInitData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant MIRROR_WITH_SIG_TYPEHASH = - keccak256( - 'MirrorWithSig(uint256 profileId,uint256 profileIdPointed,uint256 pubIdPointed,bytes referenceModuleData,address referenceModule,bytes referenceModuleInitData,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant FOLLOW_WITH_SIG_TYPEHASH = - keccak256( - 'FollowWithSig(uint256[] profileIds,bytes[] datas,uint256 nonce,uint256 deadline)' - ); - bytes32 internal constant COLLECT_WITH_SIG_TYPEHASH = - keccak256( - 'CollectWithSig(uint256 profileId,uint256 pubId,bytes data,uint256 nonce,uint256 deadline)' - ); +import './Constants.sol'; +library MetaTxHelpers { /** * @notice Validates parameters and increments the nonce for a given owner using the `permit()` * function. @@ -99,9 +21,9 @@ library MetaTxLib { address spender, uint256 tokenId, DataTypes.EIP712Signature calldata sig - ) external { + ) internal { if (spender == address(0)) revert Errors.ZeroSpender(); - address owner = _ownerOf(tokenId); + address owner = Helpers.unsafeOwnerOf(tokenId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -113,21 +35,12 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the `permitForAll()` - * function. - * - * @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 basePermitForAll( address owner, address operator, bool approved, DataTypes.EIP712Signature calldata sig - ) external { + ) internal { if (operator == address(0)) revert Errors.ZeroSpender(); _validateRecoveredAddress( _calculateDigest( @@ -147,14 +60,8 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `setDefaultProfileWithSig()` function. - * - * @param vars the SetDefaultProfileWithSigData struct containing the relevant parameters. - */ function baseSetDefaultProfileWithSig(DataTypes.SetDefaultProfileWithSigData calldata vars) - external + internal { _validateRecoveredAddress( _calculateDigest( @@ -173,16 +80,10 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `setFollowModuleWithSig()` function. - * - * @param vars the SetFollowModuleWithSigData struct containing the relevant parameters. - */ function baseSetFollowModuleWithSig(DataTypes.SetFollowModuleWithSigData calldata vars) - external + internal { - address owner = _ownerOf(vars.profileId); + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -201,14 +102,8 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `setDispatcherWithSig()` function. - * - * @param vars the setDispatcherWithSigData struct containing the relevant parameters. - */ - function baseSetDispatcherWithSig(DataTypes.SetDispatcherWithSigData calldata vars) external { - address owner = _ownerOf(vars.profileId); + function baseSetDispatcherWithSig(DataTypes.SetDispatcherWithSigData calldata vars) internal { + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -226,16 +121,10 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `setProfileImageURIWithSig()` function. - * - * @param vars the SetProfileImageURIWithSigData struct containing the relevant parameters. - */ function baseSetProfileImageURIWithSig(DataTypes.SetProfileImageURIWithSigData calldata vars) - external + internal { - address owner = _ownerOf(vars.profileId); + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -253,16 +142,10 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `setFollowNFTURIWithSig()` function. - * - * @param vars the SetFollowNFTURIWithSigData struct containing the relevant parameters. - */ function baseSetFollowNFTURIWithSig(DataTypes.SetFollowNFTURIWithSigData calldata vars) - external + internal { - address owner = _ownerOf(vars.profileId); + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -280,14 +163,8 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `postWithSig()` function. - * - * @param vars the PostWithSigData struct containing the relevant parameters. - */ - function basePostWithSig(DataTypes.PostWithSigData calldata vars) external { - address owner = _ownerOf(vars.profileId); + function basePostWithSig(DataTypes.PostWithSigData calldata vars) internal { + address owner = Helpers.unsafeOwnerOf(vars.profileId); unchecked { _validateRecoveredAddress( _calculateDigest( @@ -311,14 +188,8 @@ library MetaTxLib { } } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `commentWithSig()` function. - * - * @param vars the CommentWithSig struct containing the relevant parameters. - */ - function baseCommentWithSig(DataTypes.CommentWithSigData calldata vars) external { - address owner = _ownerOf(vars.profileId); + function baseCommentWithSig(DataTypes.CommentWithSigData calldata vars) internal { + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( @@ -344,14 +215,8 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `mirrorWithSig()` function. - * - * @param vars the MirrorWithSigData struct containing the relevant parameters. - */ - function baseMirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external { - address owner = _ownerOf(vars.profileId); + function baseMirrorWithSig(DataTypes.MirrorWithSigData calldata vars) internal { + address owner = Helpers.unsafeOwnerOf(vars.profileId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -373,15 +238,8 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `burnWithSig()` function. - * - * @param tokenId The token ID to burn. - * @param sig the EIP712Signature struct containing the token owner's signature. - */ - function baseBurnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) external { - address owner = _ownerOf(tokenId); + function baseBurnWithSig(uint256 tokenId, DataTypes.EIP712Signature calldata sig) internal { + address owner = Helpers.unsafeOwnerOf(tokenId); _validateRecoveredAddress( _calculateDigest( keccak256( @@ -393,13 +251,7 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `followWithSig()` function. - * - * @param vars the FollowWithSigData struct containing the relevant parameters. - */ - function baseFollowWithSig(DataTypes.FollowWithSigData calldata vars) external { + function baseFollowWithSig(DataTypes.FollowWithSigData calldata vars) internal { uint256 dataLength = vars.datas.length; bytes32[] memory dataHashes = new bytes32[](dataLength); for (uint256 i = 0; i < dataLength; ) { @@ -425,13 +277,7 @@ library MetaTxLib { ); } - /** - * @notice Validates parameters and increments the nonce for a given owner using the - * `collectWithSig()` function. - * - * @param vars the CollectWithSigData struct containing the relevant parameters. - */ - function baseCollectWithSig(DataTypes.CollectWithSigData calldata vars) external { + function baseCollectWithSig(DataTypes.CollectWithSigData calldata vars) internal { _validateRecoveredAddress( _calculateDigest( keccak256( @@ -450,12 +296,7 @@ library MetaTxLib { ); } - /** - * @notice Returns the domain separator. - * - * @return bytes32 The domain separator. - */ - function getDomainSeparator() external view returns (bytes32) { + function getDomainSeparator() internal view returns (bytes32) { return _calculateDomainSeparator(); } @@ -466,7 +307,7 @@ library MetaTxLib { bytes32 digest, address expectedAddress, DataTypes.EIP712Signature calldata sig - ) private view { + ) 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) @@ -506,6 +347,25 @@ library MetaTxLib { return digest; } + /** + * @dev This fetches a user's signing nonce and increments it, akin to `sigNonces++`. + * + * @param user The user address to fetch and post-increment the signing nonce for. + * + * @return uint256 The signing nonce for the given user prior to being incremented. + */ + function _sigNonces(address user) private returns (uint256) { + uint256 previousValue; + assembly { + mstore(0, user) + mstore(32, SIG_NONCES_MAPPING_SLOT) + let slot := keccak256(0, 64) + previousValue := sload(slot) + sstore(slot, add(previousValue, 1)) + } + return previousValue; + } + /** * @dev Reads the name storage slot and returns the value as a bytes variable. * @@ -565,46 +425,4 @@ library MetaTxLib { // Return a memory pointer to the name (which always starts with the size at the first slot) return ptr; } - - /** - * @dev This fetches a user's signing nonce and increments it, akin to `sigNonces++`. - * - * @param user The user address to fetch and post-increment the signing nonce for. - * - * @return uint256 The signing nonce for the given user prior to being incremented. - */ - function _sigNonces(address user) private returns (uint256) { - uint256 previousValue; - assembly { - mstore(0, user) - mstore(32, SIG_NONCES_MAPPING_SLOT) - let slot := keccak256(0, 64) - previousValue := sload(slot) - sstore(slot, add(previousValue, 1)) - } - return previousValue; - } - - /** - * @dev This fetches the owner address for a given token ID. Note that this does not check - * and revert upon receiving a zero address. - * - * However, this function is always followed by a call to `_validateRecoveredAddress()` with - * the returned address from this function as the signer, and since `_validateRecoveredAddress()` - * reverts upon recovering the zero address, the execution will always revert if the owner returned - * is the zero address. - */ - function _ownerOf(uint256 tokenId) private view returns (address) { - // Note that this does *not* include a zero address check, but this is acceptable because - // _validateRecoveredAddress reverts on recovering a zero address. - address owner; - assembly { - mstore(0, tokenId) - mstore(32, TOKEN_DATA_MAPPING_SLOT) - let slot := keccak256(0, 64) - // this weird bit shift is necessary to remove the packing from the variable - owner := shr(96, shl(96, sload(slot))) - } - return owner; - } } diff --git a/contracts/mocks/MockLensHubV2.sol b/contracts/mocks/MockLensHubV2.sol index 88961f2..55ab261 100644 --- a/contracts/mocks/MockLensHubV2.sol +++ b/contracts/mocks/MockLensHubV2.sol @@ -2,13 +2,6 @@ pragma solidity 0.8.10; -import {ILensHub} from '../interfaces/ILensHub.sol'; -import {Events} from '../libraries/Events.sol'; -import {Helpers} from '../libraries/Helpers.sol'; -import {DataTypes} from '../libraries/DataTypes.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {GeneralLib} from '../libraries/GeneralLib.sol'; -import {InteractionLogic} from '../libraries/InteractionLogic.sol'; import {LensNFTBase} from '../core/base/LensNFTBase.sol'; import {LensMultiState} from '../core/base/LensMultiState.sol'; import {VersionedInitializable} from '../upgradeability/VersionedInitializable.sol'; diff --git a/contracts/mocks/MockLensHubV2BadRevision.sol b/contracts/mocks/MockLensHubV2BadRevision.sol index a385bc2..8212fa7 100644 --- a/contracts/mocks/MockLensHubV2BadRevision.sol +++ b/contracts/mocks/MockLensHubV2BadRevision.sol @@ -2,13 +2,6 @@ pragma solidity 0.8.10; -import {ILensHub} from '../interfaces/ILensHub.sol'; -import {Events} from '../libraries/Events.sol'; -import {Helpers} from '../libraries/Helpers.sol'; -import {DataTypes} from '../libraries/DataTypes.sol'; -import {Errors} from '../libraries/Errors.sol'; -import {GeneralLib} from '../libraries/GeneralLib.sol'; -import {InteractionLogic} from '../libraries/InteractionLogic.sol'; import {LensNFTBase} from '../core/base/LensNFTBase.sol'; import {LensMultiState} from '../core/base/LensMultiState.sol'; import {VersionedInitializable} from '../upgradeability/VersionedInitializable.sol'; diff --git a/package.json b/package.json index 31da1ce..6fc2359 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "npm run compile && TRACK_GAS=true hardhat test", "quick-test": "hardhat test", "spdx": "hardhat prepend-spdx-license", - "size": "npm run compile && hardhat size-contracts", + "size": "npm run compile && SKIP_LOAD=true hardhat size-contracts", "full-deploy-local": "hardhat full-deploy --network localhost", "full-deploy-mumbai": "hardhat full-deploy --network mumbai", "coverage": "npm run compile && hardhat coverage --temp temp-artifacts --testfiles test/emptyrun.coverage.ts && hardhat coverage --temp temp-artifacts --testfiles '!test/emptyrun.coverage.ts'", diff --git a/tasks/full-deploy-verify.ts b/tasks/full-deploy-verify.ts index 3239ec8..316a2b7 100644 --- a/tasks/full-deploy-verify.ts +++ b/tasks/full-deploy-verify.ts @@ -12,7 +12,6 @@ import { FeeFollowModule__factory, FollowerOnlyReferenceModule__factory, FollowNFT__factory, - InteractionLogic__factory, LimitedFeeCollectModule__factory, LimitedTimedFeeCollectModule__factory, ModuleGlobals__factory, @@ -26,7 +25,6 @@ import { ProfileFollowModule__factory, RevertFollowModule__factory, ProfileCreationProxy__factory, - MetaTxLib__factory, } from '../typechain-types'; import { deployWithVerify, waitForTx } from './helpers/utils'; @@ -83,27 +81,15 @@ task('full-deploy-verify', 'deploys the entire Lens Protocol with explorer verif [], 'contracts/libraries/GeneralLib.sol:GeneralLib' ); - const interactionLogic = await deployWithVerify( - new InteractionLogic__factory(deployer).deploy({ nonce: deployerNonce++ }), - [], - 'contracts/libraries/InteractionLogic.sol:InteractionLogic' - ); const profileTokenURILogic = await deployWithVerify( new ProfileTokenURILogic__factory(deployer).deploy({ nonce: deployerNonce++ }), [], 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic' ); - const metaTxLib = await deployWithVerify( - new MetaTxLib__factory(deployer).deploy({ nonce: deployerNonce++ }), - [], - 'contracts/libraries/MetaTxLib.sol:MetaTxLib' - ); const hubLibs = { 'contracts/libraries/GeneralLib.sol:GeneralLib': generalLib.address, - 'contracts/libraries/InteractionLogic.sol:InteractionLogic': interactionLogic.address, 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic': profileTokenURILogic.address, - 'contracts/libraries/MetaTxLib.sol:MetaTxLib': metaTxLib.address, }; // Here, we pre-compute the nonces and addresses used to deploy the contracts. @@ -359,7 +345,6 @@ task('full-deploy-verify', 'deploys the entire Lens Protocol with explorer verif 'lensHub proxy': lensHub.address, 'lensHub impl:': lensHubImpl.address, 'publishing logic lib': generalLib.address, - 'interaction logic lib': interactionLogic.address, 'profile token URI logic lib': profileTokenURILogic.address, 'follow NFT impl': followNFTImplAddress, 'collect NFT impl': collectNFTImplAddress, diff --git a/tasks/full-deploy.ts b/tasks/full-deploy.ts index d078439..c832aef 100644 --- a/tasks/full-deploy.ts +++ b/tasks/full-deploy.ts @@ -12,7 +12,6 @@ import { FeeFollowModule__factory, FollowerOnlyReferenceModule__factory, FollowNFT__factory, - InteractionLogic__factory, LimitedFeeCollectModule__factory, LimitedTimedFeeCollectModule__factory, ModuleGlobals__factory, @@ -26,7 +25,6 @@ import { ProfileFollowModule__factory, RevertFollowModule__factory, ProfileCreationProxy__factory, - MetaTxLib__factory, } from '../typechain-types'; import { deployContract, waitForTx } from './helpers/utils'; @@ -63,21 +61,13 @@ task('full-deploy', 'deploys the entire Lens Protocol').setAction(async ({}, hre const generalLib = await deployContract( new GeneralLib__factory(deployer).deploy({ nonce: deployerNonce++ }) ); - const interactionLogic = await deployContract( - new InteractionLogic__factory(deployer).deploy({ nonce: deployerNonce++ }) - ); const profileTokenURILogic = await deployContract( new ProfileTokenURILogic__factory(deployer).deploy({ nonce: deployerNonce++ }) ); - const metaTxLib = await deployContract( - new MetaTxLib__factory(deployer).deploy({ nonce: deployerNonce++ }) - ); const hubLibs = { 'contracts/libraries/GeneralLib.sol:GeneralLib': generalLib.address, - 'contracts/libraries/InteractionLogic.sol:InteractionLogic': interactionLogic.address, 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic': profileTokenURILogic.address, - 'contracts/libraries/MetaTxLib.sol:MetaTxLib': metaTxLib.address, }; // Here, we pre-compute the nonces and addresses used to deploy the contracts. @@ -299,7 +289,6 @@ task('full-deploy', 'deploys the entire Lens Protocol').setAction(async ({}, hre 'lensHub proxy': lensHub.address, 'lensHub impl:': lensHubImpl.address, 'publishing logic lib': generalLib.address, - 'interaction logic lib': interactionLogic.address, 'follow NFT impl': followNFTImplAddress, 'collect NFT impl': collectNFTImplAddress, currency: currency.address, diff --git a/tasks/list-storage.ts b/tasks/list-storage.ts index 2140cb2..7a4cb04 100644 --- a/tasks/list-storage.ts +++ b/tasks/list-storage.ts @@ -4,11 +4,9 @@ import { task } from 'hardhat/config'; import { LensHub__factory, GeneralLib__factory, - InteractionLogic__factory, ProfileTokenURILogic__factory, FollowNFT__factory, TransparentUpgradeableProxy__factory, - MetaTxLib__factory, } from '../typechain-types'; import { deployContract, waitForTx } from './helpers/utils'; @@ -27,21 +25,13 @@ task('list-storage', '').setAction(async ({}, hre) => { const generalLib = await deployContract( new GeneralLib__factory(deployer).deploy({ nonce: deployerNonce++ }) ); - const interactionLogic = await deployContract( - new InteractionLogic__factory(deployer).deploy({ nonce: deployerNonce++ }) - ); const profileTokenURILogic = await deployContract( new ProfileTokenURILogic__factory(deployer).deploy({ nonce: deployerNonce++ }) ); - const metaTxLib = await deployContract( - new MetaTxLib__factory(deployer).deploy({ nonce: deployerNonce++ }) - ); const hubLibs = { 'contracts/libraries/GeneralLib.sol:GeneralLib': generalLib.address, - 'contracts/libraries/InteractionLogic.sol:InteractionLogic': interactionLogic.address, 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic': profileTokenURILogic.address, - 'contracts/libraries/MetaTxLib.sol:MetaTxLib': metaTxLib.address, }; // Here, we pre-compute the nonces and addresses used to deploy the contracts. diff --git a/tasks/testnet-full-deploy-verify.ts b/tasks/testnet-full-deploy-verify.ts index 70b797b..8df86b7 100644 --- a/tasks/testnet-full-deploy-verify.ts +++ b/tasks/testnet-full-deploy-verify.ts @@ -12,7 +12,6 @@ import { FeeFollowModule__factory, FollowerOnlyReferenceModule__factory, FollowNFT__factory, - InteractionLogic__factory, LimitedFeeCollectModule__factory, LimitedTimedFeeCollectModule__factory, ModuleGlobals__factory, @@ -26,7 +25,6 @@ import { UIDataProvider__factory, ProfileFollowModule__factory, RevertFollowModule__factory, - MetaTxLib__factory, } from '../typechain-types'; import { deployWithVerify, waitForTx } from './helpers/utils'; @@ -82,27 +80,15 @@ task( [], 'contracts/libraries/GeneralLib.sol:GeneralLib' ); - const interactionLogic = await deployWithVerify( - new InteractionLogic__factory(deployer).deploy({ nonce: deployerNonce++ }), - [], - 'contracts/libraries/InteractionLogic.sol:InteractionLogic' - ); const profileTokenURILogic = await deployWithVerify( new ProfileTokenURILogic__factory(deployer).deploy({ nonce: deployerNonce++ }), [], 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic' ); - const metaTxLib = await deployWithVerify( - new MetaTxLib__factory(deployer).deploy({ nonce: deployerNonce++ }), - [], - 'contracts/libraries/MetaTxLib.sol:MetaTxLib' - ); const hubLibs = { 'contracts/libraries/GeneralLib.sol:GeneralLib': generalLib.address, - 'contracts/libraries/InteractionLogic.sol:InteractionLogic': interactionLogic.address, 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic': profileTokenURILogic.address, - 'contracts/libraries/MetaTxLib.sol:MetaTxLib': metaTxLib.address, }; // Here, we pre-compute the nonces and addresses used to deploy the contracts. @@ -347,7 +333,6 @@ task( 'lensHub proxy': lensHub.address, 'lensHub impl:': lensHubImpl.address, 'publishing logic lib': generalLib.address, - 'interaction logic lib': interactionLogic.address, 'profile token URI logic lib': profileTokenURILogic.address, 'follow NFT impl': followNFTImplAddress, 'collect NFT impl': collectNFTImplAddress, diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index c799b95..5494f12 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -24,7 +24,6 @@ import { FollowNFT__factory, Helper, Helper__factory, - InteractionLogic__factory, LensHub, LensHub__factory, LimitedFeeCollectModule, @@ -39,7 +38,6 @@ import { ModuleGlobals__factory, ProfileTokenURILogic__factory, GeneralLib__factory, - MetaTxLib__factory, RevertCollectModule, RevertCollectModule__factory, TimedFeeCollectModule, @@ -166,15 +164,11 @@ before(async function () { TREASURY_FEE_BPS ); const generalLib = await new GeneralLib__factory(deployer).deploy(); - const interactionLogic = await new InteractionLogic__factory(deployer).deploy(); const profileTokenURILogic = await new ProfileTokenURILogic__factory(deployer).deploy(); - const metaTxLib = await new MetaTxLib__factory(deployer).deploy(); hubLibs = { 'contracts/libraries/GeneralLib.sol:GeneralLib': generalLib.address, - 'contracts/libraries/InteractionLogic.sol:InteractionLogic': interactionLogic.address, 'contracts/libraries/ProfileTokenURILogic.sol:ProfileTokenURILogic': profileTokenURILogic.address, - 'contracts/libraries/MetaTxLib.sol:MetaTxLib': metaTxLib.address, }; // Here, we pre-compute the nonces and addresses used to deploy the contracts.