mirror of
https://github.com/lens-protocol/core.git
synced 2026-01-15 00:48:12 -05:00
misc: TypehashConstants added and all meta-tx uses MetaTx lib
Co-authored-by: Victor Naumik <vicnaum@gmail.com>
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
|
||||
38
contracts/libraries/constants/TypehashConstants.sol
Normal file
38
contracts/libraries/constants/TypehashConstants.sol
Normal 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)');
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user