lens-modules 3.1.1 → 3.1.3

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.
Files changed (140) hide show
  1. package/contracts/actions/account/TippingAccountAction.sol +29 -9
  2. package/contracts/actions/account/base/BaseAccountAction.sol +7 -4
  3. package/contracts/actions/account/base/OwnableMetadataBasedAccountAction.sol +8 -3
  4. package/contracts/actions/base/BaseAction.sol +2 -2
  5. package/contracts/actions/post/TippingPostAction.sol +29 -9
  6. package/contracts/actions/post/base/BasePostAction.sol +7 -5
  7. package/contracts/actions/post/base/OwnableMetadataBasedPostAction.sol +8 -3
  8. package/contracts/actions/post/collect/ISimpleCollectAction.sol +14 -3
  9. package/contracts/actions/post/collect/LensCollectedPost.sol +83 -34
  10. package/contracts/actions/post/collect/SimpleCollectAction.sol +174 -62
  11. package/contracts/core/access/AccessControlled.sol +5 -9
  12. package/contracts/core/access/Ownable.sol +2 -2
  13. package/contracts/core/access/RoleBasedAccessControl.sol +28 -9
  14. package/contracts/core/base/BaseSource.sol +3 -4
  15. package/contracts/core/base/EntityExtraDataBased.sol +37 -0
  16. package/contracts/core/base/ExtraDataBased.sol +33 -0
  17. package/contracts/core/base/ExtraStorageBased.sol +45 -28
  18. package/contracts/core/base/LensERC721.sol +6 -3
  19. package/contracts/core/base/MetadataBased.sol +3 -2
  20. package/contracts/core/base/RuleBasedPrimitive.sol +9 -6
  21. package/contracts/core/base/SourceStampBased.sol +78 -24
  22. package/contracts/core/interfaces/IAccessControlled.sol +9 -0
  23. package/contracts/core/interfaces/IAccountGroupAdditionSettings.sol +12 -0
  24. package/contracts/core/interfaces/IERC721Namespace.sol +1 -1
  25. package/contracts/core/interfaces/IFeed.sol +11 -8
  26. package/contracts/core/interfaces/IFeedRule.sol +2 -2
  27. package/contracts/core/interfaces/IFollowRule.sol +1 -1
  28. package/contracts/core/interfaces/IGraph.sol +9 -7
  29. package/contracts/core/interfaces/IGraphRule.sol +1 -1
  30. package/contracts/core/interfaces/IGroup.sol +11 -9
  31. package/contracts/core/interfaces/IGroupRule.sol +1 -1
  32. package/contracts/core/interfaces/INamespace.sol +19 -11
  33. package/contracts/core/interfaces/INamespaceRule.sol +1 -1
  34. package/contracts/core/interfaces/IPostRule.sol +2 -2
  35. package/contracts/core/interfaces/IRequestBasedGroupRule.sol +12 -0
  36. package/contracts/core/interfaces/IRoleBasedAccessControl.sol +10 -1
  37. package/contracts/core/interfaces/ISource.sol +1 -1
  38. package/contracts/core/libraries/AccessControlLib.sol +20 -6
  39. package/contracts/core/libraries/CallLib.sol +1 -1
  40. package/contracts/core/libraries/EIP712EncodingLib.sol +2 -2
  41. package/contracts/core/libraries/KeyValueLib.sol +19 -0
  42. package/contracts/core/libraries/KeyValueStorageLib.sol +1 -1
  43. package/contracts/core/libraries/RulesLib.sol +3 -3
  44. package/contracts/core/primitives/feed/Feed.sol +75 -70
  45. package/contracts/core/primitives/feed/FeedCore.sol +7 -5
  46. package/contracts/core/primitives/feed/RuleBasedFeed.sol +18 -17
  47. package/contracts/core/primitives/graph/Graph.sol +51 -36
  48. package/contracts/core/primitives/graph/GraphCore.sol +2 -2
  49. package/contracts/core/primitives/graph/RuleBasedGraph.sol +16 -15
  50. package/contracts/core/primitives/group/Group.sol +145 -54
  51. package/contracts/core/primitives/group/GroupCore.sol +2 -2
  52. package/contracts/core/primitives/group/RuleBasedGroup.sol +16 -15
  53. package/contracts/core/primitives/namespace/LensUsernameTokenURIProvider.sol +3 -3
  54. package/contracts/core/primitives/namespace/Namespace.sol +113 -71
  55. package/contracts/core/primitives/namespace/NamespaceCore.sol +2 -1
  56. package/contracts/core/primitives/namespace/RuleBasedNamespace.sol +14 -13
  57. package/contracts/core/types/Constants.sol +20 -0
  58. package/contracts/core/types/Errors.sol +7 -0
  59. package/contracts/core/types/Types.sol +5 -0
  60. package/contracts/core/upgradeability/Beacon.sol +5 -4
  61. package/contracts/core/upgradeability/BeaconProxy.sol +2 -2
  62. package/contracts/core/upgradeability/EmptyImplementation.sol +5 -0
  63. package/contracts/core/upgradeability/Initializable.sol +1 -1
  64. package/contracts/core/upgradeability/LegacyBeaconProxy.sol +5 -2
  65. package/contracts/core/upgradeability/LensCreate2.sol +82 -0
  66. package/contracts/core/upgradeability/Lock.sol +4 -3
  67. package/contracts/core/upgradeability/ProxyAdmin.sol +5 -5
  68. package/contracts/extensions/access/OwnerAdminOnlyAccessControl.sol +5 -5
  69. package/contracts/extensions/access/PermissionlessAccessControl.sol +1 -1
  70. package/contracts/extensions/account/Account.sol +521 -110
  71. package/contracts/extensions/account/IAccount.sol +31 -8
  72. package/contracts/extensions/actions/ActionHub.sol +94 -31
  73. package/contracts/extensions/factories/AccessControlFactory.sol +3 -3
  74. package/contracts/extensions/factories/AccountFactory.sol +4 -4
  75. package/contracts/extensions/factories/AppFactory.sol +5 -5
  76. package/contracts/extensions/factories/FeedFactory.sol +10 -8
  77. package/contracts/extensions/factories/GraphFactory.sol +10 -8
  78. package/contracts/extensions/factories/GroupFactory.sol +12 -14
  79. package/contracts/extensions/factories/LensFactory.sol +267 -95
  80. package/contracts/extensions/factories/NamespaceFactory.sol +11 -9
  81. package/contracts/extensions/factories/PrimitiveFactory.sol +12 -3
  82. package/contracts/extensions/fees/LensFees.sol +38 -0
  83. package/contracts/extensions/fees/LensNativePaymentHelper.sol +62 -0
  84. package/contracts/extensions/fees/LensPaymentHandler.sol +116 -0
  85. package/contracts/extensions/fees/LensRulePaymentHandler.sol +30 -0
  86. package/contracts/extensions/misc/TokenDistributor.sol +248 -0
  87. package/contracts/extensions/primitives/app/App.sol +31 -34
  88. package/contracts/extensions/primitives/app/AppCore.sol +2 -2
  89. package/contracts/extensions/primitives/app/IApp.sol +4 -4
  90. package/contracts/migration/EventEmitter.sol +160 -0
  91. package/contracts/migration/EventEmitterEarly.sol +10 -0
  92. package/contracts/migration/WhitelistedAddresses.sol +1 -1
  93. package/contracts/migration/factories/MigrationAccessControlFactory.sol +10 -0
  94. package/contracts/migration/factories/MigrationAccountFactory.sol +10 -0
  95. package/contracts/migration/factories/MigrationAppFactory.sol +10 -0
  96. package/contracts/migration/factories/MigrationFeedFactory.sol +12 -0
  97. package/contracts/migration/factories/MigrationGraphFactory.sol +12 -0
  98. package/contracts/migration/factories/MigrationLensFactory.sol +12 -91
  99. package/contracts/migration/factories/MigrationNamespaceFactory.sol +12 -0
  100. package/contracts/migration/primitives/MigrationAccount.sol +3 -89
  101. package/contracts/migration/primitives/MigrationApp.sol +8 -0
  102. package/contracts/migration/primitives/MigrationFeed.sol +14 -44
  103. package/contracts/migration/primitives/MigrationGraph.sol +8 -31
  104. package/contracts/migration/primitives/MigrationNamespace.sol +11 -185
  105. package/contracts/rules/AccountBlockingRule.sol +40 -22
  106. package/contracts/rules/base/OwnableMetadataBasedRule.sol +7 -2
  107. package/contracts/rules/base/SimplePaymentRule.sol +31 -12
  108. package/contracts/rules/base/TokenGatedRule.sol +6 -2
  109. package/contracts/rules/base/TrustBasedRule.sol +1 -1
  110. package/contracts/rules/feed/GroupGatedFeedRule.sol +58 -15
  111. package/contracts/rules/feed/SimplePaymentFeedRule.sol +60 -18
  112. package/contracts/rules/feed/TokenGatedFeedRule.sol +32 -15
  113. package/contracts/rules/follow/SimplePaymentFollowRule.sol +71 -12
  114. package/contracts/rules/follow/TokenGatedFollowRule.sol +30 -9
  115. package/contracts/rules/graph/GroupGatedGraphRule.sol +35 -18
  116. package/contracts/rules/graph/TokenGatedGraphRule.sol +36 -19
  117. package/contracts/rules/group/AdditionRemovalPidGroupRule.sol +99 -0
  118. package/contracts/rules/group/BanMemberGroupRule.sol +115 -70
  119. package/contracts/rules/group/MembershipApprovalGroupRule.sol +68 -31
  120. package/contracts/rules/group/SimplePaymentGroupRule.sol +75 -26
  121. package/contracts/rules/group/TokenGatedGroupRule.sol +51 -33
  122. package/contracts/rules/namespace/TokenGatedNamespaceRule.sol +38 -20
  123. package/contracts/rules/namespace/UsernameLengthNamespaceRule.sol +31 -13
  124. package/contracts/rules/namespace/UsernamePricePerLengthNamespaceRule.sol +101 -31
  125. package/contracts/rules/namespace/UsernameReservedNamespaceRule.sol +40 -18
  126. package/contracts/rules/namespace/UsernameSimpleCharsetNamespaceRule.sol +13 -6
  127. package/contracts/rules/post/FollowersOnlyPostRule.sol +43 -19
  128. package/package.json +6 -4
  129. package/dist/abis.cjs +0 -1
  130. package/dist/abis.d.cts +0 -38902
  131. package/dist/abis.d.ts +0 -38902
  132. package/dist/abis.js +0 -1
  133. package/dist/deployments.cjs +0 -1
  134. package/dist/deployments.d.cts +0 -760
  135. package/dist/deployments.d.ts +0 -760
  136. package/dist/deployments.js +0 -1
  137. package/dist/index.cjs +0 -1
  138. package/dist/index.d.cts +0 -2
  139. package/dist/index.d.ts +0 -2
  140. package/dist/index.js +0 -1
