diff --git a/contracts/core/LensHub.sol b/contracts/core/LensHub.sol index 1100205..8452827 100644 --- a/contracts/core/LensHub.sol +++ b/contracts/core/LensHub.sol @@ -21,6 +21,7 @@ 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 {MetaTxHelpers} from 'contracts/libraries/helpers/MetaTxHelpers.sol'; /** * @title LensHub @@ -343,9 +344,9 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub function quoteWithSig( DataTypes.QuoteParams calldata quoteParams, address signer, - EIP712Signature calldata signature + DataTypes.EIP712Signature calldata signature ) external override whenPublishingEnabled returns (uint256) { - MetaTxHelpers.validateQuoteSignature(signer, quoteParams); + MetaTxHelpers.validateQuoteSignature(signer, quoteParams, signature); return PublishingLib.quote({quoteParams: quoteParams, transactionExecutor: signer}); } diff --git a/contracts/core/modules/reference/FollowerOnlyReferenceModule.sol b/contracts/core/modules/reference/FollowerOnlyReferenceModule.sol index 51e7c54..a012fc9 100644 --- a/contracts/core/modules/reference/FollowerOnlyReferenceModule.sol +++ b/contracts/core/modules/reference/FollowerOnlyReferenceModule.sol @@ -46,6 +46,23 @@ contract FollowerOnlyReferenceModule is FollowValidationModuleBase, IReferenceMo _checkFollowValidity(profileIdPointed, commentCreator); } + /** + * @notice Validates that the quoting profile's owner is a follower. + * + * NOTE: We don't need to care what the pointed publication is in this context. + */ + function processQuote( + uint256 profileId, + address, + uint256 profileIdPointed, + uint256, + uint256, + bytes calldata + ) external view override { + address quoteCreator = IERC721(HUB).ownerOf(profileId); + _checkFollowValidity(profileIdPointed, quoteCreator); + } + /** * @notice Validates that the mirroring profile's owner is a follower. * diff --git a/contracts/interfaces/ILensHub.sol b/contracts/interfaces/ILensHub.sol index 504c671..1043f63 100644 --- a/contracts/interfaces/ILensHub.sol +++ b/contracts/interfaces/ILensHub.sol @@ -281,6 +281,31 @@ interface ILensHub { */ function mirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external returns (uint256); + /** + * @notice Publishes a quote to a given profile, must be called by the profile owner. + * + * @param quoteParams A QuoteParams struct containing the needed parameters. + * + * @return uint256 An integer representing the quote's publication ID. + */ + function quote(DataTypes.QuoteParams calldata quoteParams) external returns (uint256); + + /** + * @notice Publishes a quote to a given profile via signature with the specified parameters. The signer must + * either be the profile owner or a delegated executor. + * + * @param quoteParams A QuoteParams struct containing the needed parameters. + * @param signer The address of the signer. + * @param signature The signature of the quote. + * + * @return uint256 An integer representing the quote's publication ID. + */ + function quoteWithSig( + DataTypes.QuoteParams calldata quoteParams, + address signer, + DataTypes.EIP712Signature calldata signature + ) external returns (uint256); + /** * @notice Follows the given profiles, executing each profile's follow module logic (if any). * diff --git a/contracts/interfaces/IReferenceModule.sol b/contracts/interfaces/IReferenceModule.sol index d2b6436..a54aa79 100644 --- a/contracts/interfaces/IReferenceModule.sol +++ b/contracts/interfaces/IReferenceModule.sol @@ -55,6 +55,26 @@ interface IReferenceModule { bytes calldata data ) external; + /** + * @notice Processes a quote action referencing a given publication. This can only be called by the hub. + * + * @param profileId The token ID of the profile associated with the publication being published. + * @param executor The profile owner or an approved delegated executor. + * @param profileIdPointed The profile ID of the profile associated the publication being quoted. + * @param pubIdPointed The publication ID of the publication being quoted. + * @param referrerProfileId The ID of the profile authoring the mirror if the quote was done through it, zero if + the quote was performed directly through the original publication. // TODO: is this correct? + * @param data Arbitrary data __passed from the executor!__ to be decoded. + */ + function processQuote( + uint256 profileId, + address executor, + uint256 profileIdPointed, + uint256 pubIdPointed, + uint256 referrerProfileId, + bytes calldata data + ) external; + /** * @notice Processes a mirror action referencing a given publication. This can only be called by the hub. * diff --git a/contracts/libraries/DataTypes.sol b/contracts/libraries/DataTypes.sol index 8dc1a53..b24da32 100644 --- a/contracts/libraries/DataTypes.sol +++ b/contracts/libraries/DataTypes.sol @@ -285,7 +285,7 @@ library DataTypes { * @param referenceModule The reference module to set for the given publication, must be whitelisted. * @param referenceModuleInitData The data to be passed to the reference module for initialization. */ - struct QuotePamars { + struct QuoteParams { uint256 profileId; string contentURI; uint256 profileIdPointed; diff --git a/contracts/libraries/helpers/MetaTxHelpers.sol b/contracts/libraries/helpers/MetaTxHelpers.sol index 237566f..84b66c1 100644 --- a/contracts/libraries/helpers/MetaTxHelpers.sol +++ b/contracts/libraries/helpers/MetaTxHelpers.sol @@ -237,25 +237,25 @@ library MetaTxHelpers { ); } - function validateQuoteWithSig( + function validateQuoteSignature( address signer, // TODO: put a signer inside sig struct DataTypes.QuoteParams calldata quoteParams, - EIP712Signature calldata sig + DataTypes.EIP712Signature calldata sig ) internal { _validateRecoveredAddress( _calculateDigest( keccak256( abi.encode( COMMENT_WITH_SIG_TYPEHASH, - vars.profileId, - keccak256(bytes(vars.contentURI)), - vars.profileIdPointed, - vars.pubIdPointed, - keccak256(vars.referenceModuleData), - vars.collectModule, - keccak256(vars.collectModuleInitData), - vars.referenceModule, - keccak256(vars.referenceModuleInitData), + quoteParams.profileId, + keccak256(bytes(quoteParams.contentURI)), + quoteParams.profileIdPointed, + quoteParams.pubIdPointed, + keccak256(quoteParams.referenceModuleData), + quoteParams.collectModule, + keccak256(quoteParams.collectModuleInitData), + quoteParams.referenceModule, + keccak256(quoteParams.referenceModuleInitData), _sigNonces(signer), sig.deadline ) diff --git a/contracts/mocks/MockReferenceModule.sol b/contracts/mocks/MockReferenceModule.sol index 0786f1a..f562c37 100644 --- a/contracts/mocks/MockReferenceModule.sol +++ b/contracts/mocks/MockReferenceModule.sol @@ -28,6 +28,15 @@ contract MockReferenceModule is IReferenceModule { bytes calldata data ) external override {} + function processQuote( + uint256 profileId, + address executor, + uint256 profileIdPointed, + uint256 pubIdPointed, + uint256 referrerProfileId, + bytes calldata data + ) external override {} + function processMirror( uint256 profileId, address executor,