mirror of
https://github.com/lens-protocol/core.git
synced 2026-04-22 03:02:03 -04:00
Merge pull request #88 from aave/feat/return-ids
This commit is contained in:
@@ -48,11 +48,12 @@ contract CollectNFT is ICollectNFT, LensNFTBase {
|
||||
}
|
||||
|
||||
/// @inheritdoc ICollectNFT
|
||||
function mint(address to) external override {
|
||||
function mint(address to) external override returns (uint256) {
|
||||
if (msg.sender != HUB) revert Errors.NotHub();
|
||||
unchecked {
|
||||
uint256 tokenId = ++_tokenIdCounter;
|
||||
_mint(to, tokenId);
|
||||
return tokenId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,11 +64,12 @@ contract FollowNFT is LensNFTBase, IFollowNFT {
|
||||
}
|
||||
|
||||
/// @inheritdoc IFollowNFT
|
||||
function mint(address to) external override {
|
||||
function mint(address to) external override returns (uint256) {
|
||||
if (msg.sender != HUB) revert Errors.NotHub();
|
||||
unchecked {
|
||||
uint256 tokenId = ++_tokenIdCounter;
|
||||
_mint(to, tokenId);
|
||||
return tokenId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,21 +84,23 @@ contract FollowNFT is LensNFTBase, IFollowNFT {
|
||||
address delegatee,
|
||||
DataTypes.EIP712Signature calldata sig
|
||||
) external override {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
DELEGATE_BY_SIG_TYPEHASH,
|
||||
delegator,
|
||||
delegatee,
|
||||
sigNonces[delegator]++,
|
||||
sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
DELEGATE_BY_SIG_TYPEHASH,
|
||||
delegator,
|
||||
delegatee,
|
||||
sigNonces[delegator]++,
|
||||
sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
delegator,
|
||||
sig
|
||||
);
|
||||
),
|
||||
delegator,
|
||||
sig
|
||||
);
|
||||
}
|
||||
_delegate(delegator, delegatee);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenNotPaused
|
||||
returns (uint256)
|
||||
{
|
||||
if (!_profileCreatorWhitelisted[msg.sender]) revert Errors.ProfileCreatorNotWhitelisted();
|
||||
unchecked {
|
||||
@@ -154,6 +155,7 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
_profileById,
|
||||
_followModuleWhitelisted
|
||||
);
|
||||
return profileId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,22 +170,24 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
override
|
||||
whenNotPaused
|
||||
{
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH,
|
||||
vars.wallet,
|
||||
vars.profileId,
|
||||
sigNonces[vars.wallet]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_DEFAULT_PROFILE_WITH_SIG_TYPEHASH,
|
||||
vars.wallet,
|
||||
vars.profileId,
|
||||
sigNonces[vars.wallet]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
vars.wallet,
|
||||
vars.sig
|
||||
);
|
||||
_setDefaultProfile(vars.wallet, vars.profileId);
|
||||
),
|
||||
vars.wallet,
|
||||
vars.sig
|
||||
);
|
||||
_setDefaultProfile(vars.wallet, vars.profileId);
|
||||
}
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -209,22 +213,24 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
whenNotPaused
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_FOLLOW_MODULE_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.followModule,
|
||||
keccak256(vars.followModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_FOLLOW_MODULE_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.followModule,
|
||||
keccak256(vars.followModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
PublishingLogic.setFollowModule(
|
||||
vars.profileId,
|
||||
vars.followModule,
|
||||
@@ -247,21 +253,23 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
whenNotPaused
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_DISPATCHER_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.dispatcher,
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_DISPATCHER_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.dispatcher,
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
_setDispatcher(vars.profileId, vars.dispatcher);
|
||||
}
|
||||
|
||||
@@ -282,21 +290,23 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
whenNotPaused
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_PROFILE_IMAGE_URI_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.imageURI)),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_PROFILE_IMAGE_URI_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.imageURI)),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
_setProfileImageURI(vars.profileId, vars.imageURI);
|
||||
}
|
||||
|
||||
@@ -317,35 +327,43 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
whenNotPaused
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_FOLLOW_NFT_URI_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.followNFTURI)),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
SET_FOLLOW_NFT_URI_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.followNFTURI)),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
_setFollowNFTURI(vars.profileId, vars.followNFTURI);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
function post(DataTypes.PostData calldata vars) external override whenPublishingEnabled {
|
||||
function post(DataTypes.PostData calldata vars)
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
_validateCallerIsProfileOwnerOrDispatcher(vars.profileId);
|
||||
_createPost(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
return
|
||||
_createPost(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -353,41 +371,50 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
POST_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.contentURI)),
|
||||
vars.collectModule,
|
||||
keccak256(vars.collectModuleData),
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
POST_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.contentURI)),
|
||||
vars.collectModule,
|
||||
keccak256(vars.collectModuleData),
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
_createPost(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
return
|
||||
_createPost(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
function comment(DataTypes.CommentData calldata vars) external override whenPublishingEnabled {
|
||||
function comment(DataTypes.CommentData calldata vars)
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
_validateCallerIsProfileOwnerOrDispatcher(vars.profileId);
|
||||
_createComment(vars);
|
||||
return _createComment(vars);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -395,53 +422,63 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
COMMENT_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.contentURI)),
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.collectModule,
|
||||
keccak256(vars.collectModuleData),
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
COMMENT_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
keccak256(bytes(vars.contentURI)),
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.collectModule,
|
||||
keccak256(vars.collectModuleData),
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
return
|
||||
_createComment(
|
||||
DataTypes.CommentData(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
_createComment(
|
||||
DataTypes.CommentData(
|
||||
vars.profileId,
|
||||
vars.contentURI,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.collectModule,
|
||||
vars.collectModuleData,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
function mirror(DataTypes.MirrorData calldata vars) external override whenPublishingEnabled {
|
||||
function mirror(DataTypes.MirrorData calldata vars)
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
_validateCallerIsProfileOwnerOrDispatcher(vars.profileId);
|
||||
_createMirror(
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
return
|
||||
_createMirror(
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -449,33 +486,37 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenPublishingEnabled
|
||||
returns (uint256)
|
||||
{
|
||||
address owner = ownerOf(vars.profileId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
MIRROR_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
MIRROR_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
keccak256(vars.referenceModuleData),
|
||||
sigNonces[owner]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
_createMirror(
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
),
|
||||
owner,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
return
|
||||
_createMirror(
|
||||
vars.profileId,
|
||||
vars.profileIdPointed,
|
||||
vars.pubIdPointed,
|
||||
vars.referenceModule,
|
||||
vars.referenceModuleData
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,15 +556,17 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenNotPaused
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
InteractionLogic.follow(
|
||||
msg.sender,
|
||||
profileIds,
|
||||
datas,
|
||||
FOLLOW_NFT_IMPL,
|
||||
_profileById,
|
||||
_profileIdByHandleHash
|
||||
);
|
||||
return
|
||||
InteractionLogic.follow(
|
||||
msg.sender,
|
||||
profileIds,
|
||||
datas,
|
||||
FOLLOW_NFT_IMPL,
|
||||
_profileById,
|
||||
_profileIdByHandleHash
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -531,6 +574,7 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenNotPaused
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
uint256 dataLength = vars.datas.length;
|
||||
bytes32[] memory dataHashes = new bytes32[](dataLength);
|
||||
@@ -540,29 +584,32 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
++i;
|
||||
}
|
||||
}
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
FOLLOW_WITH_SIG_TYPEHASH,
|
||||
keccak256(abi.encodePacked(vars.profileIds)),
|
||||
keccak256(abi.encodePacked(dataHashes)),
|
||||
sigNonces[vars.follower]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
FOLLOW_WITH_SIG_TYPEHASH,
|
||||
keccak256(abi.encodePacked(vars.profileIds)),
|
||||
keccak256(abi.encodePacked(dataHashes)),
|
||||
sigNonces[vars.follower]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
vars.follower,
|
||||
vars.sig
|
||||
);
|
||||
InteractionLogic.follow(
|
||||
vars.follower,
|
||||
vars.profileIds,
|
||||
vars.datas,
|
||||
FOLLOW_NFT_IMPL,
|
||||
_profileById,
|
||||
_profileIdByHandleHash
|
||||
);
|
||||
),
|
||||
vars.follower,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
return
|
||||
InteractionLogic.follow(
|
||||
vars.follower,
|
||||
vars.profileIds,
|
||||
vars.datas,
|
||||
FOLLOW_NFT_IMPL,
|
||||
_profileById,
|
||||
_profileIdByHandleHash
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -570,16 +617,17 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
uint256 profileId,
|
||||
uint256 pubId,
|
||||
bytes calldata data
|
||||
) external override whenNotPaused {
|
||||
InteractionLogic.collect(
|
||||
msg.sender,
|
||||
profileId,
|
||||
pubId,
|
||||
data,
|
||||
COLLECT_NFT_IMPL,
|
||||
_pubByIdByProfile,
|
||||
_profileById
|
||||
);
|
||||
) external override whenNotPaused returns (uint256) {
|
||||
return
|
||||
InteractionLogic.collect(
|
||||
msg.sender,
|
||||
profileId,
|
||||
pubId,
|
||||
data,
|
||||
COLLECT_NFT_IMPL,
|
||||
_pubByIdByProfile,
|
||||
_profileById
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -587,32 +635,36 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
external
|
||||
override
|
||||
whenNotPaused
|
||||
returns (uint256)
|
||||
{
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
COLLECT_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.pubId,
|
||||
keccak256(vars.data),
|
||||
sigNonces[vars.collector]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
COLLECT_WITH_SIG_TYPEHASH,
|
||||
vars.profileId,
|
||||
vars.pubId,
|
||||
keccak256(vars.data),
|
||||
sigNonces[vars.collector]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
vars.collector,
|
||||
vars.sig
|
||||
);
|
||||
InteractionLogic.collect(
|
||||
vars.collector,
|
||||
vars.profileId,
|
||||
vars.pubId,
|
||||
vars.data,
|
||||
COLLECT_NFT_IMPL,
|
||||
_pubByIdByProfile,
|
||||
_profileById
|
||||
);
|
||||
),
|
||||
vars.collector,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
return
|
||||
InteractionLogic.collect(
|
||||
vars.collector,
|
||||
vars.profileId,
|
||||
vars.pubId,
|
||||
vars.data,
|
||||
COLLECT_NFT_IMPL,
|
||||
_pubByIdByProfile,
|
||||
_profileById
|
||||
);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensHub
|
||||
@@ -861,19 +913,23 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
bytes memory collectModuleData,
|
||||
address referenceModule,
|
||||
bytes memory referenceModuleData
|
||||
) internal {
|
||||
PublishingLogic.createPost(
|
||||
profileId,
|
||||
contentURI,
|
||||
collectModule,
|
||||
collectModuleData,
|
||||
referenceModule,
|
||||
referenceModuleData,
|
||||
++_profileById[profileId].pubCount,
|
||||
_pubByIdByProfile,
|
||||
_collectModuleWhitelisted,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
) internal returns (uint256) {
|
||||
unchecked {
|
||||
uint256 pubId = ++_profileById[profileId].pubCount;
|
||||
PublishingLogic.createPost(
|
||||
profileId,
|
||||
contentURI,
|
||||
collectModule,
|
||||
collectModuleData,
|
||||
referenceModule,
|
||||
referenceModuleData,
|
||||
pubId,
|
||||
_pubByIdByProfile,
|
||||
_collectModuleWhitelisted,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
return pubId;
|
||||
}
|
||||
}
|
||||
|
||||
function _setDefaultProfile(address wallet, uint256 profileId) internal {
|
||||
@@ -885,15 +941,19 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
emit Events.DefaultProfileSet(wallet, profileId, block.timestamp);
|
||||
}
|
||||
|
||||
function _createComment(DataTypes.CommentData memory vars) internal {
|
||||
PublishingLogic.createComment(
|
||||
vars,
|
||||
++_profileById[vars.profileId].pubCount,
|
||||
_profileById,
|
||||
_pubByIdByProfile,
|
||||
_collectModuleWhitelisted,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
function _createComment(DataTypes.CommentData memory vars) internal returns (uint256) {
|
||||
unchecked {
|
||||
uint256 pubId = ++_profileById[vars.profileId].pubCount;
|
||||
PublishingLogic.createComment(
|
||||
vars,
|
||||
pubId,
|
||||
_profileById,
|
||||
_pubByIdByProfile,
|
||||
_collectModuleWhitelisted,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
return pubId;
|
||||
}
|
||||
}
|
||||
|
||||
function _createMirror(
|
||||
@@ -902,17 +962,21 @@ contract LensHub is ILensHub, LensNFTBase, VersionedInitializable, LensMultiStat
|
||||
uint256 pubIdPointed,
|
||||
address referenceModule,
|
||||
bytes calldata referenceModuleData
|
||||
) internal {
|
||||
PublishingLogic.createMirror(
|
||||
profileId,
|
||||
profileIdPointed,
|
||||
pubIdPointed,
|
||||
referenceModule,
|
||||
referenceModuleData,
|
||||
++_profileById[profileId].pubCount,
|
||||
_pubByIdByProfile,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
) internal returns (uint256) {
|
||||
unchecked {
|
||||
uint256 pubId = ++_profileById[profileId].pubCount;
|
||||
PublishingLogic.createMirror(
|
||||
profileId,
|
||||
profileIdPointed,
|
||||
pubIdPointed,
|
||||
referenceModule,
|
||||
referenceModuleData,
|
||||
pubId,
|
||||
_pubByIdByProfile,
|
||||
_referenceModuleWhitelisted
|
||||
);
|
||||
return pubId;
|
||||
}
|
||||
}
|
||||
|
||||
function _setDispatcher(uint256 profileId, address dispatcher) internal {
|
||||
|
||||
@@ -49,15 +49,23 @@ abstract contract LensNFTBase is ILensNFTBase, ERC721Enumerable {
|
||||
) external override {
|
||||
if (spender == address(0)) revert Errors.ZeroSpender();
|
||||
address owner = ownerOf(tokenId);
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(PERMIT_TYPEHASH, spender, tokenId, sigNonces[owner]++, sig.deadline)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
PERMIT_TYPEHASH,
|
||||
spender,
|
||||
tokenId,
|
||||
sigNonces[owner]++,
|
||||
sig.deadline
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
}
|
||||
_approve(spender, tokenId);
|
||||
}
|
||||
|
||||
@@ -69,22 +77,24 @@ abstract contract LensNFTBase is ILensNFTBase, ERC721Enumerable {
|
||||
DataTypes.EIP712Signature calldata sig
|
||||
) external override {
|
||||
if (operator == address(0)) revert Errors.ZeroSpender();
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
PERMIT_FOR_ALL_TYPEHASH,
|
||||
owner,
|
||||
operator,
|
||||
approved,
|
||||
sigNonces[owner]++,
|
||||
sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
PERMIT_FOR_ALL_TYPEHASH,
|
||||
owner,
|
||||
operator,
|
||||
approved,
|
||||
sigNonces[owner]++,
|
||||
sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
}
|
||||
_setOperatorApproval(owner, operator, approved);
|
||||
}
|
||||
|
||||
@@ -106,16 +116,22 @@ abstract contract LensNFTBase is ILensNFTBase, ERC721Enumerable {
|
||||
override
|
||||
{
|
||||
address owner = ownerOf(tokenId);
|
||||
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(BURN_WITH_SIG_TYPEHASH, tokenId, sigNonces[owner]++, sig.deadline)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
BURN_WITH_SIG_TYPEHASH,
|
||||
tokenId,
|
||||
sigNonces[owner]++,
|
||||
sig.deadline
|
||||
)
|
||||
)
|
||||
),
|
||||
owner,
|
||||
sig
|
||||
);
|
||||
}
|
||||
_burn(tokenId);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,10 @@ interface ICollectNFT {
|
||||
* upon collection.
|
||||
*
|
||||
* @param to The address to mint the NFT to.
|
||||
*
|
||||
* @return uint256 An interger representing the minted token ID.
|
||||
*/
|
||||
function mint(address to) external;
|
||||
function mint(address to) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Returns the source publication pointer mapped to this collect NFT.
|
||||
|
||||
@@ -30,8 +30,10 @@ interface IFollowNFT {
|
||||
* upon follow.
|
||||
*
|
||||
* @param to The address to mint the NFT to.
|
||||
*
|
||||
* @return uint256 An interger representing the minted token ID.
|
||||
*/
|
||||
function mint(address to) external;
|
||||
function mint(address to) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Delegates the caller's governance power to the given delegatee address.
|
||||
|
||||
@@ -97,7 +97,7 @@ interface ILensHub {
|
||||
* followModule: The follow module to use, can be the zero address.
|
||||
* followModuleData: The follow module initialization data, if any.
|
||||
*/
|
||||
function createProfile(DataTypes.CreateProfileData calldata vars) external;
|
||||
function createProfile(DataTypes.CreateProfileData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Sets the mapping between wallet and its main profile identity.
|
||||
@@ -184,44 +184,55 @@ interface ILensHub {
|
||||
* @notice Publishes a post to a given profile, must be called by the profile owner.
|
||||
*
|
||||
* @param vars A PostData struct containing the needed parameters.
|
||||
*
|
||||
* @return uint256 An integer representing the post's publication ID.
|
||||
*/
|
||||
function post(DataTypes.PostData calldata vars) external;
|
||||
function post(DataTypes.PostData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Publishes a post to a given profile via signature with the specified parameters.
|
||||
*
|
||||
* @param vars A PostWithSigData struct containing the regular parameters and an EIP712Signature struct.
|
||||
*
|
||||
* @return uint256 An integer representing the post's publication ID.
|
||||
*/
|
||||
function postWithSig(DataTypes.PostWithSigData calldata vars) external;
|
||||
function postWithSig(DataTypes.PostWithSigData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Publishes a comment to a given profile, must be called by the profile owner.
|
||||
*
|
||||
* @param vars A CommentData struct containing the needed parameters.
|
||||
*
|
||||
* @return uint256 An integer representing the comment's publication ID.
|
||||
*/
|
||||
function comment(DataTypes.CommentData calldata vars) external;
|
||||
function comment(DataTypes.CommentData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Publishes a comment to a given profile via signature with the specified parameters.
|
||||
*
|
||||
*@param vars A CommentWithSigData struct containing the regular parameters and an EIP712Signature struct.
|
||||
* @param vars A CommentWithSigData struct containing the regular parameters and an EIP712Signature struct.
|
||||
*
|
||||
* @return uint256 An integer representing the comment's publication ID.
|
||||
*/
|
||||
function commentWithSig(DataTypes.CommentWithSigData calldata vars) external;
|
||||
function commentWithSig(DataTypes.CommentWithSigData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Publishes a mirror to a given profile, must be called by the profile owner.
|
||||
*
|
||||
* @param vars A MirrorData struct containing the necessary parameters.
|
||||
*
|
||||
* @return uint256 An integer representing the mirror's publication ID.
|
||||
*/
|
||||
function mirror(DataTypes.MirrorData calldata vars) external;
|
||||
function mirror(DataTypes.MirrorData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Publishes a mirror to a given profile via signature with the specified parameters.
|
||||
*
|
||||
* @param vars A MirrorWithSigData struct containing the regular parameters and an EIP712Signature struct.
|
||||
*
|
||||
* @return uint256 An integer representing the mirror's publication ID.
|
||||
*/
|
||||
function mirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external;
|
||||
function mirrorWithSig(DataTypes.MirrorWithSigData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Follows the given profiles, executing each profile's follow module logic (if any) and minting followNFTs to the caller.
|
||||
@@ -230,16 +241,24 @@ interface ILensHub {
|
||||
*
|
||||
* @param profileIds The token ID array of the profiles to follow.
|
||||
* @param datas The arbitrary data array to pass to the follow module for each profile if needed.
|
||||
*
|
||||
* @return uint256[] An array of integers representing the minted follow NFTs token IDs.
|
||||
*/
|
||||
function follow(uint256[] calldata profileIds, bytes[] calldata datas) external;
|
||||
function follow(uint256[] calldata profileIds, bytes[] calldata datas)
|
||||
external
|
||||
returns (uint256[] memory);
|
||||
|
||||
/**
|
||||
* @notice Follows a given profile via signature with the specified parameters.
|
||||
*
|
||||
* @param vars A FollowWithSigData struct containing the regular parameters as well as the signing follower's address
|
||||
* and an EIP712Signature struct.
|
||||
*
|
||||
* @return uint256[] An array of integers representing the minted follow NFTs token IDs.
|
||||
*/
|
||||
function followWithSig(DataTypes.FollowWithSigData calldata vars) external;
|
||||
function followWithSig(DataTypes.FollowWithSigData calldata vars)
|
||||
external
|
||||
returns (uint256[] memory);
|
||||
|
||||
/**
|
||||
* @notice Collects a given publication, executing collect module logic and minting a collectNFT to the caller.
|
||||
@@ -247,20 +266,24 @@ interface ILensHub {
|
||||
* @param profileId The token ID of the profile that published the publication to collect.
|
||||
* @param pubId The publication to collect's publication ID.
|
||||
* @param data The arbitrary data to pass to the collect module if needed.
|
||||
*
|
||||
* @return uint256 An integer representing the minted token ID.
|
||||
*/
|
||||
function collect(
|
||||
uint256 profileId,
|
||||
uint256 pubId,
|
||||
bytes calldata data
|
||||
) external;
|
||||
) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Collects a given publication via signature with the specified parameters.
|
||||
*
|
||||
* @param vars A CollectWithSigData struct containing the regular parameters as well as the collector's address and
|
||||
* an EIP712Signature struct.
|
||||
*
|
||||
* @return uint256 An integer representing the minted token ID.
|
||||
*/
|
||||
function collectWithSig(DataTypes.CollectWithSigData calldata vars) external;
|
||||
function collectWithSig(DataTypes.CollectWithSigData calldata vars) external returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Helper function to emit a detailed followNFT transfer event from the hub, to be consumed by frontends to track
|
||||
|
||||
@@ -35,6 +35,8 @@ library InteractionLogic {
|
||||
* @param followNFTImpl The address of the follow NFT implementation, which has to be passed because it's an immutable in the hub.
|
||||
* @param _profileById A pointer to the storage mapping of profile structs by profile ID.
|
||||
* @param _profileIdByHandleHash A pointer to the storage mapping of profile IDs by handle hash.
|
||||
*
|
||||
* @return uint256[] An array of integers representing the minted follow NFTs token IDs.
|
||||
*/
|
||||
function follow(
|
||||
address follower,
|
||||
@@ -43,8 +45,9 @@ library InteractionLogic {
|
||||
address followNFTImpl,
|
||||
mapping(uint256 => DataTypes.ProfileStruct) storage _profileById,
|
||||
mapping(bytes32 => uint256) storage _profileIdByHandleHash
|
||||
) external {
|
||||
) external returns (uint256[] memory) {
|
||||
if (profileIds.length != followModuleDatas.length) revert Errors.ArrayMismatch();
|
||||
uint256[] memory tokenIds = new uint256[](profileIds.length);
|
||||
for (uint256 i = 0; i < profileIds.length; ) {
|
||||
string memory handle = _profileById[profileIds[i]].handle;
|
||||
if (_profileIdByHandleHash[keccak256(bytes(handle))] != profileIds[i])
|
||||
@@ -55,23 +58,11 @@ library InteractionLogic {
|
||||
address followNFT = _profileById[profileIds[i]].followNFT;
|
||||
|
||||
if (followNFT == address(0)) {
|
||||
followNFT = Clones.clone(followNFTImpl);
|
||||
followNFT = _deployFollowNFT(profileIds[i], handle, followNFTImpl);
|
||||
_profileById[profileIds[i]].followNFT = followNFT;
|
||||
|
||||
bytes4 firstBytes = bytes4(bytes(handle));
|
||||
|
||||
string memory followNFTName = string(
|
||||
abi.encodePacked(handle, Constants.FOLLOW_NFT_NAME_SUFFIX)
|
||||
);
|
||||
string memory followNFTSymbol = string(
|
||||
abi.encodePacked(firstBytes, Constants.FOLLOW_NFT_SYMBOL_SUFFIX)
|
||||
);
|
||||
|
||||
IFollowNFT(followNFT).initialize(profileIds[i], followNFTName, followNFTSymbol);
|
||||
emit Events.FollowNFTDeployed(profileIds[i], followNFT, block.timestamp);
|
||||
}
|
||||
|
||||
IFollowNFT(followNFT).mint(follower);
|
||||
tokenIds[i] = IFollowNFT(followNFT).mint(follower);
|
||||
|
||||
if (followModule != address(0)) {
|
||||
IFollowModule(followModule).processFollow(
|
||||
@@ -84,6 +75,7 @@ library InteractionLogic {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return tokenIds;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,6 +89,8 @@ library InteractionLogic {
|
||||
* @param collectNFTImpl The address of the collect NFT implementation, which has to be passed because it's an immutable in the hub.
|
||||
* @param _pubByIdByProfile A pointer to the storage mapping of publications by pubId by profile ID.
|
||||
* @param _profileById A pointer to the storage mapping of profile structs by profile ID.
|
||||
*
|
||||
* @return uint256 An integer representing the minted token ID.
|
||||
*/
|
||||
function collect(
|
||||
address collector,
|
||||
@@ -107,41 +101,26 @@ library InteractionLogic {
|
||||
mapping(uint256 => mapping(uint256 => DataTypes.PublicationStruct))
|
||||
storage _pubByIdByProfile,
|
||||
mapping(uint256 => DataTypes.ProfileStruct) storage _profileById
|
||||
) external {
|
||||
) external returns (uint256) {
|
||||
(uint256 rootProfileId, uint256 rootPubId, address rootCollectModule) = Helpers
|
||||
.getPointedIfMirror(profileId, pubId, _pubByIdByProfile);
|
||||
|
||||
address collectNFT = _pubByIdByProfile[rootProfileId][rootPubId].collectNFT;
|
||||
|
||||
if (collectNFT == address(0)) {
|
||||
collectNFT = Clones.clone(collectNFTImpl);
|
||||
_pubByIdByProfile[rootProfileId][rootPubId].collectNFT = collectNFT;
|
||||
|
||||
string memory handle = _profileById[rootProfileId].handle;
|
||||
bytes4 firstBytes = bytes4(bytes(handle));
|
||||
|
||||
string memory collectNFTName = string(
|
||||
abi.encodePacked(handle, Constants.COLLECT_NFT_NAME_INFIX, rootPubId.toString())
|
||||
);
|
||||
string memory collectNFTSymbol = string(
|
||||
abi.encodePacked(
|
||||
firstBytes,
|
||||
Constants.COLLECT_NFT_SYMBOL_INFIX,
|
||||
rootPubId.toString()
|
||||
)
|
||||
);
|
||||
|
||||
ICollectNFT(collectNFT).initialize(
|
||||
rootProfileId,
|
||||
rootPubId,
|
||||
collectNFTName,
|
||||
collectNFTSymbol
|
||||
);
|
||||
emit Events.CollectNFTDeployed(rootProfileId, rootPubId, collectNFT, block.timestamp);
|
||||
uint256 tokenId;
|
||||
// Avoids stack too deep
|
||||
{
|
||||
address collectNFT = _pubByIdByProfile[rootProfileId][rootPubId].collectNFT;
|
||||
if (collectNFT == address(0)) {
|
||||
collectNFT = _deployCollectNFT(
|
||||
rootProfileId,
|
||||
rootPubId,
|
||||
_profileById[rootProfileId].handle,
|
||||
collectNFTImpl
|
||||
);
|
||||
_pubByIdByProfile[rootProfileId][rootPubId].collectNFT = collectNFT;
|
||||
}
|
||||
tokenId = ICollectNFT(collectNFT).mint(collector);
|
||||
}
|
||||
|
||||
ICollectNFT(collectNFT).mint(collector);
|
||||
|
||||
ICollectModule(rootCollectModule).processCollect(
|
||||
profileId,
|
||||
collector,
|
||||
@@ -149,6 +128,93 @@ library InteractionLogic {
|
||||
rootPubId,
|
||||
collectModuleData
|
||||
);
|
||||
_emitCollectedEvent(collector, profileId, pubId, rootProfileId, rootPubId);
|
||||
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploys the given profile's Follow NFT contract.
|
||||
*
|
||||
* @param profileId The token ID of the profile which Follow NFT should be deployed.
|
||||
* @param handle The profile's associated handle.
|
||||
* @param followNFTImpl The address of the Follow NFT implementation that should be used for the deployment.
|
||||
*
|
||||
* @return address The address of the deployed Follow NFT contract.
|
||||
*/
|
||||
function _deployFollowNFT(
|
||||
uint256 profileId,
|
||||
string memory handle,
|
||||
address followNFTImpl
|
||||
) private returns (address) {
|
||||
address followNFT = Clones.clone(followNFTImpl);
|
||||
|
||||
bytes4 firstBytes = bytes4(bytes(handle));
|
||||
|
||||
string memory followNFTName = string(
|
||||
abi.encodePacked(handle, Constants.FOLLOW_NFT_NAME_SUFFIX)
|
||||
);
|
||||
string memory followNFTSymbol = string(
|
||||
abi.encodePacked(firstBytes, Constants.FOLLOW_NFT_SYMBOL_SUFFIX)
|
||||
);
|
||||
|
||||
IFollowNFT(followNFT).initialize(profileId, followNFTName, followNFTSymbol);
|
||||
emit Events.FollowNFTDeployed(profileId, followNFT, block.timestamp);
|
||||
|
||||
return followNFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploys the given profile's Collect NFT contract.
|
||||
*
|
||||
* @param profileId The token ID of the profile which Collect NFT should be deployed.
|
||||
* @param pubId The publication ID of the publication being collected, which Collect NFT should be deployed.
|
||||
* @param handle The profile's associated handle.
|
||||
* @param collectNFTImpl The address of the Collect NFT implementation that should be used for the deployment.
|
||||
*
|
||||
* @return address The address of the deployed Collect NFT contract.
|
||||
*/
|
||||
function _deployCollectNFT(
|
||||
uint256 profileId,
|
||||
uint256 pubId,
|
||||
string memory handle,
|
||||
address collectNFTImpl
|
||||
) private returns (address) {
|
||||
address collectNFT = Clones.clone(collectNFTImpl);
|
||||
|
||||
bytes4 firstBytes = bytes4(bytes(handle));
|
||||
|
||||
string memory collectNFTName = string(
|
||||
abi.encodePacked(handle, Constants.COLLECT_NFT_NAME_INFIX, pubId.toString())
|
||||
);
|
||||
string memory collectNFTSymbol = string(
|
||||
abi.encodePacked(firstBytes, Constants.COLLECT_NFT_SYMBOL_INFIX, pubId.toString())
|
||||
);
|
||||
|
||||
ICollectNFT(collectNFT).initialize(profileId, pubId, collectNFTName, collectNFTSymbol);
|
||||
emit Events.CollectNFTDeployed(profileId, pubId, collectNFT, block.timestamp);
|
||||
|
||||
return collectNFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Emits the `Collected` event that signals that a successful collect action has occurred.
|
||||
*
|
||||
* @dev This is done through this function to prevent stack too deep compilation error.
|
||||
*
|
||||
* @param collector The address collecting the publication.
|
||||
* @param profileId The token ID of the profile that the collect was initiated towards, useful to differentiate mirrors.
|
||||
* @param pubId The publication ID that the collect was initiated towards, useful to differentiate mirrors.
|
||||
* @param rootProfileId The profile token ID of the profile whose publication is being collected.
|
||||
* @param rootPubId The publication ID of the publication being collected.
|
||||
*/
|
||||
function _emitCollectedEvent(
|
||||
address collector,
|
||||
uint256 profileId,
|
||||
uint256 pubId,
|
||||
uint256 rootProfileId,
|
||||
uint256 rootPubId
|
||||
) private {
|
||||
emit Events.Collected(
|
||||
collector,
|
||||
profileId,
|
||||
|
||||
@@ -110,21 +110,24 @@ contract LensPeriphery {
|
||||
* and an EIP712Signature struct.
|
||||
*/
|
||||
function toggleFollowWithSig(DataTypes.ToggleFollowWithSigData calldata vars) external {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
TOGGLE_FOLLOW_WITH_SIG_TYPEHASH,
|
||||
keccak256(abi.encodePacked(vars.profileIds)),
|
||||
keccak256(abi.encodePacked(vars.enables)),
|
||||
sigNonces[vars.follower]++,
|
||||
vars.sig.deadline
|
||||
unchecked {
|
||||
_validateRecoveredAddress(
|
||||
_calculateDigest(
|
||||
keccak256(
|
||||
abi.encode(
|
||||
TOGGLE_FOLLOW_WITH_SIG_TYPEHASH,
|
||||
keccak256(abi.encodePacked(vars.profileIds)),
|
||||
keccak256(abi.encodePacked(vars.enables)),
|
||||
sigNonces[vars.follower]++,
|
||||
vars.sig.deadline
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
vars.follower,
|
||||
vars.sig
|
||||
);
|
||||
),
|
||||
vars.follower,
|
||||
vars.sig
|
||||
);
|
||||
}
|
||||
|
||||
_toggleFollow(vars.follower, vars.profileIds, vars.enables);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import '@nomiclabs/hardhat-ethers';
|
||||
import { BigNumberish, Bytes, logger, utils, BigNumber, Contract } from 'ethers';
|
||||
import { BigNumberish, Bytes, logger, utils, BigNumber, Contract, Signer } from 'ethers';
|
||||
import {
|
||||
eventsLib,
|
||||
helper,
|
||||
@@ -8,15 +8,27 @@ import {
|
||||
lensPeriphery,
|
||||
LENS_PERIPHERY_NAME,
|
||||
testWallet,
|
||||
user,
|
||||
} from '../__setup.spec';
|
||||
import { expect } from 'chai';
|
||||
import { HARDHAT_CHAINID, MAX_UINT256 } from './constants';
|
||||
import { hexlify, keccak256, RLP, toUtf8Bytes } from 'ethers/lib/utils';
|
||||
import { BytesLike, hexlify, keccak256, RLP, toUtf8Bytes } from 'ethers/lib/utils';
|
||||
import { LensHub__factory } from '../../typechain-types';
|
||||
import { TransactionReceipt, TransactionResponse } from '@ethersproject/providers';
|
||||
import hre, { ethers } from 'hardhat';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import {
|
||||
CollectWithSigDataStruct,
|
||||
CommentDataStruct,
|
||||
CommentWithSigDataStruct,
|
||||
CreateProfileDataStruct,
|
||||
FollowWithSigDataStruct,
|
||||
MirrorDataStruct,
|
||||
MirrorWithSigDataStruct,
|
||||
PostDataStruct,
|
||||
PostWithSigDataStruct,
|
||||
} from '../../typechain-types/LensHub';
|
||||
|
||||
export enum ProtocolState {
|
||||
Unpaused,
|
||||
@@ -466,6 +478,151 @@ export async function getCollectWithSigParts(
|
||||
return await getSig(msgParams);
|
||||
}
|
||||
|
||||
export function expectEqualArrays(actual: BigNumberish[], expected: BigNumberish[]) {
|
||||
if (actual.length != expected.length) {
|
||||
logger.throwError(
|
||||
`${actual} length ${actual.length} does not match ${expected} length ${expect.length}`
|
||||
);
|
||||
}
|
||||
|
||||
let areEquals = true;
|
||||
for (let i = 0; areEquals && i < actual.length; i++) {
|
||||
areEquals = BigNumber.from(actual[i]).eq(BigNumber.from(expected[i]));
|
||||
}
|
||||
|
||||
if (!areEquals) {
|
||||
logger.throwError(`${actual} does not match ${expected}`);
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateProfileReturningTokenIdStruct {
|
||||
sender?: Signer;
|
||||
vars: CreateProfileDataStruct;
|
||||
}
|
||||
|
||||
export async function createProfileReturningTokenId({
|
||||
sender = user,
|
||||
vars,
|
||||
}: CreateProfileReturningTokenIdStruct): Promise<BigNumber> {
|
||||
const tokenId = await lensHub.connect(sender).callStatic.createProfile(vars);
|
||||
await expect(lensHub.connect(sender).createProfile(vars)).to.not.be.reverted;
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
export interface FollowDataStruct {
|
||||
profileIds: BigNumberish[];
|
||||
datas: BytesLike[];
|
||||
}
|
||||
|
||||
export interface FollowReturningTokenIdsStruct {
|
||||
sender?: Signer;
|
||||
vars: FollowDataStruct | FollowWithSigDataStruct;
|
||||
}
|
||||
|
||||
export async function followReturningTokenIds({
|
||||
sender = user,
|
||||
vars,
|
||||
}: FollowReturningTokenIdsStruct): Promise<BigNumber[]> {
|
||||
let tokenIds;
|
||||
if ('sig' in vars) {
|
||||
tokenIds = await lensHub.connect(sender).callStatic.followWithSig(vars);
|
||||
await expect(lensHub.connect(sender).followWithSig(vars)).to.not.be.reverted;
|
||||
} else {
|
||||
tokenIds = await lensHub.connect(sender).callStatic.follow(vars.profileIds, vars.datas);
|
||||
await expect(lensHub.connect(sender).follow(vars.profileIds, vars.datas)).to.not.be.reverted;
|
||||
}
|
||||
return tokenIds;
|
||||
}
|
||||
|
||||
export interface CollectDataStruct {
|
||||
profileId: BigNumberish;
|
||||
pubId: BigNumberish;
|
||||
data: BytesLike;
|
||||
}
|
||||
|
||||
export interface CollectReturningTokenIdsStruct {
|
||||
sender?: Signer;
|
||||
vars: CollectDataStruct | CollectWithSigDataStruct;
|
||||
}
|
||||
|
||||
export async function collectReturningTokenIds({
|
||||
sender = user,
|
||||
vars,
|
||||
}: CollectReturningTokenIdsStruct): Promise<BigNumber> {
|
||||
let tokenId;
|
||||
if ('sig' in vars) {
|
||||
tokenId = await lensHub.connect(sender).callStatic.collectWithSig(vars);
|
||||
await expect(lensHub.connect(sender).collectWithSig(vars)).to.not.be.reverted;
|
||||
} else {
|
||||
tokenId = await lensHub
|
||||
.connect(sender)
|
||||
.callStatic.collect(vars.profileId, vars.pubId, vars.data);
|
||||
await expect(lensHub.connect(sender).collect(vars.profileId, vars.pubId, vars.data)).to.not.be
|
||||
.reverted;
|
||||
}
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
export interface CommentReturningTokenIdStruct {
|
||||
sender?: Signer;
|
||||
vars: CommentDataStruct | CommentWithSigDataStruct;
|
||||
}
|
||||
|
||||
export async function commentReturningTokenId({
|
||||
sender = user,
|
||||
vars,
|
||||
}: CommentReturningTokenIdStruct): Promise<BigNumber> {
|
||||
let tokenId;
|
||||
if ('sig' in vars) {
|
||||
tokenId = await lensHub.connect(sender).callStatic.commentWithSig(vars);
|
||||
await expect(lensHub.connect(sender).commentWithSig(vars)).to.not.be.reverted;
|
||||
} else {
|
||||
tokenId = await lensHub.connect(sender).callStatic.comment(vars);
|
||||
await expect(lensHub.connect(sender).comment(vars)).to.not.be.reverted;
|
||||
}
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
export interface MirrorReturningTokenIdStruct {
|
||||
sender?: Signer;
|
||||
vars: MirrorDataStruct | MirrorWithSigDataStruct;
|
||||
}
|
||||
|
||||
export async function mirrorReturningTokenId({
|
||||
sender = user,
|
||||
vars,
|
||||
}: MirrorReturningTokenIdStruct): Promise<BigNumber> {
|
||||
let tokenId;
|
||||
if ('sig' in vars) {
|
||||
tokenId = await lensHub.connect(sender).callStatic.mirrorWithSig(vars);
|
||||
await expect(lensHub.connect(sender).mirrorWithSig(vars)).to.not.be.reverted;
|
||||
} else {
|
||||
tokenId = await lensHub.connect(sender).callStatic.mirror(vars);
|
||||
await expect(lensHub.connect(sender).mirror(vars)).to.not.be.reverted;
|
||||
}
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
export interface PostReturningTokenIdStruct {
|
||||
sender?: Signer;
|
||||
vars: PostDataStruct | PostWithSigDataStruct;
|
||||
}
|
||||
|
||||
export async function postReturningTokenId({
|
||||
sender = user,
|
||||
vars,
|
||||
}: PostReturningTokenIdStruct): Promise<BigNumber> {
|
||||
let tokenId;
|
||||
if ('sig' in vars) {
|
||||
tokenId = await lensHub.connect(sender).callStatic.postWithSig(vars);
|
||||
await expect(lensHub.connect(sender).postWithSig(vars)).to.not.be.reverted;
|
||||
} else {
|
||||
tokenId = await lensHub.connect(sender).callStatic.post(vars);
|
||||
await expect(lensHub.connect(sender).post(vars)).to.not.be.reverted;
|
||||
}
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
export interface TokenUriMetadataAttribute {
|
||||
trait_type: string;
|
||||
value: string;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import {
|
||||
cancelWithPermitForAll,
|
||||
collectReturningTokenIds,
|
||||
getAbbreviation,
|
||||
getCollectWithSigParts,
|
||||
getTimestamp,
|
||||
@@ -95,6 +96,69 @@ makeSuiteCleanRoom('Collecting', function () {
|
||||
await expect(lensHub.collect(FIRST_PROFILE_ID, 1, [])).to.not.be.reverted;
|
||||
});
|
||||
|
||||
it('Should return the expected token IDs when collecting publications', async function () {
|
||||
await expect(lensHub.connect(userTwo).follow([FIRST_PROFILE_ID], [[]])).to.not.be.reverted;
|
||||
await expect(
|
||||
lensHub.connect(testWallet).follow([FIRST_PROFILE_ID], [[]])
|
||||
).to.not.be.reverted;
|
||||
|
||||
expect(
|
||||
await collectReturningTokenIds({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
pubId: 1,
|
||||
data: [],
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await collectReturningTokenIds({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
pubId: 1,
|
||||
data: [],
|
||||
},
|
||||
})
|
||||
).to.eq(2);
|
||||
|
||||
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
|
||||
const { v, r, s } = await getCollectWithSigParts(
|
||||
FIRST_PROFILE_ID,
|
||||
'1',
|
||||
[],
|
||||
nonce,
|
||||
MAX_UINT256
|
||||
);
|
||||
expect(
|
||||
await collectReturningTokenIds({
|
||||
vars: {
|
||||
collector: testWallet.address,
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
pubId: '1',
|
||||
data: [],
|
||||
sig: {
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
deadline: MAX_UINT256,
|
||||
},
|
||||
},
|
||||
})
|
||||
).to.eq(3);
|
||||
|
||||
expect(
|
||||
await collectReturningTokenIds({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
pubId: 1,
|
||||
data: [],
|
||||
},
|
||||
})
|
||||
).to.eq(4);
|
||||
});
|
||||
|
||||
it('UserTwo should follow, then collect, receive a collect NFT with the expected properties', async function () {
|
||||
await expect(lensHub.connect(userTwo).follow([FIRST_PROFILE_ID], [[]])).to.not.be.reverted;
|
||||
await expect(lensHub.connect(userTwo).collect(FIRST_PROFILE_ID, 1, [])).to.not.be.reverted;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import '@nomiclabs/hardhat-ethers';
|
||||
import { expect } from 'chai';
|
||||
import { BigNumber } from 'ethers';
|
||||
import { FollowNFT__factory } from '../../../typechain-types';
|
||||
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import {
|
||||
cancelWithPermitForAll,
|
||||
expectEqualArrays,
|
||||
followReturningTokenIds,
|
||||
getAbbreviation,
|
||||
getFollowWithSigParts,
|
||||
getTimestamp,
|
||||
@@ -96,7 +99,11 @@ makeSuiteCleanRoom('Following', function () {
|
||||
});
|
||||
|
||||
it('UserTwo should follow profile 1 3 times in the same call, receive IDs 1,2 and 3', async function () {
|
||||
await expect(lensHub.connect(userTwo).follow([FIRST_PROFILE_ID, FIRST_PROFILE_ID, FIRST_PROFILE_ID], [[], [], []])).to.not.be.reverted;
|
||||
await expect(
|
||||
lensHub
|
||||
.connect(userTwo)
|
||||
.follow([FIRST_PROFILE_ID, FIRST_PROFILE_ID, FIRST_PROFILE_ID], [[], [], []])
|
||||
).to.not.be.reverted;
|
||||
const followNFTAddress = await lensHub.getFollowNFT(FIRST_PROFILE_ID);
|
||||
const followNFT = FollowNFT__factory.connect(followNFTAddress, user);
|
||||
const idOne = await followNFT.tokenOfOwnerByIndex(userTwoAddress, 0);
|
||||
@@ -106,6 +113,63 @@ makeSuiteCleanRoom('Following', function () {
|
||||
expect(idTwo).to.eq(2);
|
||||
expect(idThree).to.eq(3);
|
||||
});
|
||||
|
||||
it('Should return the expected token IDs when following profiles', async function () {
|
||||
expectEqualArrays(
|
||||
await followReturningTokenIds({
|
||||
vars: {
|
||||
profileIds: [FIRST_PROFILE_ID, FIRST_PROFILE_ID],
|
||||
datas: [[], []],
|
||||
},
|
||||
}),
|
||||
[1, 2]
|
||||
);
|
||||
|
||||
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
|
||||
const { v, r, s } = await getFollowWithSigParts(
|
||||
[FIRST_PROFILE_ID],
|
||||
[[]],
|
||||
nonce,
|
||||
MAX_UINT256
|
||||
);
|
||||
expectEqualArrays(
|
||||
await followReturningTokenIds({
|
||||
vars: {
|
||||
follower: testWallet.address,
|
||||
profileIds: [FIRST_PROFILE_ID],
|
||||
datas: [[]],
|
||||
sig: {
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
deadline: MAX_UINT256,
|
||||
},
|
||||
},
|
||||
}),
|
||||
[3]
|
||||
);
|
||||
|
||||
expectEqualArrays(
|
||||
await followReturningTokenIds({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
profileIds: [FIRST_PROFILE_ID],
|
||||
datas: [[]],
|
||||
},
|
||||
}),
|
||||
[4]
|
||||
);
|
||||
|
||||
expectEqualArrays(
|
||||
await followReturningTokenIds({
|
||||
vars: {
|
||||
profileIds: [FIRST_PROFILE_ID],
|
||||
datas: [[]],
|
||||
},
|
||||
}),
|
||||
[5]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@ import '@nomiclabs/hardhat-ethers';
|
||||
import { expect } from 'chai';
|
||||
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import { cancelWithPermitForAll, getCommentWithSigParts } from '../../helpers/utils';
|
||||
import {
|
||||
cancelWithPermitForAll,
|
||||
commentReturningTokenId,
|
||||
getCommentWithSigParts,
|
||||
} from '../../helpers/utils';
|
||||
import {
|
||||
abiCoder,
|
||||
freeCollectModule,
|
||||
@@ -20,6 +24,7 @@ import {
|
||||
timedFeeCollectModule,
|
||||
userAddress,
|
||||
userTwo,
|
||||
userTwoAddress,
|
||||
} from '../../__setup.spec';
|
||||
|
||||
makeSuiteCleanRoom('Publishing Comments', function () {
|
||||
@@ -191,6 +196,112 @@ makeSuiteCleanRoom('Publishing Comments', function () {
|
||||
expect(pub.referenceModule).to.eq(ZERO_ADDRESS);
|
||||
});
|
||||
|
||||
it('Should return the expected token IDs when commenting publications', async function () {
|
||||
await expect(
|
||||
lensHub.connect(testWallet).createProfile({
|
||||
to: testWallet.address,
|
||||
handle: 'testwallet',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
await expect(
|
||||
lensHub.connect(testWallet).createProfile({
|
||||
to: userTwoAddress,
|
||||
handle: 'usertwo',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
|
||||
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
|
||||
const collectModuleData = abiCoder.encode(['bool'], [true]);
|
||||
const referenceModuleData = [];
|
||||
const { v, r, s } = await getCommentWithSigParts(
|
||||
FIRST_PROFILE_ID + 1,
|
||||
OTHER_MOCK_URI,
|
||||
FIRST_PROFILE_ID,
|
||||
'1',
|
||||
freeCollectModule.address,
|
||||
collectModuleData,
|
||||
ZERO_ADDRESS,
|
||||
referenceModuleData,
|
||||
nonce,
|
||||
MAX_UINT256
|
||||
);
|
||||
expect(
|
||||
await commentReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 1,
|
||||
contentURI: OTHER_MOCK_URI,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: '1',
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: collectModuleData,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
sig: {
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
deadline: MAX_UINT256,
|
||||
},
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await commentReturningTokenId({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 2,
|
||||
contentURI: MOCK_URI,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: 1,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: collectModuleData,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await commentReturningTokenId({
|
||||
sender: testWallet,
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 1,
|
||||
contentURI: MOCK_URI,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: 1,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: collectModuleData,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
},
|
||||
})
|
||||
).to.eq(2);
|
||||
|
||||
expect(
|
||||
await commentReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
contentURI: MOCK_URI,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: 1,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: collectModuleData,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
},
|
||||
})
|
||||
).to.eq(2);
|
||||
});
|
||||
|
||||
it('User should create a post using the mock reference module as reference module, then comment on that post', async function () {
|
||||
const data = abiCoder.encode(['uint256'], ['1']);
|
||||
await expect(
|
||||
|
||||
@@ -2,7 +2,11 @@ import '@nomiclabs/hardhat-ethers';
|
||||
import { expect } from 'chai';
|
||||
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import { cancelWithPermitForAll, getMirrorWithSigParts } from '../../helpers/utils';
|
||||
import {
|
||||
cancelWithPermitForAll,
|
||||
getMirrorWithSigParts,
|
||||
mirrorReturningTokenId,
|
||||
} from '../../helpers/utils';
|
||||
import {
|
||||
abiCoder,
|
||||
freeCollectModule,
|
||||
@@ -18,6 +22,7 @@ import {
|
||||
testWallet,
|
||||
userAddress,
|
||||
userTwo,
|
||||
userTwoAddress,
|
||||
} from '../../__setup.spec';
|
||||
|
||||
makeSuiteCleanRoom('Publishing mirrors', function () {
|
||||
@@ -105,6 +110,95 @@ makeSuiteCleanRoom('Publishing mirrors', function () {
|
||||
});
|
||||
|
||||
context('Scenarios', function () {
|
||||
it('Should return the expected token IDs when mirroring publications', async function () {
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
to: testWallet.address,
|
||||
handle: 'testwallet',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
to: userTwoAddress,
|
||||
handle: 'usertwo',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
|
||||
expect(
|
||||
await mirrorReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: 1,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(2);
|
||||
|
||||
expect(
|
||||
await mirrorReturningTokenId({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 2,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: 2,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
|
||||
const referenceModuleData = [];
|
||||
const { v, r, s } = await getMirrorWithSigParts(
|
||||
FIRST_PROFILE_ID + 1,
|
||||
FIRST_PROFILE_ID,
|
||||
'1',
|
||||
ZERO_ADDRESS,
|
||||
referenceModuleData,
|
||||
nonce,
|
||||
MAX_UINT256
|
||||
);
|
||||
expect(
|
||||
await mirrorReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 1,
|
||||
profileIdPointed: FIRST_PROFILE_ID,
|
||||
pubIdPointed: '1',
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
sig: {
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
deadline: MAX_UINT256,
|
||||
},
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await mirrorReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
profileIdPointed: FIRST_PROFILE_ID + 1,
|
||||
pubIdPointed: 1,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(3);
|
||||
});
|
||||
|
||||
it('User should create a mirror with empty reference module and reference module data, fetched mirror data should be accurate', async function () {
|
||||
await expect(
|
||||
lensHub.mirror({
|
||||
|
||||
@@ -2,7 +2,11 @@ import '@nomiclabs/hardhat-ethers';
|
||||
import { expect } from 'chai';
|
||||
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import { cancelWithPermitForAll, getPostWithSigParts } from '../../helpers/utils';
|
||||
import {
|
||||
cancelWithPermitForAll,
|
||||
getPostWithSigParts,
|
||||
postReturningTokenId,
|
||||
} from '../../helpers/utils';
|
||||
import {
|
||||
freeCollectModule,
|
||||
FIRST_PROFILE_ID,
|
||||
@@ -20,6 +24,7 @@ import {
|
||||
userAddress,
|
||||
userTwo,
|
||||
abiCoder,
|
||||
userTwoAddress,
|
||||
} from '../../__setup.spec';
|
||||
|
||||
makeSuiteCleanRoom('Publishing Posts', function () {
|
||||
@@ -121,6 +126,105 @@ makeSuiteCleanRoom('Publishing Posts', function () {
|
||||
});
|
||||
|
||||
context('Scenarios', function () {
|
||||
it('Should return the expected token IDs when mirroring publications', async function () {
|
||||
await expect(
|
||||
lensHub.connect(governance).whitelistCollectModule(freeCollectModule.address, true)
|
||||
).to.not.be.reverted;
|
||||
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
to: testWallet.address,
|
||||
handle: 'testwallet',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
to: userTwoAddress,
|
||||
handle: 'usertwo',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
|
||||
expect(
|
||||
await postReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
contentURI: MOCK_URI,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: abiCoder.encode(['bool'], [true]),
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await postReturningTokenId({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 2,
|
||||
contentURI: MOCK_URI,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: abiCoder.encode(['bool'], [true]),
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
const nonce = (await lensHub.sigNonces(testWallet.address)).toNumber();
|
||||
const collectModuleData = abiCoder.encode(['bool'], [true]);
|
||||
const referenceModuleData = [];
|
||||
const { v, r, s } = await getPostWithSigParts(
|
||||
FIRST_PROFILE_ID + 1,
|
||||
MOCK_URI,
|
||||
freeCollectModule.address,
|
||||
collectModuleData,
|
||||
ZERO_ADDRESS,
|
||||
referenceModuleData,
|
||||
nonce,
|
||||
MAX_UINT256
|
||||
);
|
||||
expect(
|
||||
await postReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID + 1,
|
||||
contentURI: MOCK_URI,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: collectModuleData,
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: referenceModuleData,
|
||||
sig: {
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
deadline: MAX_UINT256,
|
||||
},
|
||||
},
|
||||
})
|
||||
).to.eq(1);
|
||||
|
||||
expect(
|
||||
await postReturningTokenId({
|
||||
vars: {
|
||||
profileId: FIRST_PROFILE_ID,
|
||||
contentURI: MOCK_URI,
|
||||
collectModule: freeCollectModule.address,
|
||||
collectModuleData: abiCoder.encode(['bool'], [true]),
|
||||
referenceModule: ZERO_ADDRESS,
|
||||
referenceModuleData: [],
|
||||
},
|
||||
})
|
||||
).to.eq(2);
|
||||
});
|
||||
|
||||
it('User should create a post with empty collect and reference module data, fetched post data should be accurate', async function () {
|
||||
await expect(
|
||||
lensHub.connect(governance).whitelistCollectModule(freeCollectModule.address, true)
|
||||
|
||||
@@ -2,9 +2,9 @@ import '@nomiclabs/hardhat-ethers';
|
||||
import { expect } from 'chai';
|
||||
import { BigNumber } from 'ethers';
|
||||
import { TokenDataStructOutput } from '../../../typechain-types/LensHub';
|
||||
import { MAX_UINT256, ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ZERO_ADDRESS } from '../../helpers/constants';
|
||||
import { ERRORS } from '../../helpers/errors';
|
||||
import { cancelWithPermitForAll, getTimestamp } from '../../helpers/utils';
|
||||
import { createProfileReturningTokenId, getTimestamp, waitForTx } from '../../helpers/utils';
|
||||
import {
|
||||
FIRST_PROFILE_ID,
|
||||
governance,
|
||||
@@ -134,16 +134,18 @@ makeSuiteCleanRoom('Profile Creation', function () {
|
||||
let mintTimestamp: BigNumber;
|
||||
let tokenData: TokenDataStructOutput;
|
||||
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
to: userAddress,
|
||||
handle: MOCK_PROFILE_HANDLE,
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
expect(
|
||||
await createProfileReturningTokenId({
|
||||
vars: {
|
||||
to: userAddress,
|
||||
handle: MOCK_PROFILE_HANDLE,
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
},
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
).to.eq(FIRST_PROFILE_ID);
|
||||
|
||||
timestamp = await getTimestamp();
|
||||
owner = await lensHub.ownerOf(FIRST_PROFILE_ID);
|
||||
@@ -159,21 +161,25 @@ makeSuiteCleanRoom('Profile Creation', function () {
|
||||
expect(tokenData.mintTimestamp).to.eq(timestamp);
|
||||
|
||||
const secondProfileId = FIRST_PROFILE_ID + 1;
|
||||
await expect(
|
||||
lensHub.connect(userTwo).createProfile({
|
||||
to: userTwoAddress,
|
||||
handle: 'test',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
const secondProfileHandle = '2nd_profile';
|
||||
expect(
|
||||
await createProfileReturningTokenId({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
to: userTwoAddress,
|
||||
handle: secondProfileHandle,
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
},
|
||||
})
|
||||
).to.not.be.reverted;
|
||||
).to.eq(secondProfileId);
|
||||
|
||||
timestamp = await getTimestamp();
|
||||
owner = await lensHub.ownerOf(secondProfileId);
|
||||
totalSupply = await lensHub.totalSupply();
|
||||
profileId = await lensHub.getProfileIdByHandle('test');
|
||||
profileId = await lensHub.getProfileIdByHandle(secondProfileHandle);
|
||||
mintTimestamp = await lensHub.mintTimestampOf(secondProfileId);
|
||||
tokenData = await lensHub.tokenDataOf(secondProfileId);
|
||||
expect(owner).to.eq(userTwoAddress);
|
||||
@@ -184,6 +190,50 @@ makeSuiteCleanRoom('Profile Creation', function () {
|
||||
expect(tokenData.mintTimestamp).to.eq(timestamp);
|
||||
});
|
||||
|
||||
it('Should return the expected token IDs when creating profiles', async function () {
|
||||
expect(
|
||||
await createProfileReturningTokenId({
|
||||
vars: {
|
||||
to: userAddress,
|
||||
handle: 'token.id_1',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
},
|
||||
})
|
||||
).to.eq(FIRST_PROFILE_ID);
|
||||
|
||||
const secondProfileId = FIRST_PROFILE_ID + 1;
|
||||
expect(
|
||||
await createProfileReturningTokenId({
|
||||
sender: userTwo,
|
||||
vars: {
|
||||
to: userTwoAddress,
|
||||
handle: 'token.id_2',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
},
|
||||
})
|
||||
).to.eq(secondProfileId);
|
||||
|
||||
const thirdProfileId = secondProfileId + 1;
|
||||
expect(
|
||||
await createProfileReturningTokenId({
|
||||
vars: {
|
||||
to: userAddress,
|
||||
handle: 'token.id_3',
|
||||
imageURI: MOCK_PROFILE_URI,
|
||||
followModule: ZERO_ADDRESS,
|
||||
followModuleData: [],
|
||||
followNFTURI: MOCK_FOLLOW_NFT_URI,
|
||||
},
|
||||
})
|
||||
).to.eq(thirdProfileId);
|
||||
});
|
||||
|
||||
it('User should be able to create a profile with a handle including "-" and "_" characters', async function () {
|
||||
await expect(
|
||||
lensHub.createProfile({
|
||||
|
||||
Reference in New Issue
Block a user