misc: TypehashConstants added and all meta-tx uses MetaTx lib

Co-authored-by: Victor Naumik <vicnaum@gmail.com>
This commit is contained in:
donosonaumczuk
2023-02-21 20:23:26 +00:00
parent 293e8e768c
commit 93c4e14ee3
19 changed files with 266 additions and 679 deletions

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;
}
/**

View File

@@ -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,

View File

@@ -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)');
}

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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),

View File

@@ -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)),

View File

@@ -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,

View File

@@ -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 {}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)

View File

@@ -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
)

View File

@@ -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
)