@lukso/lsp26-contracts 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,164 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.17;
3
+
4
+ // interfaces
5
+ import {ILSP26FollowerSystem} from "./ILSP26FollowerSystem.sol";
6
+ import {
7
+ ILSP1UniversalReceiver
8
+ } from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";
9
+
10
+ // libraries
11
+ import {
12
+ EnumerableSet
13
+ } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
14
+ import {
15
+ ERC165Checker
16
+ } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
17
+
18
+ // constants
19
+ import {
20
+ _TYPEID_LSP26_FOLLOW,
21
+ _TYPEID_LSP26_UNFOLLOW
22
+ } from "./LSP26Constants.sol";
23
+ import {
24
+ _INTERFACEID_LSP1
25
+ } from "@lukso/lsp1-contracts/contracts/LSP1Constants.sol";
26
+
27
+ // errors
28
+ import {
29
+ LSP26CannotSelfFollow,
30
+ LSP26AlreadyFollowing,
31
+ LSP26NotFollowing
32
+ } from "./LSP26Errors.sol";
33
+
34
+ contract LSP26FollowerSystem is ILSP26FollowerSystem {
35
+ using EnumerableSet for EnumerableSet.AddressSet;
36
+ using ERC165Checker for address;
37
+
38
+ mapping(address => EnumerableSet.AddressSet) private _followersOf;
39
+ mapping(address => EnumerableSet.AddressSet) private _followingsOf;
40
+
41
+ // @inheritdoc ILSP26FollowerSystem
42
+ function follow(address addr) public {
43
+ _follow(addr);
44
+ }
45
+
46
+ // @inheritdoc ILSP26FollowerSystem
47
+ function followBatch(address[] memory addresses) public {
48
+ for (uint256 index = 0; index < addresses.length; ++index) {
49
+ _follow(addresses[index]);
50
+ }
51
+ }
52
+
53
+ // @inheritdoc ILSP26FollowerSystem
54
+ function unfollow(address addr) public {
55
+ _unfollow(addr);
56
+ }
57
+
58
+ // @inheritdoc ILSP26FollowerSystem
59
+ function unfollowBatch(address[] memory addresses) public {
60
+ for (uint256 index = 0; index < addresses.length; ++index) {
61
+ _unfollow(addresses[index]);
62
+ }
63
+ }
64
+
65
+ // @inheritdoc ILSP26FollowerSystem
66
+ function isFollowing(
67
+ address follower,
68
+ address addr
69
+ ) public view returns (bool) {
70
+ return _followingsOf[follower].contains(addr);
71
+ }
72
+
73
+ // @inheritdoc ILSP26FollowerSystem
74
+ function followerCount(address addr) public view returns (uint256) {
75
+ return _followersOf[addr].length();
76
+ }
77
+
78
+ // @inheritdoc ILSP26FollowerSystem
79
+ function followingCount(address addr) public view returns (uint256) {
80
+ return _followingsOf[addr].length();
81
+ }
82
+
83
+ // @inheritdoc ILSP26FollowerSystem
84
+ function getFollowsByIndex(
85
+ address addr,
86
+ uint256 startIndex,
87
+ uint256 endIndex
88
+ ) public view returns (address[] memory) {
89
+ uint256 sliceLength = endIndex - startIndex;
90
+
91
+ address[] memory followings = new address[](sliceLength);
92
+
93
+ for (uint256 index = 0; index < sliceLength; ++index) {
94
+ followings[index] = _followingsOf[addr].at(startIndex + index);
95
+ }
96
+
97
+ return followings;
98
+ }
99
+
100
+ // @inheritdoc ILSP26FollowerSystem
101
+ function getFollowersByIndex(
102
+ address addr,
103
+ uint256 startIndex,
104
+ uint256 endIndex
105
+ ) public view returns (address[] memory) {
106
+ uint256 sliceLength = endIndex - startIndex;
107
+
108
+ address[] memory followers = new address[](sliceLength);
109
+
110
+ for (uint256 index = 0; index < sliceLength; ++index) {
111
+ followers[index] = _followersOf[addr].at(startIndex + index);
112
+ }
113
+
114
+ return followers;
115
+ }
116
+
117
+ function _follow(address addr) internal {
118
+ if (msg.sender == addr) {
119
+ revert LSP26CannotSelfFollow();
120
+ }
121
+
122
+ bool isAdded = _followingsOf[msg.sender].add(addr);
123
+
124
+ if (!isAdded) {
125
+ revert LSP26AlreadyFollowing(addr);
126
+ }
127
+
128
+ _followersOf[addr].add(msg.sender);
129
+
130
+ emit Follow(msg.sender, addr);
131
+
132
+ if (addr.supportsERC165InterfaceUnchecked(_INTERFACEID_LSP1)) {
133
+ // solhint-disable no-empty-blocks
134
+ try
135
+ ILSP1UniversalReceiver(addr).universalReceiver(
136
+ _TYPEID_LSP26_FOLLOW,
137
+ abi.encodePacked(msg.sender)
138
+ )
139
+ {} catch {}
140
+ }
141
+ }
142
+
143
+ function _unfollow(address addr) internal {
144
+ bool isRemoved = _followingsOf[msg.sender].remove(addr);
145
+
146
+ if (!isRemoved) {
147
+ revert LSP26NotFollowing(addr);
148
+ }
149
+
150
+ _followersOf[addr].remove(msg.sender);
151
+
152
+ emit Unfollow(msg.sender, addr);
153
+
154
+ if (addr.supportsERC165InterfaceUnchecked(_INTERFACEID_LSP1)) {
155
+ // solhint-disable no-empty-blocks
156
+ try
157
+ ILSP1UniversalReceiver(addr).universalReceiver(
158
+ _TYPEID_LSP26_UNFOLLOW,
159
+ abi.encodePacked(msg.sender)
160
+ )
161
+ {} catch {}
162
+ }
163
+ }
164
+ }
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.17;
3
+
4
+ // interfaces
5
+ import {
6
+ ILSP1UniversalReceiver
7
+ } from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";
8
+
9
+ contract InfiniteLoopURD is ILSP1UniversalReceiver {
10
+ uint256 public counter;
11
+
12
+ function supportsInterface(bytes4) external pure returns (bool) {
13
+ return true;
14
+ }
15
+
16
+ function universalReceiver(
17
+ bytes32,
18
+ bytes memory
19
+ ) external payable returns (bytes memory) {
20
+ while (true) {
21
+ ++counter;
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.17;
3
+
4
+ // interfaces
5
+ import {
6
+ ILSP1UniversalReceiver
7
+ } from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";
8
+
9
+ contract ReturnBomb is ILSP1UniversalReceiver {
10
+ uint256 public counter;
11
+
12
+ function supportsInterface(bytes4) external pure returns (bool) {
13
+ return true;
14
+ }
15
+
16
+ function universalReceiver(
17
+ bytes32,
18
+ bytes memory
19
+ ) external payable returns (bytes memory) {
20
+ ++counter;
21
+ // solhint-disable-next-line no-inline-assembly
22
+ assembly {
23
+ revert(0, 10000)
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.17;
3
+
4
+ // interfaces
5
+ import {
6
+ ILSP1UniversalReceiver
7
+ } from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";
8
+
9
+ contract RevertOnFollow is ILSP1UniversalReceiver {
10
+ function supportsInterface(bytes4) external pure returns (bool) {
11
+ return true;
12
+ }
13
+
14
+ function universalReceiver(
15
+ bytes32,
16
+ bytes memory
17
+ ) external payable returns (bytes memory) {
18
+ revert("Block LSP1 notifications");
19
+ }
20
+ }
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.17;
3
+
4
+ // interfaces
5
+ import {
6
+ ILSP1UniversalReceiver
7
+ } from "@lukso/lsp1-contracts/contracts/ILSP1UniversalReceiver.sol";
8
+
9
+ contract SelfDestructOnInterfaceCheck is ILSP1UniversalReceiver {
10
+ uint256 public counter;
11
+
12
+ function supportsInterface(bytes4) external returns (bool) {
13
+ selfdestruct(payable(msg.sender));
14
+ return true;
15
+ }
16
+
17
+ function universalReceiver(
18
+ bytes32,
19
+ bytes memory
20
+ ) external payable returns (bytes memory) {
21
+ return "";
22
+ }
23
+ }
package/dist/index.cjs ADDED
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const INTERFACE_ID_LSP26 = "0x2b299cea";
4
+ const LSP26_TYPE_IDS = {
5
+ // keccak256('LSP26FollowerSystem_FollowNotification')
6
+ LSP26FollowerSystem_FollowNotification: "0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a",
7
+ // keccak256('LSP26FollowerSystem_UnfollowNotification')
8
+ LSP26FollowerSystem_UnfollowNotification: "0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f"
9
+ };
10
+
11
+ exports.INTERFACE_ID_LSP26 = INTERFACE_ID_LSP26;
12
+ exports.LSP26_TYPE_IDS = LSP26_TYPE_IDS;
@@ -0,0 +1,7 @@
1
+ declare const INTERFACE_ID_LSP26 = "0x2b299cea";
2
+ declare const LSP26_TYPE_IDS: {
3
+ readonly LSP26FollowerSystem_FollowNotification: "0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a";
4
+ readonly LSP26FollowerSystem_UnfollowNotification: "0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f";
5
+ };
6
+
7
+ export { INTERFACE_ID_LSP26, LSP26_TYPE_IDS };
@@ -0,0 +1,7 @@
1
+ declare const INTERFACE_ID_LSP26 = "0x2b299cea";
2
+ declare const LSP26_TYPE_IDS: {
3
+ readonly LSP26FollowerSystem_FollowNotification: "0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a";
4
+ readonly LSP26FollowerSystem_UnfollowNotification: "0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f";
5
+ };
6
+
7
+ export { INTERFACE_ID_LSP26, LSP26_TYPE_IDS };
@@ -0,0 +1,7 @@
1
+ declare const INTERFACE_ID_LSP26 = "0x2b299cea";
2
+ declare const LSP26_TYPE_IDS: {
3
+ readonly LSP26FollowerSystem_FollowNotification: "0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a";
4
+ readonly LSP26FollowerSystem_UnfollowNotification: "0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f";
5
+ };
6
+
7
+ export { INTERFACE_ID_LSP26, LSP26_TYPE_IDS };
package/dist/index.mjs ADDED
@@ -0,0 +1,9 @@
1
+ const INTERFACE_ID_LSP26 = "0x2b299cea";
2
+ const LSP26_TYPE_IDS = {
3
+ // keccak256('LSP26FollowerSystem_FollowNotification')
4
+ LSP26FollowerSystem_FollowNotification: "0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a",
5
+ // keccak256('LSP26FollowerSystem_UnfollowNotification')
6
+ LSP26FollowerSystem_UnfollowNotification: "0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f"
7
+ };
8
+
9
+ export { INTERFACE_ID_LSP26, LSP26_TYPE_IDS };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@lukso/lsp26-contracts",
3
+ "version": "0.1.2",
4
+ "description": "Package for the LSP26 Follower System standard",
5
+ "license": "Apache-2.0",
6
+ "author": "",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.mjs",
9
+ "typings": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "require": "./dist/index.cjs",
13
+ "import": "./dist/index.mjs",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./artifacts/*": "./artifacts/*",
17
+ "./package.json": "./package.json"
18
+ },
19
+ "keywords": [
20
+ "LUKSO",
21
+ "LSP",
22
+ "Blockchain",
23
+ "Standards",
24
+ "Smart Contracts",
25
+ "Ethereum",
26
+ "EVM",
27
+ "Solidity"
28
+ ],
29
+ "files": [
30
+ "contracts/**/*.sol",
31
+ "!contracts/Mocks/**/*.sol",
32
+ "artifacts/*.json",
33
+ "dist",
34
+ "types",
35
+ "!types/factories",
36
+ "./README.md"
37
+ ],
38
+ "scripts": {
39
+ "build": "hardhat compile --show-stack-traces",
40
+ "build:js": "unbuild",
41
+ "build:types": "npx wagmi generate",
42
+ "clean": "hardhat clean && rm -Rf dist/ cache/ node_modules/ .turbo/ types/ typechain/ build/ artifacts/",
43
+ "format": "prettier --write .",
44
+ "lint": "eslint . --ext .ts,.js",
45
+ "lint:solidity": "solhint 'contracts/**/*.sol' && prettier --check 'contracts/**/*.sol'",
46
+ "test": "hardhat test --no-compile tests/*.test.ts",
47
+ "test:coverage": "hardhat coverage",
48
+ "package": "hardhat prepare-package"
49
+ },
50
+ "dependencies": {
51
+ "@openzeppelin/contracts": "^4.9.6",
52
+ "@lukso/lsp0-contracts": "~0.15.0",
53
+ "@lukso/lsp1-contracts": "~0.15.0"
54
+ }
55
+ }