-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathFollowLib.sol
142 lines (121 loc) · 5 KB
/
FollowLib.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import {IFollowModule} from 'contracts/interfaces/IFollowModule.sol';
import {ValidationLib} from 'contracts/libraries/ValidationLib.sol';
import {Types} from 'contracts/libraries/constants/Types.sol';
import {Errors} from 'contracts/libraries/constants/Errors.sol';
import {Events} from 'contracts/libraries/constants/Events.sol';
import {StorageLib} from 'contracts/libraries/StorageLib.sol';
import {IFollowNFT} from 'contracts/interfaces/IFollowNFT.sol';
import {FollowNFTProxy} from 'contracts/base/upgradeability/FollowNFTProxy.sol';
library FollowLib {
function follow(
uint256 followerProfileId,
address transactionExecutor,
uint256[] calldata idsOfProfilesToFollow,
uint256[] calldata followTokenIds,
bytes[] calldata followModuleDatas
) external returns (uint256[] memory) {
if (
idsOfProfilesToFollow.length != followTokenIds.length ||
idsOfProfilesToFollow.length != followModuleDatas.length
) {
revert Errors.ArrayMismatch();
}
uint256[] memory followTokenIdsAssigned = new uint256[](idsOfProfilesToFollow.length);
uint256 i;
while (i < idsOfProfilesToFollow.length) {
ValidationLib.validateProfileExists({profileId: idsOfProfilesToFollow[i]});
ValidationLib.validateNotBlocked({profile: followerProfileId, byProfile: idsOfProfilesToFollow[i]});
if (followerProfileId == idsOfProfilesToFollow[i]) {
revert Errors.SelfFollow();
}
followTokenIdsAssigned[i] = _follow({
followerProfileId: followerProfileId,
transactionExecutor: transactionExecutor,
idOfProfileToFollow: idsOfProfilesToFollow[i],
followTokenId: followTokenIds[i],
followModuleData: followModuleDatas[i]
});
unchecked {
++i;
}
}
return followTokenIdsAssigned;
}
function unfollow(
uint256 unfollowerProfileId,
address transactionExecutor,
uint256[] calldata idsOfProfilesToUnfollow
) external {
uint256 i;
while (i < idsOfProfilesToUnfollow.length) {
uint256 idOfProfileToUnfollow = idsOfProfilesToUnfollow[i];
ValidationLib.validateProfileExists(idOfProfileToUnfollow);
address followNFT = StorageLib.getProfile(idOfProfileToUnfollow).followNFT;
if (followNFT == address(0)) {
revert Errors.NotFollowing();
}
IFollowNFT(followNFT).unfollow({
unfollowerProfileId: unfollowerProfileId,
transactionExecutor: transactionExecutor
});
emit Events.Unfollowed(unfollowerProfileId, idOfProfileToUnfollow, block.timestamp);
unchecked {
++i;
}
}
}
/**
* @notice Deploys the given profile's Follow NFT contract.
*
* @param profileId The token ID of the profile which Follow NFT should be deployed.
*
* @return address The address of the deployed Follow NFT contract.
*/
function _deployFollowNFT(uint256 profileId) private returns (address) {
bytes memory functionData = abi.encodeWithSelector(IFollowNFT.initialize.selector, profileId);
address followNFT = address(new FollowNFTProxy(functionData));
emit Events.FollowNFTDeployed(profileId, followNFT, block.timestamp);
return followNFT;
}
function _follow(
uint256 followerProfileId,
address transactionExecutor,
uint256 idOfProfileToFollow,
uint256 followTokenId,
bytes calldata followModuleData
) private returns (uint256) {
Types.Profile storage _profileToFollow = StorageLib.getProfile(idOfProfileToFollow);
address followNFT = _profileToFollow.followNFT;
if (followNFT == address(0)) {
followNFT = _deployFollowNFT(idOfProfileToFollow);
_profileToFollow.followNFT = followNFT;
}
uint256 followTokenIdAssigned = IFollowNFT(followNFT).follow({
followerProfileId: followerProfileId,
transactionExecutor: transactionExecutor,
followTokenId: followTokenId
});
bytes memory processFollowModuleReturnData;
address followModule = _profileToFollow.followModule;
if (followModule != address(0)) {
processFollowModuleReturnData = IFollowModule(followModule).processFollow(
followerProfileId,
followTokenId,
transactionExecutor,
idOfProfileToFollow,
followModuleData
);
}
emit Events.Followed(
followerProfileId,
idOfProfileToFollow,
followTokenIdAssigned,
followModuleData,
processFollowModuleReturnData,
block.timestamp
);
return followTokenIdAssigned;
}
}