@@ -2,23 +2,33 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {OwnableMetadataBasedAccountAction} from "./base/OwnableMetadataBasedAccountAction.sol";
5
+ import {OwnableMetadataBasedAccountAction} from "lens-modules/contracts/actions/account/base/OwnableMetadataBasedAccountAction.sol";
6
6
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
7
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8
- import {KeyValue} from "../../core/types/Types.sol";
9
- import {Errors} from "../../core/types/Errors.sol";
8
+ import {KeyValue, RecipientData} from "lens-modules/contracts/core/types/Types.sol";
9
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
10
+ import {Initializable} from "lens-modules/contracts/core/upgradeability/Initializable.sol";
11
+ import {LensPaymentHandler} from "lens-modules/contracts/extensions/fees/LensPaymentHandler.sol";
10
12
 
11
- contract TippingAccountAction is OwnableMetadataBasedAccountAction {
13
+ contract TippingAccountAction is LensPaymentHandler, OwnableMetadataBasedAccountAction, Initializable {
12
14
  using SafeERC20 for IERC20;
13
15
 
14
16
  /// @custom:keccak lens.param.amount
15
17
  bytes32 constant PARAM__TIP_AMOUNT = 0xc8a06abcb0f2366f32dc2741bdf075c3215e3108918311ec0ac742f1ffd37f49;
16
18
  /// @custom:keccak lens.param.token
17
- bytes32 constant PARAM__TIP_TOKEN = 0xee737c77be2981e91c179485406e6d793521b20aca5e2137b6c497949a74bc94;
19
+ bytes32 public constant PARAM__TIP_TOKEN = 0xee737c77be2981e91c179485406e6d793521b20aca5e2137b6c497949a74bc94;
20
+ /// @custom:keccak lens.param.referrals
21
+ bytes32 constant PARAM__REFERRALS = 0x183a1b7fdb9626f5ae4e8cac88ee13cc03b29800d2690f61e2a2566f76d8773f;
18
22
 
19
- constructor(address actionHub, address owner, string memory metadataURI)
20
- OwnableMetadataBasedAccountAction(actionHub, owner, metadataURI)
21
- {}
23
+ uint16 constant REFERRALS_FEE_MAX_BPS = 2000; // 20.00%
24
+
25
+ constructor(address actionHub) OwnableMetadataBasedAccountAction(actionHub, address(0), "") {
26
+ _disableInitializers();
27
+ }
28
+
29
+ function initialize(address owner, string memory metadataURI) external initializer {
30
+ OwnableMetadataBasedAccountAction._initialize(owner, metadataURI);
31
+ }
22
32
 
23
33
  function _execute(address originalMsgSender, address account, KeyValue[] calldata params)
24
34
  internal
@@ -27,15 +37,25 @@ contract TippingAccountAction is OwnableMetadataBasedAccountAction {
27
37
  {
28
38
  address erc20Token;
29
39
  uint256 tipAmount;
40
+ RecipientData[] memory referrals = new RecipientData[](0);
30
41
  for (uint256 i = 0; i < params.length; i++) {
31
42
  if (params[i].key == PARAM__TIP_AMOUNT) {
32
43
  tipAmount = abi.decode(params[i].value, (uint256));
33
44
  } else if (params[i].key == PARAM__TIP_TOKEN) {
34
45
  erc20Token = abi.decode(params[i].value, (address));
46
+ } else if (params[i].key == PARAM__REFERRALS) {
47
+ referrals = abi.decode(params[i].value, (RecipientData[]));
35
48
  }
36
49
  }
37
50
  require(tipAmount > 0, Errors.InvalidParameter());
38
- IERC20(erc20Token).safeTransferFrom(originalMsgSender, account, tipAmount);
51
+ _handlePayment({
52
+ payer: originalMsgSender,
53
+ token: erc20Token,
54
+ amount: tipAmount,
55
+ recipient: account,
56
+ referrals: referrals,
57
+ referralFeeBps: REFERRALS_FEE_MAX_BPS
58
+ });
39
59
  return "";
40
60
  }
41
61
  }
@@ -2,16 +2,17 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {KeyValue} from "../../../core/types/Types.sol";
6
- import {BaseAction} from "../../base/BaseAction.sol";
7
- import {IAccountAction} from "../../../extensions/actions/ActionHub.sol";
8
- import {Errors} from "../../../core/types/Errors.sol";
5
+ import {KeyValue} from "lens-modules/contracts/core/types/Types.sol";
6
+ import {BaseAction} from "lens-modules/contracts/actions/base/BaseAction.sol";
7
+ import {IAccountAction} from "lens-modules/contracts/extensions/actions/ActionHub.sol";
8
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
9
9
 
10
10
  abstract contract BaseAccountAction is BaseAction, IAccountAction {
11
11
  constructor(address actionHub) BaseAction(actionHub) {}
12
12
 
13
13
  function configure(address originalMsgSender, address account, KeyValue[] calldata params)
14
14
  external
15
+ payable
15
16
  override
16
17
  onlyActionHub
17
18
  returns (bytes memory)
@@ -21,6 +22,7 @@ abstract contract BaseAccountAction is BaseAction, IAccountAction {
21
22
 
22
23
  function execute(address originalMsgSender, address account, KeyValue[] calldata params)
23
24
  external
25
+ payable
24
26
  override
25
27
  onlyActionHub
26
28
  returns (bytes memory)
@@ -30,6 +32,7 @@ abstract contract BaseAccountAction is BaseAction, IAccountAction {
30
32
 
31
33
  function setDisabled(address originalMsgSender, address account, bool isDisabled, KeyValue[] calldata params)
32
34
  external
35
+ payable
33
36
  override
34
37
  onlyActionHub
35
38
  returns (bytes memory)
@@ -2,9 +2,9 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {Ownable} from "../../../core/access/Ownable.sol";
6
- import {MetadataBased} from "../../../core/base/MetadataBased.sol";
7
- import {BaseAccountAction} from "./BaseAccountAction.sol";
5
+ import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol";
6
+ import {MetadataBased} from "lens-modules/contracts/core/base/MetadataBased.sol";
7
+ import {BaseAccountAction} from "lens-modules/contracts/actions/account/base/BaseAccountAction.sol";
8
8
 
9
9
  abstract contract OwnableMetadataBasedAccountAction is BaseAccountAction, Ownable, MetadataBased {
10
10
  event Lens_AccountAction_MetadataURISet(string metadataURI);
@@ -14,6 +14,11 @@ abstract contract OwnableMetadataBasedAccountAction is BaseAccountAction, Ownabl
14
14
  _setMetadataURI(metadataURI);
15
15
  }
16
16
 
17
+ function _initialize(address owner, string memory metadataURI) internal {
18
+ _transferOwnership(owner);
19
+ _setMetadataURI(metadataURI);
20
+ }
21
+
17
22
  function _emitMetadataURISet(string memory metadataURI, address /* source */ ) internal virtual override {
18
23
  emit Lens_AccountAction_MetadataURISet(metadataURI);
19
24
  }
@@ -2,8 +2,8 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {UNIVERSAL_ACTION_MAGIC_VALUE} from "../../extensions/actions/ActionHub.sol";
6
- import {Errors} from "../../core/types/Errors.sol";
5
+ import {UNIVERSAL_ACTION_MAGIC_VALUE} from "lens-modules/contracts/extensions/actions/ActionHub.sol";
6
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
7
7
 
8
8
  abstract contract BaseAction {
9
9
  address immutable ACTION_HUB;
@@ -2,24 +2,34 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {OwnableMetadataBasedPostAction} from "./base/OwnableMetadataBasedPostAction.sol";
5
+ import {OwnableMetadataBasedPostAction} from "lens-modules/contracts/actions/post/base/OwnableMetadataBasedPostAction.sol";
6
6
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
7
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8
- import {KeyValue} from "../../core/types/Types.sol";
9
- import {IFeed} from "../../core/interfaces/IFeed.sol";
10
- import {Errors} from "../../core/types/Errors.sol";
8
+ import {KeyValue, RecipientData} from "lens-modules/contracts/core/types/Types.sol";
9
+ import {IFeed} from "lens-modules/contracts/core/interfaces/IFeed.sol";
10
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
11
+ import {Initializable} from "lens-modules/contracts/core/upgradeability/Initializable.sol";
12
+ import {LensPaymentHandler} from "lens-modules/contracts/extensions/fees/LensPaymentHandler.sol";
11
13
 
12
- contract TippingPostAction is OwnableMetadataBasedPostAction {
14
+ contract TippingPostAction is LensPaymentHandler, OwnableMetadataBasedPostAction, Initializable {
13
15
  using SafeERC20 for IERC20;
14
16
 
15
17
  /// @custom:keccak lens.param.amount
16
18
  bytes32 constant PARAM__TIP_AMOUNT = 0xc8a06abcb0f2366f32dc2741bdf075c3215e3108918311ec0ac742f1ffd37f49;
17
19
  /// @custom:keccak lens.param.token
18
20
  bytes32 constant PARAM__TIP_TOKEN = 0xee737c77be2981e91c179485406e6d793521b20aca5e2137b6c497949a74bc94;
21
+ /// @custom:keccak lens.param.referrals
22
+ bytes32 constant PARAM__REFERRALS = 0x183a1b7fdb9626f5ae4e8cac88ee13cc03b29800d2690f61e2a2566f76d8773f;
19
23
 
20
- constructor(address actionHub, address owner, string memory metadataURI)
21
- OwnableMetadataBasedPostAction(actionHub, owner, metadataURI)
22
- {}
24
+ uint16 constant REFERRALS_FEE_MAX_BPS = 2000; // 20.00%
25
+
26
+ constructor(address actionHub) OwnableMetadataBasedPostAction(actionHub, address(0), "") {
27
+ _disableInitializers();
28
+ }
29
+
30
+ function initialize(address owner, string memory metadataURI) external initializer {
31
+ OwnableMetadataBasedPostAction._initialize(owner, metadataURI);
32
+ }
23
33
 
24
34
  function _execute(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params)
25
35
  internal
@@ -28,16 +38,26 @@ contract TippingPostAction is OwnableMetadataBasedPostAction {
28
38
  {
29
39
  address erc20Token;
30
40
  uint256 tipAmount;
41
+ RecipientData[] memory referrals = new RecipientData[](0);
31
42
  for (uint256 i = 0; i < params.length; i++) {
32
43
  if (params[i].key == PARAM__TIP_AMOUNT) {
33
44
  tipAmount = abi.decode(params[i].value, (uint256));
34
45
  } else if (params[i].key == PARAM__TIP_TOKEN) {
35
46
  erc20Token = abi.decode(params[i].value, (address));
47
+ } else if (params[i].key == PARAM__REFERRALS) {
48
+ referrals = abi.decode(params[i].value, (RecipientData[]));
36
49
  }
37
50
  }
38
51
  require(tipAmount > 0, Errors.InvalidParameter());
39
52
  address account = IFeed(feed).getPostAuthor(postId);
40
- IERC20(erc20Token).safeTransferFrom(originalMsgSender, account, tipAmount);
53
+ _handlePayment({
54
+ payer: originalMsgSender,
55
+ token: erc20Token,
56
+ amount: tipAmount,
57
+ recipient: account,
58
+ referrals: referrals,
59
+ referralFeeBps: REFERRALS_FEE_MAX_BPS
60
+ });
41
61
  return abi.encode(account);
42
62
  }
43
63
  }
@@ -2,16 +2,17 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {KeyValue} from "../../../core/types/Types.sol";
6
- import {BaseAction} from "../../base/BaseAction.sol";
7
- import {IPostAction} from "../../../extensions/actions/ActionHub.sol";
8
- import {Errors} from "../../../core/types/Errors.sol";
5
+ import {KeyValue} from "lens-modules/contracts/core/types/Types.sol";
6
+ import {BaseAction} from "lens-modules/contracts/actions/base/BaseAction.sol";
7
+ import {IPostAction} from "lens-modules/contracts/extensions/actions/ActionHub.sol";
8
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
9
9
 
10
10
  abstract contract BasePostAction is BaseAction, IPostAction {
11
11
  constructor(address actionHub) BaseAction(actionHub) {}
12
12
 
13
13
  function configure(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params)
14
14
  external
15
+ payable
15
16
  override
16
17
  onlyActionHub
17
18
  returns (bytes memory)
@@ -21,6 +22,7 @@ abstract contract BasePostAction is BaseAction, IPostAction {
21
22
 
22
23
  function execute(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params)
23
24
  external
25
+ payable
24
26
  override
25
27
  onlyActionHub
26
28
  returns (bytes memory)
@@ -34,7 +36,7 @@ abstract contract BasePostAction is BaseAction, IPostAction {
34
36
  uint256 postId,
35
37
  bool isDisabled,
36
38
  KeyValue[] calldata params
37
- ) external override onlyActionHub returns (bytes memory) {
39
+ ) external payable override onlyActionHub returns (bytes memory) {
38
40
  return _setDisabled(originalMsgSender, feed, postId, isDisabled, params);
39
41
  }
40
42
 
@@ -2,9 +2,9 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {Ownable} from "../../../core/access/Ownable.sol";
6
- import {MetadataBased} from "../../../core/base/MetadataBased.sol";
7
- import {BasePostAction} from "./BasePostAction.sol";
5
+ import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol";
6
+ import {MetadataBased} from "lens-modules/contracts/core/base/MetadataBased.sol";
7
+ import {BasePostAction} from "lens-modules/contracts/actions/post/base/BasePostAction.sol";
8
8
 
9
9
  abstract contract OwnableMetadataBasedPostAction is BasePostAction, Ownable, MetadataBased {
10
10
  event Lens_PostAction_MetadataURISet(string metadataURI);
@@ -14,6 +14,11 @@ abstract contract OwnableMetadataBasedPostAction is BasePostAction, Ownable, Met
14
14
  _setMetadataURI(metadataURI);
15
15
  }
16
16
 
17
+ function _initialize(address owner, string memory metadataURI) internal {
18
+ _transferOwnership(owner);
19
+ _setMetadataURI(metadataURI);
20
+ }
21
+
17
22
  function _emitMetadataURISet(string memory metadataURI, address /* source */ ) internal virtual override {
18
23
  emit Lens_PostAction_MetadataURISet(metadataURI);
19
24
  }
@@ -2,7 +2,8 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import {IPostAction} from "../../../extensions/actions/ActionHub.sol";
5
+ import {IPostAction} from "lens-modules/contracts/extensions/actions/ActionHub.sol";
6
+ import {RecipientData} from "lens-modules/contracts/core/types/Types.sol";
6
7
 
7
8
  /**
8
9
  * @notice A storage struct containing all data regarding a post's collect action.
@@ -11,17 +12,27 @@ import {IPostAction} from "../../../extensions/actions/ActionHub.sol";
11
12
  * @param collectLimit The maximum number of collects for this publication. 0 for no limit.
12
13
  * @param token The token associated with this publication.
13
14
  * @param currentCollects The current number of collects for this publication.
14
- * @param recipient Recipient of collect fees.
15
+ * @param recipients Recipients of collect amount.
15
16
  * @param endTimestamp The end timestamp after which collecting is impossible. 0 for no expiry.
17
+ * @param referralFeeBps The referral fee in basis points.
18
+ * @param followerOnlyGraph The graph that holds the follow relations that restrict who can collect this post.
16
19
  * @param collectionAddress The address of the collectible ERC721 contract.
20
+ * @param isImmutable If true, it means that:
21
+ * - The Post URI is snapshotted at configuration time and cannot be changed later.
22
+ * - Collected posts' NFTs remain permanently available.
23
+ * - What you see is what you get; editing the Post URI or deleting the post will disable collection.
24
+ * Note: This immutability is only guaranteed if the URI is hosted on immutable storage. Mutability inherent
25
+ * to the chosen storage technology exceeds the on-chain verification capabilities.
26
+ * @param isDisabled Whether the collect action is disabled or not.
17
27
  */
18
28
  struct CollectActionData {
19
29
  uint160 amount;
20
30
  uint96 collectLimit;
21
31
  address token;
22
32
  uint96 currentCollects;
23
- address recipient;
33
+ RecipientData[] recipients;
24
34
  uint72 endTimestamp;
35
+ uint16 referralFeeBps;
25
36
  address followerOnlyGraph;
26
37
  address collectionAddress;
27
38
  bool isImmutable;
@@ -2,11 +2,15 @@
2
2
  // Copyright (C) 2024 Lens Labs. All Rights Reserved.
3
3
  pragma solidity ^0.8.26;
4
4
 
5
- import "../../../core/base/LensERC721.sol";
6
- import {IERC7572} from "./IERC7572.sol";
7
- import {IFeed} from "../../../core/interfaces/IFeed.sol";
8
- import {ITokenURIProvider} from "../../../core/interfaces/ITokenURIProvider.sol";
9
- import {Errors} from "../../../core/types/Errors.sol";
5
+ import "lens-modules/contracts/core/base/LensERC721.sol";
6
+ import {IFeed} from "lens-modules/contracts/core/interfaces/IFeed.sol";
7
+ import {ITokenURIProvider} from "lens-modules/contracts/core/interfaces/ITokenURIProvider.sol";
8
+ import {Errors} from "lens-modules/contracts/core/types/Errors.sol";
9
+
10
+ struct ContentURISnapshot {
11
+ string contentURI;
12
+ uint256 tokenId;
13
+ }
10
14
 
11
15
  /**
12
16
  * @notice A contract that represents a Lens Collected Post.
@@ -19,52 +23,97 @@ import {Errors} from "../../../core/types/Errors.sol";
19
23
  * If the Collect is immutable - it will snapshot the content of the post and always return the snapshotted tokenURI
20
24
  * even if the post was updated or deleted. The contractURI, however, always stays the same, as it was at the moment of
21
25
  * Collect creation.
26
+ *
27
+ * We assume tokenIds are sequential and start from 1.
22
28
  */
23
- contract LensCollectedPost is LensERC721, IERC7572 {
24
- string internal _contentURISnapshot;
25
- string internal _contractURI;
26
- address internal immutable _feed;
27
- uint256 internal immutable _postId;
28
- address internal immutable _collectAction;
29
-
30
- constructor(address feed, uint256 postId, bool isImmutable) {
29
+ contract LensCollectedPost is LensERC721 {
30
+ event Lens_LensCollectedPost_Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
31
+
32
+ ContentURISnapshot[] internal _contentURISnapshots;
33
+ bool internal _isImmutable;
34
+ address internal immutable FEED;
35
+ uint256 internal immutable POST_ID;
36
+ address internal immutable COLLECT_ACTION;
37
+
38
+ constructor(address feed, uint256 postId, bool isImmutableCollect) {
31
39
  LensERC721._initialize("Lens Collected Post", "LCP", ITokenURIProvider(address(0)));
32
- string memory contentURI = IFeed(feed).getPost(postId).contentURI;
33
- require(bytes(contentURI).length > 0, Errors.InvalidParameter());
34
- _feed = feed;
35
- _postId = postId;
36
- _contractURI = contentURI;
37
- _collectAction = msg.sender;
38
- if (isImmutable) {
39
- _contentURISnapshot = contentURI;
40
+ COLLECT_ACTION = msg.sender;
41
+ FEED = feed;
42
+ POST_ID = postId;
43
+ // Getting the URI outside the if to use it as a length validation too.
44
+ string memory contentURI = _getNonEmptyContentURIFromPost();
45
+ if (isImmutableCollect) {
46
+ _turnImmutable(contentURI);
40
47
  }
41
- emit ContractURIUpdated();
42
48
  }
43
49
 
44
50
  function mint(address to, uint256 tokenId) external {
45
- require(msg.sender == _collectAction, Errors.InvalidMsgSender());
51
+ require(msg.sender == COLLECT_ACTION, Errors.InvalidMsgSender());
52
+ _takeContentURISnapshotIfNeeded(tokenId);
46
53
  _mint(to, tokenId);
47
54
  }
48
55
 
49
- // Getters
50
-
51
- function contractURI() external view returns (string memory) {
52
- return _contractURI;
56
+ function turnImmutable() external {
57
+ require(msg.sender == COLLECT_ACTION, Errors.InvalidMsgSender());
58
+ if (!_isImmutable) {
59
+ _turnImmutable(_getNonEmptyContentURIFromPost());
60
+ }
53
61
  }
54
62
 
55
- function tokenURI(uint256 /*tokenId*/ ) public view override returns (string memory) {
56
- if (bytes(_contentURISnapshot).length > 0) {
57
- return _contentURISnapshot;
63
+ // Getters
64
+
65
+ function tokenURI(uint256 tokenId) public view override returns (string memory) {
66
+ if (_isImmutable) {
67
+ // Searching for snapshots (starting from latest)
68
+ for (uint256 i = _contentURISnapshots.length - 1; i > 0; i--) {
69
+ if (_contentURISnapshots[i].tokenId <= tokenId) {
70
+ return _contentURISnapshots[i].contentURI;
71
+ }
72
+ }
73
+ // contentURISnapshot[0] is always taken when the collection is marked as immutable,
74
+ // so we can guarantee it's present and non-empty.
75
+ return _contentURISnapshots[0].contentURI;
58
76
  } else {
59
- string memory contentURI = IFeed(_feed).getPost(_postId).contentURI;
60
- // If content was deleted we fail. You can override this to return the empty URI if preferred.
61
- require(bytes(contentURI).length > 0, Errors.DoesNotExist());
62
- return contentURI;
77
+ return _getNonEmptyContentURIFromPost();
63
78
  }
64
79
  }
65
80
 
81
+ function getPostId() external view returns (uint256) {
82
+ return POST_ID;
83
+ }
84
+
85
+ function isImmutable() external view returns (bool) {
86
+ return _isImmutable;
87
+ }
88
+
66
89
  // Internal
67
90
 
91
+ function _getNonEmptyContentURIFromPost() internal view returns (string memory) {
92
+ string memory contentURI = IFeed(FEED).getPost(POST_ID).contentURI;
93
+ require(bytes(contentURI).length > 0, Errors.InvalidParameter());
94
+ return contentURI;
95
+ }
96
+
97
+ function _turnImmutable(string memory contentURI) internal {
98
+ _isImmutable = true;
99
+ _contentURISnapshots.push(ContentURISnapshot(contentURI, 0));
100
+ }
101
+
102
+ function _takeContentURISnapshotIfNeeded(uint256 tokenId) internal {
103
+ if (_isImmutable) {
104
+ // Getting the content URI will revert if the post was deleted or does not exist.
105
+ string memory contentURI = _getNonEmptyContentURIFromPost();
106
+ string memory latestContentURISnapshot = _contentURISnapshots[_contentURISnapshots.length - 1].contentURI;
107
+ if (keccak256(bytes(contentURI)) != keccak256(bytes(latestContentURISnapshot))) {
108
+ _contentURISnapshots.push(ContentURISnapshot(contentURI, tokenId));
109
+ }
110
+ }
111
+ }
112
+
113
+ function _afterTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
114
+ emit Lens_LensCollectedPost_Transfer(from, to, tokenId);
115
+ }
116
+
68
117
  // Disabling integrated LensERC721 tokenURIProvider
69
118
  function _beforeTokenURIProviderSet(ITokenURIProvider /* tokenURIProvider */ ) internal pure override {
70
119
  revert Errors.NotImplemented();