├── abis ├── LensRulePaymentHandler.abi.json ├── PayableUsingNativePaymentHelper.abi.json ├── Proxy.abi.json ├── ILock.abi.json ├── IERC1822Proxiable.abi.json ├── IAccessControlled.abi.json ├── LibString.abi.json ├── IERC7572.abi.json ├── ERC165.abi.json ├── IToken.abi.json ├── IERC165.abi.json ├── ITokenURIProvider.abi.json ├── SetTokenDistributorSigner.abi.json ├── PrimitiveFactory.abi.json ├── IOwnable.abi.json ├── Query.abi.json ├── IMetadataBased.abi.json ├── ILensNativePaymentHelper.abi.json ├── IVersionedBeacon.abi.json ├── IERC4906Events.abi.json ├── ERC721Holder.abi.json ├── IERC721Receiver.abi.json ├── IERC721ReceiverUpgradeable.abi.json ├── IERC721TokenReceiver.abi.json ├── Events.abi.json ├── ExtraDataBased.abi.json ├── ExtraStorageBased.abi.json ├── SourceStampBased.abi.json ├── EntityExtraDataBased.abi.json ├── LensNativePaymentHelper.abi.json ├── IAccountGroupAdditionSettings.abi.json ├── IERC1967.abi.json ├── ERC1967Upgrade.abi.json ├── MetadataBased.abi.json ├── Ownable.abi.json ├── ILensFees.abi.json ├── AccessControlFactory.abi.json ├── TrustBasedRule.abi.json ├── LensUsernameTokenURIProvider.abi.json ├── PermissionlessAccessControl.abi.json ├── ISource.abi.json ├── IAccessControl.abi.json ├── ERC1967Proxy.abi.json ├── LensFees.abi.json ├── AccessControlled.abi.json ├── TransparentUpgradeableProxy.abi.json ├── IERC20Permit.abi.json ├── ERC1155Holder.abi.json ├── ERC1155Receiver.abi.json ├── IERC1155Receiver.abi.json ├── ProxyAdmin.abi.json ├── IFollowRule.abi.json ├── TokenGatedRule.abi.json ├── OwnableMetadataBasedRule.abi.json ├── ITransparentUpgradeableProxy.abi.json ├── BaseSource.abi.json ├── IAccountAction.abi.json └── EventEmitter.abi.json ├── .prettierignore ├── contracts ├── LICENSE ├── core │ ├── upgradeability │ │ ├── EmptyImplementation.sol │ │ ├── Initializable.sol │ │ ├── Lock.sol │ │ ├── ProxyAdmin.sol │ │ ├── Beacon.sol │ │ └── LensCreate2.sol │ ├── interfaces │ │ ├── ITokenURIProvider.sol │ │ ├── IOwnable.sol │ │ ├── ILock.sol │ │ ├── IMetadataBased.sol │ │ ├── IAccessControlled.sol │ │ ├── ISource.sol │ │ ├── IAccountGroupAdditionSettings.sol │ │ ├── IRequestBasedGroupRule.sol │ │ ├── IFollowRule.sol │ │ ├── IERC4906Events.sol │ │ ├── IERC721Namespace.sol │ │ ├── IVersionedBeacon.sol │ │ ├── IPostRule.sol │ │ ├── IGraphRule.sol │ │ ├── IGroupRule.sol │ │ ├── IAccessControl.sol │ │ ├── IFeedRule.sol │ │ ├── INamespaceRule.sol │ │ └── IRoleBasedAccessControl.sol │ ├── types │ │ ├── Events.sol │ │ ├── Constants.sol │ │ ├── Types.sol │ │ └── Errors.sol │ ├── libraries │ │ ├── KeyValueLib.sol │ │ ├── KeyValueStorageLib.sol │ │ ├── CallLib.sol │ │ └── AccessControlLib.sol │ ├── base │ │ ├── ExtraDataBased.sol │ │ ├── EntityExtraDataBased.sol │ │ └── MetadataBased.sol │ ├── access │ │ ├── Ownable.sol │ │ └── AccessControlled.sol │ └── primitives │ │ ├── group │ │ └── GroupCore.sol │ │ ├── namespace │ │ └── NamespaceCore.sol │ │ └── graph │ │ └── GraphCore.sol ├── migration │ ├── EventEmitterEarly.sol │ ├── primitives │ │ ├── MigrationApp.sol │ │ ├── MigrationAccount.sol │ │ ├── MigrationNamespace.sol │ │ └── MigrationGraph.sol │ └── factories │ │ ├── MigrationAppFactory.sol │ │ ├── MigrationAccountFactory.sol │ │ ├── MigrationAccessControlFactory.sol │ │ ├── MigrationFeedFactory.sol │ │ ├── MigrationGraphFactory.sol │ │ ├── MigrationNamespaceFactory.sol │ │ └── MigrationLensFactory.sol ├── actions │ ├── post │ │ ├── collect │ │ │ ├── IERC7572.sol │ │ │ └── ISimpleCollectAction.sol │ │ ├── base │ │ │ ├── OwnableMetadataBasedPostAction.sol │ │ │ └── BasePostAction.sol │ │ └── TippingPostAction.sol │ ├── account │ │ ├── base │ │ │ ├── OwnableMetadataBasedAccountAction.sol │ │ │ └── BaseAccountAction.sol │ │ └── TippingAccountAction.sol │ └── base │ │ └── BaseAction.sol ├── extensions │ ├── access │ │ ├── PermissionlessAccessControl.sol │ │ └── OwnerAdminOnlyAccessControl.sol │ ├── factories │ │ ├── PrimitiveFactory.sol │ │ ├── AccessControlFactory.sol │ │ ├── AppFactory.sol │ │ ├── FeedFactory.sol │ │ ├── GraphFactory.sol │ │ ├── GroupFactory.sol │ │ ├── AccountFactory.sol │ │ └── NamespaceFactory.sol │ └── fees │ │ ├── LensFees.sol │ │ ├── LensRulePaymentHandler.sol │ │ └── LensNativePaymentHelper.sol └── rules │ ├── base │ ├── OwnableMetadataBasedRule.sol │ ├── TrustBasedRule.sol │ ├── TokenGatedRule.sol │ └── SimplePaymentRule.sol │ ├── follow │ └── TokenGatedFollowRule.sol │ ├── graph │ └── RestrictedSignersGraphRule.sol │ └── feed │ └── RestrictedSignersFeedRule.sol ├── src └── index.ts ├── .npmignore ├── .prettierrc.json ├── .eslintignore ├── tsup.config.ts ├── .eslintrc.json ├── tsconfig.json ├── wagmi.config.ts ├── LICENSE ├── scripts └── generate-deployments.js ├── README.md └── package.json /abis/LensRulePaymentHandler.abi.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /abis/PayableUsingNativePaymentHelper.abi.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | pnpm-lock.yaml 2 | README.md 3 | *.json -------------------------------------------------------------------------------- /contracts/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2024 Lens Labs. All Rights Reserved. -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./deployments"; 2 | export * from "./abis"; 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | artifacts 3 | cache 4 | .idea/ 5 | .eslintignore 6 | .eslintrc.json 7 | .prettierrc.json 8 | abis -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "printWidth": 120, 4 | "tabWidth": 2, 5 | "trailingComma": "all", 6 | "importOrderSortSpecifiers": true 7 | } 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # folders 2 | .next 3 | node_modules/ 4 | # files 5 | **/*.less 6 | **/*.css 7 | **/*.scss 8 | **/*.json 9 | **/*.png 10 | **/*.svg 11 | **/generated/**/* 12 | -------------------------------------------------------------------------------- /abis/Proxy.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "fallback", 4 | "stateMutability": "payable" 5 | }, 6 | { 7 | "type": "receive", 8 | "stateMutability": "payable" 9 | } 10 | ] -------------------------------------------------------------------------------- /contracts/core/upgradeability/EmptyImplementation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.0; 4 | 5 | contract EmptyImplementation {} 6 | -------------------------------------------------------------------------------- /contracts/core/interfaces/ITokenURIProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface ITokenURIProvider { 6 | function tokenURI(uint256 tokenId) external view returns (string memory); 7 | } 8 | -------------------------------------------------------------------------------- /abis/ILock.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "isLocked", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "bool", 10 | "internalType": "bool" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | } 15 | ] -------------------------------------------------------------------------------- /abis/IERC1822Proxiable.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "proxiableUUID", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "bytes32", 10 | "internalType": "bytes32" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | } 15 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IOwnable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface IOwnable { 6 | function transferOwnership(address newOwner) external; 7 | 8 | function owner() external view returns (address); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/core/interfaces/ILock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface ILock { 6 | /** 7 | * @dev Returns true if locked, false if not. 8 | */ 9 | function isLocked() external view returns (bool); 10 | } 11 | -------------------------------------------------------------------------------- /contracts/migration/EventEmitterEarly.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | import "./EventEmitter.sol"; 5 | 6 | contract EventEmitterEarly is EventEmitter { 7 | function _allowedToEmitEvents() internal view override returns (bool) { 8 | return block.number < 30_000; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /abis/IAccessControlled.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getAccessControl", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "contract IAccessControl" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | } 15 | ] -------------------------------------------------------------------------------- /abis/LibString.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "error", 4 | "name": "HexLengthInsufficient", 5 | "inputs": [] 6 | }, 7 | { 8 | "type": "error", 9 | "name": "StringNot7BitASCII", 10 | "inputs": [] 11 | }, 12 | { 13 | "type": "error", 14 | "name": "TooBigForSmallString", 15 | "inputs": [] 16 | } 17 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IMetadataBased.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface IMetadataBased { 6 | function getMetadataURI() external view returns (string memory); 7 | function setMetadataURI(string memory metadata) external; 8 | } 9 | -------------------------------------------------------------------------------- /contracts/core/types/Events.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | library Events { 6 | event Lens_Contract_Deployed(string contractType, string flavour); 7 | 8 | event Lens_PermissionId_Available(uint256 indexed permissionId, string name); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/migration/primitives/MigrationApp.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {App} from "lens-modules/contracts/extensions/primitives/app/App.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationApp is App, EventEmitter {} 9 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IAccessControlled.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | 7 | interface IAccessControlled { 8 | function getAccessControl() external view returns (IAccessControl); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/migration/primitives/MigrationAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Account} from "lens-modules/contracts/extensions/account/Account.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationAccount is Account, EventEmitter {} 9 | -------------------------------------------------------------------------------- /contracts/core/interfaces/ISource.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {SourceStamp} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface ISource { 8 | function getTreasury() external view returns (address); 9 | 10 | function validateSource(SourceStamp calldata sourceStamp) external; 11 | } 12 | -------------------------------------------------------------------------------- /abis/IERC7572.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "contractURI", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string", 10 | "internalType": "string" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "event", 17 | "name": "ContractURIUpdated", 18 | "inputs": [], 19 | "anonymous": false 20 | } 21 | ] -------------------------------------------------------------------------------- /abis/ERC165.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "supportsInterface", 5 | "inputs": [ 6 | { 7 | "name": "interfaceId", 8 | "type": "bytes4", 9 | "internalType": "bytes4" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "bool", 16 | "internalType": "bool" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | } 21 | ] -------------------------------------------------------------------------------- /abis/IToken.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "balanceOf", 5 | "inputs": [ 6 | { 7 | "name": "account", 8 | "type": "address", 9 | "internalType": "address" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "uint256", 16 | "internalType": "uint256" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | } 21 | ] -------------------------------------------------------------------------------- /abis/IERC165.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "supportsInterface", 5 | "inputs": [ 6 | { 7 | "name": "interfaceId", 8 | "type": "bytes4", 9 | "internalType": "bytes4" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "bool", 16 | "internalType": "bool" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | } 21 | ] -------------------------------------------------------------------------------- /abis/ITokenURIProvider.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "tokenURI", 5 | "inputs": [ 6 | { 7 | "name": "tokenId", 8 | "type": "uint256", 9 | "internalType": "uint256" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "string", 16 | "internalType": "string" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | } 21 | ] -------------------------------------------------------------------------------- /abis/SetTokenDistributorSigner.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "IS_SCRIPT", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "bool", 10 | "internalType": "bool" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "run", 18 | "inputs": [], 19 | "outputs": [], 20 | "stateMutability": "nonpayable" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IAccountGroupAdditionSettings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface IAccountGroupAdditionSettings { 8 | function canBeAddedToGroup(address group, address addedBy, KeyValue[] calldata params) 9 | external 10 | view 11 | returns (bool); 12 | } 13 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | bundle: false, 5 | entry: { 6 | index: "src/index.ts", 7 | abis: "src/abis.ts", 8 | deployments: "src/deployments.ts", 9 | }, 10 | clean: true, 11 | sourcemap: false, 12 | dts: true, 13 | minifyWhitespace: true, 14 | format: ["esm", "cjs"], 15 | outDir: "dist", 16 | outExtension: ({ format }) => (format === "cjs" ? { js: ".cjs" } : { js: ".js" }), 17 | }); 18 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "extends": ["next/core-web-vitals", "plugin:prettier/recommended", "plugin:@typescript-eslint/recommended"], 4 | "rules": { 5 | "@typescript-eslint/no-unused-vars": ["error"], 6 | "@typescript-eslint/no-explicit-any": ["off"], 7 | "@typescript-eslint/ban-ts-comment": ["off"], 8 | "prettier/prettier": [ 9 | "warn", 10 | { 11 | "endOfLine": "auto" 12 | } 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | "module": "ESNext", 5 | "target": "ES2020", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "removeComments": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationAppFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {AppFactory} from "lens-modules/contracts/extensions/factories/AppFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationAppFactory is AppFactory, EventEmitter { 9 | constructor(address beacon, address lock) AppFactory(beacon, lock) {} 10 | } 11 | -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationAccountFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {AccountFactory} from "lens-modules/contracts/extensions/factories/AccountFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationAccountFactory is AccountFactory, EventEmitter { 9 | constructor(address beacon, address lock) AccountFactory(beacon, lock) {} 10 | } 11 | -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationAccessControlFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {AccessControlFactory} from "lens-modules/contracts/extensions/factories/AccessControlFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationAccessControlFactory is AccessControlFactory, EventEmitter { 9 | constructor(address lock) AccessControlFactory(lock) {} 10 | } 11 | -------------------------------------------------------------------------------- /abis/PrimitiveFactory.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "primitiveBeacon", 7 | "type": "address", 8 | "internalType": "address" 9 | }, 10 | { 11 | "name": "proxyAdminLock", 12 | "type": "address", 13 | "internalType": "address" 14 | }, 15 | { 16 | "name": "lensFactory", 17 | "type": "address", 18 | "internalType": "address" 19 | } 20 | ], 21 | "stateMutability": "nonpayable" 22 | } 23 | ] -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationFeedFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {FeedFactory} from "lens-modules/contracts/extensions/factories/FeedFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationFeedFactory is FeedFactory, EventEmitter { 9 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 10 | FeedFactory(primitiveBeacon, proxyAdminLock, lensFactory) 11 | {} 12 | } 13 | -------------------------------------------------------------------------------- /abis/IOwnable.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "owner", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "address" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "transferOwnership", 18 | "inputs": [ 19 | { 20 | "name": "newOwner", 21 | "type": "address", 22 | "internalType": "address" 23 | } 24 | ], 25 | "outputs": [], 26 | "stateMutability": "nonpayable" 27 | } 28 | ] -------------------------------------------------------------------------------- /abis/Query.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "IS_SCRIPT", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "bool", 10 | "internalType": "bool" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "run", 18 | "inputs": [], 19 | "outputs": [], 20 | "stateMutability": "view" 21 | }, 22 | { 23 | "type": "function", 24 | "name": "testQuery", 25 | "inputs": [], 26 | "outputs": [], 27 | "stateMutability": "nonpayable" 28 | } 29 | ] -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationGraphFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {GraphFactory} from "lens-modules/contracts/extensions/factories/GraphFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationGraphFactory is GraphFactory, EventEmitter { 9 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 10 | GraphFactory(primitiveBeacon, proxyAdminLock, lensFactory) 11 | {} 12 | } 13 | -------------------------------------------------------------------------------- /abis/IMetadataBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getMetadataURI", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string", 10 | "internalType": "string" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "setMetadataURI", 18 | "inputs": [ 19 | { 20 | "name": "metadata", 21 | "type": "string", 22 | "internalType": "string" 23 | } 24 | ], 25 | "outputs": [], 26 | "stateMutability": "nonpayable" 27 | } 28 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IRequestBasedGroupRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IGroupRule} from "lens-modules/contracts/core/interfaces/IGroupRule.sol"; 6 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 7 | 8 | interface IRequestBasedGroupRule is IGroupRule { 9 | function sendMembershipRequest(bytes32 configSalt, address group, KeyValue[] calldata params) external; 10 | 11 | function cancelMembershipRequest(bytes32 configSalt, address group, KeyValue[] calldata params) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationNamespaceFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {NamespaceFactory} from "lens-modules/contracts/extensions/factories/NamespaceFactory.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | 8 | contract MigrationNamespaceFactory is NamespaceFactory, EventEmitter { 9 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 10 | NamespaceFactory(primitiveBeacon, proxyAdminLock, lensFactory) 11 | {} 12 | } 13 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IFollowRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface IFollowRule { 8 | function configure(bytes32 configSalt, address account, KeyValue[] calldata ruleParams) external; 9 | 10 | function processFollow( 11 | bytes32 configSalt, 12 | address originalMsgSender, 13 | address followerAccount, 14 | address accountToFollow, 15 | KeyValue[] calldata primitiveParams, 16 | KeyValue[] calldata ruleParams 17 | ) external; 18 | } 19 | -------------------------------------------------------------------------------- /contracts/actions/post/collect/IERC7572.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | // As appears in https://eips.ethereum.org/EIPS/eip-7572 4 | 5 | pragma solidity ^0.8.26; 6 | 7 | /** 8 | * This specification standardizes contractURI() to return contract-level metadata. This is useful for dapps and 9 | * offchain indexers to show rich information about a contract, such as its name, description and image, without 10 | * specifying it manually or individually for each dapp. 11 | */ 12 | interface IERC7572 { 13 | function contractURI() external view returns (string memory); 14 | 15 | event ContractURIUpdated(); 16 | } 17 | -------------------------------------------------------------------------------- /abis/ILensNativePaymentHelper.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "refundNative", 5 | "inputs": [ 6 | { 7 | "name": "to", 8 | "type": "address", 9 | "internalType": "address" 10 | } 11 | ], 12 | "outputs": [], 13 | "stateMutability": "nonpayable" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "transferNative", 18 | "inputs": [ 19 | { 20 | "name": "to", 21 | "type": "address", 22 | "internalType": "address" 23 | }, 24 | { 25 | "name": "amount", 26 | "type": "uint256", 27 | "internalType": "uint256" 28 | } 29 | ], 30 | "outputs": [], 31 | "stateMutability": "nonpayable" 32 | } 33 | ] -------------------------------------------------------------------------------- /abis/IVersionedBeacon.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "implementation", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "address" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "implementation", 18 | "inputs": [ 19 | { 20 | "name": "implementationVersion", 21 | "type": "uint256", 22 | "internalType": "uint256" 23 | } 24 | ], 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "address", 29 | "internalType": "address" 30 | } 31 | ], 32 | "stateMutability": "view" 33 | } 34 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IERC4906Events.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | library IERC4906Events { 6 | /// @dev This event emits when the metadata of a token is changed. 7 | /// So that the third-party platforms such as NFT market could 8 | /// timely update the images and related attributes of the NFT. 9 | event MetadataUpdate(uint256 _tokenId); 10 | 11 | /// @dev This event emits when the metadata of a range of tokens is changed. 12 | /// So that the third-party platforms such as NFT market could 13 | /// timely update the images and related attributes of the NFTs. 14 | event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); 15 | } 16 | -------------------------------------------------------------------------------- /abis/IERC4906Events.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "BatchMetadataUpdate", 5 | "inputs": [ 6 | { 7 | "name": "_fromTokenId", 8 | "type": "uint256", 9 | "indexed": false, 10 | "internalType": "uint256" 11 | }, 12 | { 13 | "name": "_toTokenId", 14 | "type": "uint256", 15 | "indexed": false, 16 | "internalType": "uint256" 17 | } 18 | ], 19 | "anonymous": false 20 | }, 21 | { 22 | "type": "event", 23 | "name": "MetadataUpdate", 24 | "inputs": [ 25 | { 26 | "name": "_tokenId", 27 | "type": "uint256", 28 | "indexed": false, 29 | "internalType": "uint256" 30 | } 31 | ], 32 | "anonymous": false 33 | } 34 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IERC721Namespace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 6 | import {INamespace} from "lens-modules/contracts/core/interfaces/INamespace.sol"; 7 | 8 | interface IERC721Namespace is INamespace, IERC721 { 9 | event Lens_Username_Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 10 | 11 | function exists(uint256 tokenId) external view returns (bool); 12 | 13 | function getTokenIdByUsername(string calldata username) external view returns (uint256); 14 | 15 | function getUsernameByTokenId(uint256 tokenId) external view returns (string memory); 16 | } 17 | -------------------------------------------------------------------------------- /abis/ERC721Holder.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC721Received", 5 | "inputs": [ 6 | { 7 | "name": "", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "", 18 | "type": "uint256", 19 | "internalType": "uint256" 20 | }, 21 | { 22 | "name": "", 23 | "type": "bytes", 24 | "internalType": "bytes" 25 | } 26 | ], 27 | "outputs": [ 28 | { 29 | "name": "", 30 | "type": "bytes4", 31 | "internalType": "bytes4" 32 | } 33 | ], 34 | "stateMutability": "nonpayable" 35 | } 36 | ] -------------------------------------------------------------------------------- /abis/IERC721Receiver.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC721Received", 5 | "inputs": [ 6 | { 7 | "name": "operator", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "from", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "tokenId", 18 | "type": "uint256", 19 | "internalType": "uint256" 20 | }, 21 | { 22 | "name": "data", 23 | "type": "bytes", 24 | "internalType": "bytes" 25 | } 26 | ], 27 | "outputs": [ 28 | { 29 | "name": "", 30 | "type": "bytes4", 31 | "internalType": "bytes4" 32 | } 33 | ], 34 | "stateMutability": "nonpayable" 35 | } 36 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IVersionedBeacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface IVersionedBeacon { 6 | /** 7 | * @dev Returns the default implementation held by the Beacon. Usually this will be the latest or the most 8 | * stable version. 9 | * @return Address of the implementation. 10 | */ 11 | function implementation() external view returns (address); 12 | 13 | /** 14 | * @dev Returns the implementation that corresponds to the requested version. 15 | * @param implementationVersion Version of the implementation to return. 16 | * @return Address of the implementation. 17 | */ 18 | function implementation(uint256 implementationVersion) external view returns (address); 19 | } 20 | -------------------------------------------------------------------------------- /abis/IERC721ReceiverUpgradeable.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC721Received", 5 | "inputs": [ 6 | { 7 | "name": "operator", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "from", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "tokenId", 18 | "type": "uint256", 19 | "internalType": "uint256" 20 | }, 21 | { 22 | "name": "data", 23 | "type": "bytes", 24 | "internalType": "bytes" 25 | } 26 | ], 27 | "outputs": [ 28 | { 29 | "name": "", 30 | "type": "bytes4", 31 | "internalType": "bytes4" 32 | } 33 | ], 34 | "stateMutability": "nonpayable" 35 | } 36 | ] -------------------------------------------------------------------------------- /abis/IERC721TokenReceiver.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC721Received", 5 | "inputs": [ 6 | { 7 | "name": "_operator", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "_from", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "_tokenId", 18 | "type": "uint256", 19 | "internalType": "uint256" 20 | }, 21 | { 22 | "name": "_data", 23 | "type": "bytes", 24 | "internalType": "bytes" 25 | } 26 | ], 27 | "outputs": [ 28 | { 29 | "name": "", 30 | "type": "bytes4", 31 | "internalType": "bytes4" 32 | } 33 | ], 34 | "stateMutability": "nonpayable" 35 | } 36 | ] -------------------------------------------------------------------------------- /contracts/core/libraries/KeyValueLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "../types/Types.sol"; 6 | 7 | library KeyValueLib { 8 | // TODO: Replace for an optimized version later. Copying chunks of calldata into memory directly. 9 | function concat(KeyValue[] calldata start, KeyValue[] calldata end) internal pure returns (KeyValue[] memory) { 10 | KeyValue[] memory concatenated = new KeyValue[](start.length + end.length); 11 | for (uint256 i = 0; i < start.length; i++) { 12 | concatenated[i] = start[i]; 13 | } 14 | for (uint256 i = 0; i < end.length; i++) { 15 | concatenated[start.length + i] = end[i]; 16 | } 17 | return concatenated; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wagmi.config.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs/promises"; 2 | import path from "path"; 3 | import { fileURLToPath } from "url"; 4 | import type { Abi } from "viem"; 5 | import type { Config } from "@wagmi/cli"; 6 | 7 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 8 | const abiDir = path.resolve(__dirname, "./abis"); 9 | 10 | const files = await fs.readdir(abiDir); 11 | const contracts = await Promise.all( 12 | files 13 | .filter(file => file.endsWith(".abi.json")) 14 | .map(async file => { 15 | const name = path.basename(file, ".abi.json"); 16 | const json = await fs.readFile(path.join(abiDir, file), "utf8"); 17 | const abi = JSON.parse(json) as Abi; 18 | return { name, abi }; 19 | }), 20 | ); 21 | 22 | const config: Config = { 23 | out: "src/abis.ts", 24 | contracts, 25 | }; 26 | 27 | export default config; 28 | -------------------------------------------------------------------------------- /contracts/core/types/Constants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | // 100.00% represented as Basis Points, each Basis Point is 0.01% 6 | uint256 constant BPS_MAX = 10_000; 7 | 8 | uint256 constant SELECTOR_BYTE_LENGTH = 4; 9 | 10 | /// @custom:keccak lens.contract.ActionHub 11 | bytes32 constant CONTRACT__ACTION_HUB = 0x914706a68d66e273351f2cd4c1f0c739a3d2d211eb45a40f548eb964a6081fef; 12 | 13 | /// @custom:keccak lens.contract.LensFees 14 | bytes32 constant CONTRACT__LENS_FEES = 0x5072b519d346fa8b5598f9e3ddfc010379305b352a80b2bc6c119eb92ac9a520; 15 | 16 | /// @custom:keccak lens.contract.LensNativePaymentHelper 17 | bytes32 constant CONTRACT__LENS_NATIVE_PAYMENT_HELPER = 18 | 0x4181add33551df9049a16e8f6b64e891696eba958d766672bd32e1d3bf635636; 19 | 20 | address constant NATIVE_TOKEN = address(0x800A); 21 | -------------------------------------------------------------------------------- /abis/Events.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "Lens_Contract_Deployed", 5 | "inputs": [ 6 | { 7 | "name": "contractType", 8 | "type": "string", 9 | "indexed": false, 10 | "internalType": "string" 11 | }, 12 | { 13 | "name": "flavour", 14 | "type": "string", 15 | "indexed": false, 16 | "internalType": "string" 17 | } 18 | ], 19 | "anonymous": false 20 | }, 21 | { 22 | "type": "event", 23 | "name": "Lens_PermissionId_Available", 24 | "inputs": [ 25 | { 26 | "name": "permissionId", 27 | "type": "uint256", 28 | "indexed": true, 29 | "internalType": "uint256" 30 | }, 31 | { 32 | "name": "name", 33 | "type": "string", 34 | "indexed": false, 35 | "internalType": "string" 36 | } 37 | ], 38 | "anonymous": false 39 | } 40 | ] -------------------------------------------------------------------------------- /abis/ExtraDataBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "Lens_ExtraStorageSet", 5 | "inputs": [ 6 | { 7 | "name": "addressScope", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "entityType", 14 | "type": "uint256", 15 | "indexed": true, 16 | "internalType": "uint256" 17 | }, 18 | { 19 | "name": "entityId", 20 | "type": "uint256", 21 | "indexed": true, 22 | "internalType": "uint256" 23 | }, 24 | { 25 | "name": "key", 26 | "type": "bytes32", 27 | "indexed": true, 28 | "internalType": "bytes32" 29 | }, 30 | { 31 | "name": "value", 32 | "type": "bytes", 33 | "indexed": false, 34 | "internalType": "bytes" 35 | } 36 | ], 37 | "anonymous": false 38 | } 39 | ] -------------------------------------------------------------------------------- /abis/ExtraStorageBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "Lens_ExtraStorageSet", 5 | "inputs": [ 6 | { 7 | "name": "addressScope", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "entityType", 14 | "type": "uint256", 15 | "indexed": true, 16 | "internalType": "uint256" 17 | }, 18 | { 19 | "name": "entityId", 20 | "type": "uint256", 21 | "indexed": true, 22 | "internalType": "uint256" 23 | }, 24 | { 25 | "name": "key", 26 | "type": "bytes32", 27 | "indexed": true, 28 | "internalType": "bytes32" 29 | }, 30 | { 31 | "name": "value", 32 | "type": "bytes", 33 | "indexed": false, 34 | "internalType": "bytes" 35 | } 36 | ], 37 | "anonymous": false 38 | } 39 | ] -------------------------------------------------------------------------------- /abis/SourceStampBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "Lens_ExtraStorageSet", 5 | "inputs": [ 6 | { 7 | "name": "addressScope", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "entityType", 14 | "type": "uint256", 15 | "indexed": true, 16 | "internalType": "uint256" 17 | }, 18 | { 19 | "name": "entityId", 20 | "type": "uint256", 21 | "indexed": true, 22 | "internalType": "uint256" 23 | }, 24 | { 25 | "name": "key", 26 | "type": "bytes32", 27 | "indexed": true, 28 | "internalType": "bytes32" 29 | }, 30 | { 31 | "name": "value", 32 | "type": "bytes", 33 | "indexed": false, 34 | "internalType": "bytes" 35 | } 36 | ], 37 | "anonymous": false 38 | } 39 | ] -------------------------------------------------------------------------------- /abis/EntityExtraDataBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "Lens_ExtraStorageSet", 5 | "inputs": [ 6 | { 7 | "name": "addressScope", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "entityType", 14 | "type": "uint256", 15 | "indexed": true, 16 | "internalType": "uint256" 17 | }, 18 | { 19 | "name": "entityId", 20 | "type": "uint256", 21 | "indexed": true, 22 | "internalType": "uint256" 23 | }, 24 | { 25 | "name": "key", 26 | "type": "bytes32", 27 | "indexed": true, 28 | "internalType": "bytes32" 29 | }, 30 | { 31 | "name": "value", 32 | "type": "bytes", 33 | "indexed": false, 34 | "internalType": "bytes" 35 | } 36 | ], 37 | "anonymous": false 38 | } 39 | ] -------------------------------------------------------------------------------- /abis/LensNativePaymentHelper.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "receive", 4 | "stateMutability": "payable" 5 | }, 6 | { 7 | "type": "function", 8 | "name": "refundNative", 9 | "inputs": [ 10 | { 11 | "name": "to", 12 | "type": "address", 13 | "internalType": "address" 14 | } 15 | ], 16 | "outputs": [], 17 | "stateMutability": "nonpayable" 18 | }, 19 | { 20 | "type": "function", 21 | "name": "transferNative", 22 | "inputs": [ 23 | { 24 | "name": "to", 25 | "type": "address", 26 | "internalType": "address" 27 | }, 28 | { 29 | "name": "amount", 30 | "type": "uint256", 31 | "internalType": "uint256" 32 | } 33 | ], 34 | "outputs": [], 35 | "stateMutability": "nonpayable" 36 | }, 37 | { 38 | "type": "error", 39 | "name": "FailedToTransferNative", 40 | "inputs": [] 41 | }, 42 | { 43 | "type": "error", 44 | "name": "NotEnoughBalance", 45 | "inputs": [] 46 | } 47 | ] -------------------------------------------------------------------------------- /abis/IAccountGroupAdditionSettings.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "canBeAddedToGroup", 5 | "inputs": [ 6 | { 7 | "name": "group", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "addedBy", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "params", 18 | "type": "tuple[]", 19 | "internalType": "struct KeyValue[]", 20 | "components": [ 21 | { 22 | "name": "key", 23 | "type": "bytes32", 24 | "internalType": "bytes32" 25 | }, 26 | { 27 | "name": "value", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ] 32 | } 33 | ], 34 | "outputs": [ 35 | { 36 | "name": "", 37 | "type": "bool", 38 | "internalType": "bool" 39 | } 40 | ], 41 | "stateMutability": "view" 42 | } 43 | ] -------------------------------------------------------------------------------- /abis/IERC1967.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "AdminChanged", 5 | "inputs": [ 6 | { 7 | "name": "previousAdmin", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "newAdmin", 14 | "type": "address", 15 | "indexed": false, 16 | "internalType": "address" 17 | } 18 | ], 19 | "anonymous": false 20 | }, 21 | { 22 | "type": "event", 23 | "name": "BeaconUpgraded", 24 | "inputs": [ 25 | { 26 | "name": "beacon", 27 | "type": "address", 28 | "indexed": true, 29 | "internalType": "address" 30 | } 31 | ], 32 | "anonymous": false 33 | }, 34 | { 35 | "type": "event", 36 | "name": "Upgraded", 37 | "inputs": [ 38 | { 39 | "name": "implementation", 40 | "type": "address", 41 | "indexed": true, 42 | "internalType": "address" 43 | } 44 | ], 45 | "anonymous": false 46 | } 47 | ] -------------------------------------------------------------------------------- /abis/ERC1967Upgrade.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "event", 4 | "name": "AdminChanged", 5 | "inputs": [ 6 | { 7 | "name": "previousAdmin", 8 | "type": "address", 9 | "indexed": false, 10 | "internalType": "address" 11 | }, 12 | { 13 | "name": "newAdmin", 14 | "type": "address", 15 | "indexed": false, 16 | "internalType": "address" 17 | } 18 | ], 19 | "anonymous": false 20 | }, 21 | { 22 | "type": "event", 23 | "name": "BeaconUpgraded", 24 | "inputs": [ 25 | { 26 | "name": "beacon", 27 | "type": "address", 28 | "indexed": true, 29 | "internalType": "address" 30 | } 31 | ], 32 | "anonymous": false 33 | }, 34 | { 35 | "type": "event", 36 | "name": "Upgraded", 37 | "inputs": [ 38 | { 39 | "name": "implementation", 40 | "type": "address", 41 | "indexed": true, 42 | "internalType": "address" 43 | } 44 | ], 45 | "anonymous": false 46 | } 47 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IPostRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {CreatePostParams, EditPostParams} from "lens-modules/contracts/core/interfaces/IFeed.sol"; 6 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 7 | 8 | interface IPostRule { 9 | function configure(bytes32 configSalt, uint256 postId, KeyValue[] calldata ruleParams) external; 10 | 11 | function processCreatePost( 12 | bytes32 configSalt, 13 | uint256 rootPostId, 14 | uint256 postId, 15 | CreatePostParams calldata postParams, 16 | KeyValue[] calldata primitiveParams, 17 | KeyValue[] calldata ruleParams 18 | ) external; 19 | 20 | function processEditPost( 21 | bytes32 configSalt, 22 | uint256 rootPostId, 23 | uint256 postId, 24 | EditPostParams calldata postParams, 25 | KeyValue[] calldata primitiveParams, 26 | KeyValue[] calldata ruleParams 27 | ) external; 28 | } 29 | -------------------------------------------------------------------------------- /contracts/extensions/access/PermissionlessAccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | 7 | contract PermissionlessAccessControl is IAccessControl { 8 | /// @custom:keccak lens.contract.AccessControl.PermissionlessAccessControl 9 | bytes32 constant CONTRACT_TYPE = 0xb5440aae9cc7331e30d1f5f4d93e4b545e210d2a6887783d935991d99a3c4dae; 10 | 11 | function getType() external pure returns (bytes32) { 12 | return CONTRACT_TYPE; 13 | } 14 | 15 | function canChangeAccessControl(address, /* account */ address /* contractAddress */ ) 16 | external 17 | pure 18 | returns (bool) 19 | { 20 | return true; 21 | } 22 | 23 | function hasAccess(address, /* account */ address, /* contractAddress */ uint256 /* permissionId */ ) 24 | external 25 | pure 26 | returns (bool) 27 | { 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /contracts/core/upgradeability/Initializable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | 7 | abstract contract Initializable { 8 | // Storage 9 | 10 | struct InitializableStorage { 11 | bool initialized; 12 | } 13 | 14 | /// @custom:keccak lens.storage.Initializable 15 | bytes32 constant STORAGE__INITIALIZABLE = 0xbd2c04feebbff2d29fe1b04edf9a1d94ba7a836bad797bdd99c9e722e172cdd0; 16 | 17 | function $initializableStorage() internal pure returns (InitializableStorage storage _storage) { 18 | assembly { 19 | _storage.slot := STORAGE__INITIALIZABLE 20 | } 21 | } 22 | 23 | modifier initializer() { 24 | require(!$initializableStorage().initialized, Errors.AlreadyInitialized()); 25 | $initializableStorage().initialized = true; 26 | _; 27 | } 28 | 29 | function _disableInitializers() internal virtual { 30 | $initializableStorage().initialized = true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /abis/MetadataBased.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getMetadataURI", 5 | "inputs": [ 6 | { 7 | "name": "source", 8 | "type": "address", 9 | "internalType": "address" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "string", 16 | "internalType": "string" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | }, 21 | { 22 | "type": "function", 23 | "name": "getMetadataURI", 24 | "inputs": [], 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "string", 29 | "internalType": "string" 30 | } 31 | ], 32 | "stateMutability": "view" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "setMetadataURI", 37 | "inputs": [ 38 | { 39 | "name": "metadataURI", 40 | "type": "string", 41 | "internalType": "string" 42 | } 43 | ], 44 | "outputs": [], 45 | "stateMutability": "nonpayable" 46 | }, 47 | { 48 | "type": "error", 49 | "name": "NotImplemented", 50 | "inputs": [] 51 | } 52 | ] -------------------------------------------------------------------------------- /contracts/rules/base/OwnableMetadataBasedRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol"; 6 | import {MetadataBased} from "lens-modules/contracts/core/base/MetadataBased.sol"; 7 | 8 | abstract contract OwnableMetadataBasedRule is Ownable, MetadataBased { 9 | event Lens_Rule_MetadataURISet(string metadataURI); 10 | 11 | constructor(address owner, string memory metadataURI) { 12 | _transferOwnership(owner); 13 | _setMetadataURI(metadataURI); 14 | } 15 | 16 | function _initialize(address owner, string memory metadataURI) internal virtual { 17 | _transferOwnership(owner); 18 | _setMetadataURI(metadataURI); 19 | } 20 | 21 | function _emitMetadataURISet(string memory metadataURI, address /* source */ ) internal virtual override { 22 | emit Lens_Rule_MetadataURISet(metadataURI); 23 | } 24 | 25 | function _beforeMetadataURIUpdate(string memory /* metadataURI */ ) internal virtual override onlyOwner { 26 | return; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /abis/Ownable.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "owner", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "address" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "transferOwnership", 18 | "inputs": [ 19 | { 20 | "name": "newOwner", 21 | "type": "address", 22 | "internalType": "address" 23 | } 24 | ], 25 | "outputs": [], 26 | "stateMutability": "nonpayable" 27 | }, 28 | { 29 | "type": "event", 30 | "name": "Lens_Ownable_OwnershipTransferred", 31 | "inputs": [ 32 | { 33 | "name": "previousOwner", 34 | "type": "address", 35 | "indexed": true, 36 | "internalType": "address" 37 | }, 38 | { 39 | "name": "newOwner", 40 | "type": "address", 41 | "indexed": true, 42 | "internalType": "address" 43 | } 44 | ], 45 | "anonymous": false 46 | }, 47 | { 48 | "type": "error", 49 | "name": "InvalidMsgSender", 50 | "inputs": [] 51 | } 52 | ] -------------------------------------------------------------------------------- /contracts/extensions/factories/PrimitiveFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {PermissionlessAccessControl} from "lens-modules/contracts/extensions/access/PermissionlessAccessControl.sol"; 7 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 8 | 9 | contract PrimitiveFactory { 10 | IAccessControl internal immutable TEMPORARY_ACCESS_CONTROL; 11 | address internal immutable PRIMITIVE_BEACON; 12 | address internal immutable PROXY_ADMIN_LOCK; 13 | 14 | address internal immutable LENS_FACTORY; 15 | 16 | modifier onlyLensFactory() { 17 | require(msg.sender == LENS_FACTORY, Errors.AccessDenied()); 18 | _; 19 | } 20 | 21 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) { 22 | TEMPORARY_ACCESS_CONTROL = new PermissionlessAccessControl(); 23 | PRIMITIVE_BEACON = primitiveBeacon; 24 | PROXY_ADMIN_LOCK = proxyAdminLock; 25 | LENS_FACTORY = lensFactory; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IGraphRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue, RuleChange} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface IGraphRule { 8 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external; 9 | 10 | function processFollow( 11 | bytes32 configSalt, 12 | address originalMsgSender, 13 | address followerAccount, 14 | address accountToFollow, 15 | KeyValue[] calldata primitiveParams, 16 | KeyValue[] calldata ruleParams 17 | ) external; 18 | 19 | function processUnfollow( 20 | bytes32 configSalt, 21 | address originalMsgSender, 22 | address followerAccount, 23 | address accountToUnfollow, 24 | KeyValue[] calldata primitiveParams, 25 | KeyValue[] calldata ruleParams 26 | ) external; 27 | 28 | function processFollowRuleChanges( 29 | bytes32 configSalt, 30 | address account, 31 | RuleChange[] calldata ruleChanges, 32 | KeyValue[] calldata ruleParams 33 | ) external; 34 | } 35 | -------------------------------------------------------------------------------- /abis/ILensFees.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getLensFeesData", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "tuple", 10 | "internalType": "struct LensFeesData", 11 | "components": [ 12 | { 13 | "name": "treasuryAddress", 14 | "type": "address", 15 | "internalType": "address" 16 | }, 17 | { 18 | "name": "treasuryFeeBps", 19 | "type": "uint16", 20 | "internalType": "uint16" 21 | } 22 | ] 23 | } 24 | ], 25 | "stateMutability": "view" 26 | }, 27 | { 28 | "type": "function", 29 | "name": "getTreasuryAddress", 30 | "inputs": [], 31 | "outputs": [ 32 | { 33 | "name": "", 34 | "type": "address", 35 | "internalType": "address" 36 | } 37 | ], 38 | "stateMutability": "view" 39 | }, 40 | { 41 | "type": "function", 42 | "name": "getTreasuryFeeBps", 43 | "inputs": [], 44 | "outputs": [ 45 | { 46 | "name": "", 47 | "type": "uint16", 48 | "internalType": "uint16" 49 | } 50 | ], 51 | "stateMutability": "view" 52 | } 53 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/IGroupRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface IGroupRule { 8 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external; 9 | 10 | function processAddition( 11 | bytes32 configSalt, 12 | address originalMsgSender, 13 | address account, 14 | KeyValue[] calldata primitiveParams, 15 | KeyValue[] calldata ruleParams 16 | ) external; 17 | 18 | function processRemoval( 19 | bytes32 configSalt, 20 | address originalMsgSender, 21 | address account, 22 | KeyValue[] calldata primitiveParams, 23 | KeyValue[] calldata ruleParams 24 | ) external; 25 | 26 | function processJoining( 27 | bytes32 configSalt, 28 | address account, 29 | KeyValue[] calldata primitiveParams, 30 | KeyValue[] calldata ruleParams 31 | ) external; 32 | 33 | function processLeaving( 34 | bytes32 configSalt, 35 | address account, 36 | KeyValue[] calldata primitiveParams, 37 | KeyValue[] calldata ruleParams 38 | ) external; 39 | } 40 | -------------------------------------------------------------------------------- /contracts/actions/post/base/OwnableMetadataBasedPostAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 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 | 9 | abstract contract OwnableMetadataBasedPostAction is BasePostAction, Ownable, MetadataBased { 10 | event Lens_PostAction_MetadataURISet(string metadataURI); 11 | 12 | constructor(address actionHub, address owner, string memory metadataURI) BasePostAction(actionHub) { 13 | _transferOwnership(owner); 14 | _setMetadataURI(metadataURI); 15 | } 16 | 17 | function _initialize(address owner, string memory metadataURI) internal { 18 | _transferOwnership(owner); 19 | _setMetadataURI(metadataURI); 20 | } 21 | 22 | function _emitMetadataURISet(string memory metadataURI, address /* source */ ) internal virtual override { 23 | emit Lens_PostAction_MetadataURISet(metadataURI); 24 | } 25 | 26 | function _beforeMetadataURIUpdate(string memory /* metadataURI */ ) internal virtual override onlyOwner { 27 | return; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/extensions/fees/LensFees.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | struct LensFeesData { 6 | address treasuryAddress; 7 | uint16 treasuryFeeBps; 8 | } 9 | 10 | interface ILensFees { 11 | function getTreasuryAddress() external view returns (address); 12 | 13 | function getTreasuryFeeBps() external view returns (uint16); 14 | 15 | function getLensFeesData() external view returns (LensFeesData memory); 16 | } 17 | 18 | contract LensFees is ILensFees { 19 | address internal immutable LENS_TREASURY_ADDRESS; 20 | uint16 internal immutable LENS_TREASURY_FEE_BPS; 21 | 22 | constructor(address treasuryAddress, uint16 treasuryFeeBps) { 23 | LENS_TREASURY_ADDRESS = treasuryAddress; 24 | LENS_TREASURY_FEE_BPS = treasuryFeeBps; 25 | } 26 | 27 | function getTreasuryAddress() external view override returns (address) { 28 | return LENS_TREASURY_ADDRESS; 29 | } 30 | 31 | function getTreasuryFeeBps() external view override returns (uint16) { 32 | return LENS_TREASURY_FEE_BPS; 33 | } 34 | 35 | function getLensFeesData() external view override returns (LensFeesData memory) { 36 | return LensFeesData(LENS_TREASURY_ADDRESS, LENS_TREASURY_FEE_BPS); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IAccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | interface IAccessControl { 6 | /** 7 | * Returns the implementation type of the access control. 8 | */ 9 | function getType() external view returns (bytes32); 10 | 11 | /** 12 | * Returns true if the account is allowed to change the access control in the given contract address, false if not. 13 | * 14 | * @param account The account to check if is allowed to change the access control. 15 | * @param contractAddress The address where the access control is being changed. 16 | */ 17 | function canChangeAccessControl(address account, address contractAddress) external view returns (bool); 18 | 19 | /** 20 | * Returns true if the account has granted access to the specified permission, false otherwise. 21 | * This function MUST NOT revert. Instead, return false. 22 | * 23 | * @param account The account to check if has access to a permission. 24 | * @param contractAddress The address where the permission is queried. 25 | * @param permissionId The ID of the permission. 26 | */ 27 | function hasAccess(address account, address contractAddress, uint256 permissionId) external view returns (bool); 28 | } 29 | -------------------------------------------------------------------------------- /abis/AccessControlFactory.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "lock", 7 | "type": "address", 8 | "internalType": "address" 9 | } 10 | ], 11 | "stateMutability": "nonpayable" 12 | }, 13 | { 14 | "type": "function", 15 | "name": "deployOwnerAdminOnlyAccessControl", 16 | "inputs": [ 17 | { 18 | "name": "owner", 19 | "type": "address", 20 | "internalType": "address" 21 | }, 22 | { 23 | "name": "admins", 24 | "type": "address[]", 25 | "internalType": "address[]" 26 | } 27 | ], 28 | "outputs": [ 29 | { 30 | "name": "", 31 | "type": "address", 32 | "internalType": "contract IRoleBasedAccessControl" 33 | } 34 | ], 35 | "stateMutability": "nonpayable" 36 | }, 37 | { 38 | "type": "event", 39 | "name": "Lens_AccessControlFactory_OwnerAdminDeployment", 40 | "inputs": [ 41 | { 42 | "name": "accessControl", 43 | "type": "address", 44 | "indexed": true, 45 | "internalType": "address" 46 | }, 47 | { 48 | "name": "owner", 49 | "type": "address", 50 | "indexed": false, 51 | "internalType": "address" 52 | } 53 | ], 54 | "anonymous": false 55 | } 56 | ] -------------------------------------------------------------------------------- /abis/TrustBasedRule.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "setTrust", 5 | "inputs": [ 6 | { 7 | "name": "target", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "isTrusted", 13 | "type": "bool", 14 | "internalType": "bool" 15 | } 16 | ], 17 | "outputs": [], 18 | "stateMutability": "nonpayable" 19 | }, 20 | { 21 | "type": "event", 22 | "name": "Lens_Rule_Trusted", 23 | "inputs": [ 24 | { 25 | "name": "account", 26 | "type": "address", 27 | "indexed": true, 28 | "internalType": "address" 29 | }, 30 | { 31 | "name": "trustedAddress", 32 | "type": "address", 33 | "indexed": true, 34 | "internalType": "address" 35 | } 36 | ], 37 | "anonymous": false 38 | }, 39 | { 40 | "type": "event", 41 | "name": "Lens_Rule_Untrusted", 42 | "inputs": [ 43 | { 44 | "name": "account", 45 | "type": "address", 46 | "indexed": true, 47 | "internalType": "address" 48 | }, 49 | { 50 | "name": "untrustedAddress", 51 | "type": "address", 52 | "indexed": true, 53 | "internalType": "address" 54 | } 55 | ], 56 | "anonymous": false 57 | } 58 | ] -------------------------------------------------------------------------------- /contracts/actions/account/base/OwnableMetadataBasedAccountAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 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 | 9 | abstract contract OwnableMetadataBasedAccountAction is BaseAccountAction, Ownable, MetadataBased { 10 | event Lens_AccountAction_MetadataURISet(string metadataURI); 11 | 12 | constructor(address actionHub, address owner, string memory metadataURI) BaseAccountAction(actionHub) { 13 | _transferOwnership(owner); 14 | _setMetadataURI(metadataURI); 15 | } 16 | 17 | function _initialize(address owner, string memory metadataURI) internal { 18 | _transferOwnership(owner); 19 | _setMetadataURI(metadataURI); 20 | } 21 | 22 | function _emitMetadataURISet(string memory metadataURI, address /* source */ ) internal virtual override { 23 | emit Lens_AccountAction_MetadataURISet(metadataURI); 24 | } 25 | 26 | function _beforeMetadataURIUpdate(string memory /* metadataURI */ ) internal virtual override onlyOwner { 27 | return; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/core/types/Types.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | struct KeyValue { 6 | bytes32 key; 7 | bytes value; 8 | } 9 | 10 | struct Rule { 11 | address ruleAddress; 12 | bytes32 configSalt; 13 | } 14 | 15 | struct RuleChange { 16 | address ruleAddress; 17 | bytes32 configSalt; 18 | RuleConfigurationChange configurationChanges; 19 | RuleSelectorChange[] selectorChanges; 20 | } 21 | 22 | struct RuleConfigurationChange { 23 | bool configure; 24 | KeyValue[] ruleParams; 25 | } 26 | 27 | struct RuleSelectorChange { 28 | bytes4 ruleSelector; 29 | bool isRequired; 30 | bool enabled; 31 | } 32 | 33 | struct RuleProcessingParams { 34 | address ruleAddress; 35 | bytes32 configSalt; 36 | KeyValue[] ruleParams; 37 | } 38 | 39 | struct SourceStamp { 40 | address source; 41 | address originalMsgSender; // Who called the validator to execute some action with a source (e.g. Account) 42 | address validator; // Who is calling the source to validate the source stamp (e.g. Lens Primitives) 43 | uint256 nonce; 44 | uint256 deadline; 45 | bytes signature; 46 | } 47 | 48 | struct RecipientData { 49 | address recipient; 50 | uint16 splitBps; // In Basis Points, each Basis Point represents 0.01% 51 | } 52 | -------------------------------------------------------------------------------- /contracts/actions/base/BaseAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 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 | 8 | abstract contract BaseAction { 9 | address immutable ACTION_HUB; 10 | 11 | /// @custom:keccak lens.storage.Action.configured 12 | bytes32 constant STORAGE__ACTION_CONFIGURED = 0x852bead036b7ef35b8026346140cc688bafe817a6c3491812e6d994b1bcda6d9; 13 | 14 | modifier onlyActionHub() { 15 | require(msg.sender == ACTION_HUB, Errors.InvalidMsgSender()); 16 | _; 17 | } 18 | 19 | constructor(address actionHub) { 20 | ACTION_HUB = actionHub; 21 | } 22 | 23 | function _configureUniversalAction(address originalMsgSender) internal onlyActionHub returns (bytes memory) { 24 | bool configured; 25 | assembly { 26 | configured := sload(STORAGE__ACTION_CONFIGURED) 27 | } 28 | require(!configured, Errors.RedundantStateChange()); 29 | require(originalMsgSender == address(0), Errors.InvalidParameter()); 30 | assembly { 31 | sstore(STORAGE__ACTION_CONFIGURED, 1) 32 | } 33 | return abi.encode(UNIVERSAL_ACTION_MAGIC_VALUE); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/core/libraries/KeyValueStorageLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | library KeyValueStorageLib { 8 | function set(mapping(bytes32 => bytes) storage _keyValueStorage, KeyValue memory keyValueToSet) 9 | internal 10 | returns (bool) 11 | { 12 | return _setKeyValueToStorage(_keyValueStorage, keyValueToSet); 13 | } 14 | 15 | function set(mapping(bytes32 => bytes) storage _keyValueStorage, KeyValue[] calldata keyValuesToSet) 16 | internal 17 | returns (bool[] memory) 18 | { 19 | bool[] memory werePreviousValuesSet = new bool[](keyValuesToSet.length); 20 | for (uint256 i = 0; i < keyValuesToSet.length; i++) { 21 | werePreviousValuesSet[i] = _setKeyValueToStorage(_keyValueStorage, keyValuesToSet[i]); 22 | } 23 | return werePreviousValuesSet; 24 | } 25 | 26 | function _setKeyValueToStorage(mapping(bytes32 => bytes) storage _keyValueStorage, KeyValue memory keyValueToSet) 27 | internal 28 | returns (bool) 29 | { 30 | bool wasPreviousValueSet = _keyValueStorage[keyValueToSet.key].length != 0; 31 | _keyValueStorage[keyValueToSet.key] = keyValueToSet.value; 32 | return wasPreviousValueSet; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IFeedRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {CreatePostParams, EditPostParams} from "lens-modules/contracts/core/interfaces/IFeed.sol"; 6 | import {KeyValue, RuleChange} from "lens-modules/contracts/core/types/Types.sol"; 7 | 8 | interface IFeedRule { 9 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external; 10 | 11 | function processCreatePost( 12 | bytes32 configSalt, 13 | uint256 postId, 14 | CreatePostParams calldata postParams, 15 | KeyValue[] calldata primitiveParams, 16 | KeyValue[] calldata ruleParams 17 | ) external; 18 | 19 | function processEditPost( 20 | bytes32 configSalt, 21 | uint256 postId, 22 | EditPostParams calldata postParams, 23 | KeyValue[] calldata primitiveParams, 24 | KeyValue[] calldata ruleParams 25 | ) external; 26 | 27 | function processDeletePost( 28 | bytes32 configSalt, 29 | uint256 postId, 30 | KeyValue[] calldata primitiveParams, 31 | KeyValue[] calldata ruleParams 32 | ) external; 33 | 34 | function processPostRuleChanges( 35 | bytes32 configSalt, 36 | uint256 postId, 37 | RuleChange[] calldata ruleChanges, 38 | KeyValue[] calldata ruleParams 39 | ) external; 40 | } 41 | -------------------------------------------------------------------------------- /abis/LensUsernameTokenURIProvider.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [], 5 | "stateMutability": "nonpayable" 6 | }, 7 | { 8 | "type": "function", 9 | "name": "_toLowercase", 10 | "inputs": [ 11 | { 12 | "name": "str", 13 | "type": "string", 14 | "internalType": "string" 15 | } 16 | ], 17 | "outputs": [ 18 | { 19 | "name": "", 20 | "type": "string", 21 | "internalType": "string" 22 | } 23 | ], 24 | "stateMutability": "pure" 25 | }, 26 | { 27 | "type": "function", 28 | "name": "tokenURI", 29 | "inputs": [ 30 | { 31 | "name": "tokenId", 32 | "type": "uint256", 33 | "internalType": "uint256" 34 | } 35 | ], 36 | "outputs": [ 37 | { 38 | "name": "", 39 | "type": "string", 40 | "internalType": "string" 41 | } 42 | ], 43 | "stateMutability": "view" 44 | }, 45 | { 46 | "type": "event", 47 | "name": "Lens_Contract_Deployed", 48 | "inputs": [ 49 | { 50 | "name": "contractType", 51 | "type": "string", 52 | "indexed": false, 53 | "internalType": "string" 54 | }, 55 | { 56 | "name": "flavour", 57 | "type": "string", 58 | "indexed": false, 59 | "internalType": "string" 60 | } 61 | ], 62 | "anonymous": false 63 | } 64 | ] -------------------------------------------------------------------------------- /abis/PermissionlessAccessControl.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "canChangeAccessControl", 5 | "inputs": [ 6 | { 7 | "name": "", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "", 13 | "type": "address", 14 | "internalType": "address" 15 | } 16 | ], 17 | "outputs": [ 18 | { 19 | "name": "", 20 | "type": "bool", 21 | "internalType": "bool" 22 | } 23 | ], 24 | "stateMutability": "pure" 25 | }, 26 | { 27 | "type": "function", 28 | "name": "getType", 29 | "inputs": [], 30 | "outputs": [ 31 | { 32 | "name": "", 33 | "type": "bytes32", 34 | "internalType": "bytes32" 35 | } 36 | ], 37 | "stateMutability": "pure" 38 | }, 39 | { 40 | "type": "function", 41 | "name": "hasAccess", 42 | "inputs": [ 43 | { 44 | "name": "", 45 | "type": "address", 46 | "internalType": "address" 47 | }, 48 | { 49 | "name": "", 50 | "type": "address", 51 | "internalType": "address" 52 | }, 53 | { 54 | "name": "", 55 | "type": "uint256", 56 | "internalType": "uint256" 57 | } 58 | ], 59 | "outputs": [ 60 | { 61 | "name": "", 62 | "type": "bool", 63 | "internalType": "bool" 64 | } 65 | ], 66 | "stateMutability": "pure" 67 | } 68 | ] -------------------------------------------------------------------------------- /contracts/core/interfaces/INamespaceRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 6 | 7 | interface INamespaceRule { 8 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external; 9 | 10 | function processCreation( 11 | bytes32 configSalt, 12 | address originalMsgSender, 13 | address account, 14 | string calldata username, 15 | KeyValue[] calldata primitiveParams, 16 | KeyValue[] calldata ruleParams 17 | ) external; 18 | 19 | function processRemoval( 20 | bytes32 configSalt, 21 | address originalMsgSender, 22 | string calldata username, 23 | KeyValue[] calldata primitiveParams, 24 | KeyValue[] calldata ruleParams 25 | ) external; 26 | 27 | function processAssigning( 28 | bytes32 configSalt, 29 | address originalMsgSender, 30 | address account, 31 | string calldata username, 32 | KeyValue[] calldata primitiveParams, 33 | KeyValue[] calldata ruleParams 34 | ) external; 35 | 36 | function processUnassigning( 37 | bytes32 configSalt, 38 | address originalMsgSender, 39 | address account, 40 | string calldata username, 41 | KeyValue[] calldata primitiveParams, 42 | KeyValue[] calldata ruleParams 43 | ) external; 44 | } 45 | -------------------------------------------------------------------------------- /contracts/core/base/ExtraDataBased.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 5 | import {ExtraStorageBased} from "lens-modules/contracts/core/base/ExtraStorageBased.sol"; 6 | 7 | abstract contract ExtraDataBased is ExtraStorageBased { 8 | function _emitExtraDataAddedEvent(KeyValue calldata extraDataAdded) internal virtual; 9 | 10 | function _emitExtraDataUpdatedEvent(KeyValue calldata extraDataUpdated) internal virtual; 11 | 12 | function _emitExtraDataRemovedEvent(KeyValue calldata extraDataRemoved) internal virtual; 13 | 14 | function _setExtraData(KeyValue[] calldata extraDataToSet) internal { 15 | for (uint256 i = 0; i < extraDataToSet.length; i++) { 16 | bool hadAValueSetBefore = _setExtraStorage_Self(extraDataToSet[i]); 17 | bool isNewValueEmpty = extraDataToSet[i].value.length == 0; 18 | if (hadAValueSetBefore) { 19 | if (isNewValueEmpty) { 20 | _emitExtraDataRemovedEvent(extraDataToSet[i]); 21 | } else { 22 | _emitExtraDataUpdatedEvent(extraDataToSet[i]); 23 | } 24 | } else if (!isNewValueEmpty) { 25 | _emitExtraDataAddedEvent(extraDataToSet[i]); 26 | } 27 | } 28 | } 29 | 30 | function _getExtraData(bytes32 key) internal view returns (bytes memory) { 31 | return _getExtraStorage_Self(key); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /abis/ISource.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getTreasury", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "address" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "validateSource", 18 | "inputs": [ 19 | { 20 | "name": "sourceStamp", 21 | "type": "tuple", 22 | "internalType": "struct SourceStamp", 23 | "components": [ 24 | { 25 | "name": "source", 26 | "type": "address", 27 | "internalType": "address" 28 | }, 29 | { 30 | "name": "originalMsgSender", 31 | "type": "address", 32 | "internalType": "address" 33 | }, 34 | { 35 | "name": "validator", 36 | "type": "address", 37 | "internalType": "address" 38 | }, 39 | { 40 | "name": "nonce", 41 | "type": "uint256", 42 | "internalType": "uint256" 43 | }, 44 | { 45 | "name": "deadline", 46 | "type": "uint256", 47 | "internalType": "uint256" 48 | }, 49 | { 50 | "name": "signature", 51 | "type": "bytes", 52 | "internalType": "bytes" 53 | } 54 | ] 55 | } 56 | ], 57 | "outputs": [], 58 | "stateMutability": "nonpayable" 59 | } 60 | ] -------------------------------------------------------------------------------- /abis/IAccessControl.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "canChangeAccessControl", 5 | "inputs": [ 6 | { 7 | "name": "account", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "contractAddress", 13 | "type": "address", 14 | "internalType": "address" 15 | } 16 | ], 17 | "outputs": [ 18 | { 19 | "name": "", 20 | "type": "bool", 21 | "internalType": "bool" 22 | } 23 | ], 24 | "stateMutability": "view" 25 | }, 26 | { 27 | "type": "function", 28 | "name": "getType", 29 | "inputs": [], 30 | "outputs": [ 31 | { 32 | "name": "", 33 | "type": "bytes32", 34 | "internalType": "bytes32" 35 | } 36 | ], 37 | "stateMutability": "view" 38 | }, 39 | { 40 | "type": "function", 41 | "name": "hasAccess", 42 | "inputs": [ 43 | { 44 | "name": "account", 45 | "type": "address", 46 | "internalType": "address" 47 | }, 48 | { 49 | "name": "contractAddress", 50 | "type": "address", 51 | "internalType": "address" 52 | }, 53 | { 54 | "name": "permissionId", 55 | "type": "uint256", 56 | "internalType": "uint256" 57 | } 58 | ], 59 | "outputs": [ 60 | { 61 | "name": "", 62 | "type": "bool", 63 | "internalType": "bool" 64 | } 65 | ], 66 | "stateMutability": "view" 67 | } 68 | ] -------------------------------------------------------------------------------- /contracts/extensions/fees/LensRulePaymentHandler.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {LensPaymentHandler} from "lens-modules/contracts/extensions/fees/LensPaymentHandler.sol"; 6 | import {ILensNativePaymentHelper} from "lens-modules/contracts/extensions/fees/LensNativePaymentHelper.sol"; 7 | import {LENS_CREATE_2_ADDRESS, ILensCreate2} from "lens-modules/contracts/core/upgradeability/LensCreate2.sol"; 8 | import {CONTRACT__LENS_NATIVE_PAYMENT_HELPER, NATIVE_TOKEN} from "lens-modules/contracts/core/types/Constants.sol"; 9 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 10 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 11 | 12 | abstract contract LensRulePaymentHandler is LensPaymentHandler { 13 | using SafeERC20 for IERC20; 14 | 15 | ILensNativePaymentHelper private immutable LENS_NATIVE_PAYMENT_HELPER; 16 | 17 | constructor() { 18 | LENS_NATIVE_PAYMENT_HELPER = ILensNativePaymentHelper( 19 | ILensCreate2(LENS_CREATE_2_ADDRESS).getAddress(CONTRACT__LENS_NATIVE_PAYMENT_HELPER) 20 | ); 21 | } 22 | 23 | function _sendToken(address token, address payer, address recipient, uint256 amount) internal virtual override { 24 | if (token == NATIVE_TOKEN) { 25 | LENS_NATIVE_PAYMENT_HELPER.transferNative(recipient, amount); 26 | } else { 27 | IERC20(token).safeTransferFrom(payer, recipient, amount); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/rules/base/TrustBasedRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | 7 | abstract contract TrustBasedRule { 8 | event Lens_Rule_Trusted(address indexed account, address indexed trustedAddress); 9 | event Lens_Rule_Untrusted(address indexed account, address indexed untrustedAddress); 10 | 11 | /// @custom:keccak lens.storage.TrustBasedRule.isTrusted 12 | bytes32 constant STORAGE__IS_TRUSTED = 0x463a00e6fc84151780a21ba2127d78a0c153372a15d5669ad3912100980952bc; 13 | 14 | function $isTrusted() private pure returns (mapping(address => mapping(address => bool)) storage _storage) { 15 | assembly { 16 | _storage.slot := STORAGE__IS_TRUSTED 17 | } 18 | } 19 | 20 | function setTrust(address target, bool isTrusted) external virtual { 21 | $isTrusted()[msg.sender][target] = isTrusted; 22 | if (isTrusted) { 23 | emit Lens_Rule_Trusted(msg.sender, target); 24 | } else { 25 | emit Lens_Rule_Untrusted(msg.sender, target); 26 | } 27 | } 28 | 29 | function _requireTrust(address fromAccount, address toTarget) internal view virtual { 30 | require(_isTrusted(fromAccount, toTarget), Errors.Untrusted()); 31 | } 32 | 33 | function _isTrusted(address fromAccount, address toTarget) internal view virtual returns (bool) { 34 | return $isTrusted()[fromAccount][toTarget]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /abis/ERC1967Proxy.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "_logic", 7 | "type": "address", 8 | "internalType": "address" 9 | }, 10 | { 11 | "name": "_data", 12 | "type": "bytes", 13 | "internalType": "bytes" 14 | } 15 | ], 16 | "stateMutability": "payable" 17 | }, 18 | { 19 | "type": "fallback", 20 | "stateMutability": "payable" 21 | }, 22 | { 23 | "type": "receive", 24 | "stateMutability": "payable" 25 | }, 26 | { 27 | "type": "event", 28 | "name": "AdminChanged", 29 | "inputs": [ 30 | { 31 | "name": "previousAdmin", 32 | "type": "address", 33 | "indexed": false, 34 | "internalType": "address" 35 | }, 36 | { 37 | "name": "newAdmin", 38 | "type": "address", 39 | "indexed": false, 40 | "internalType": "address" 41 | } 42 | ], 43 | "anonymous": false 44 | }, 45 | { 46 | "type": "event", 47 | "name": "BeaconUpgraded", 48 | "inputs": [ 49 | { 50 | "name": "beacon", 51 | "type": "address", 52 | "indexed": true, 53 | "internalType": "address" 54 | } 55 | ], 56 | "anonymous": false 57 | }, 58 | { 59 | "type": "event", 60 | "name": "Upgraded", 61 | "inputs": [ 62 | { 63 | "name": "implementation", 64 | "type": "address", 65 | "indexed": true, 66 | "internalType": "address" 67 | } 68 | ], 69 | "anonymous": false 70 | } 71 | ] -------------------------------------------------------------------------------- /contracts/core/access/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | import {IOwnable} from "lens-modules/contracts/core/interfaces/IOwnable.sol"; 7 | 8 | abstract contract Ownable is IOwnable { 9 | event Lens_Ownable_OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 10 | 11 | struct OwnableStorage { 12 | address owner; 13 | } 14 | 15 | /// @custom:keccak lens.storage.Ownable 16 | bytes32 constant STORAGE__OWNABLE = 0x29cf0539cdb8487ad7dbc33f1a5f82174ca0f44de05580c9bd8cfe649fa8c9fe; 17 | 18 | function $ownableStorage() private pure returns (OwnableStorage storage _storage) { 19 | assembly { 20 | _storage.slot := STORAGE__OWNABLE 21 | } 22 | } 23 | 24 | modifier onlyOwner() { 25 | require(msg.sender == $ownableStorage().owner, Errors.InvalidMsgSender()); 26 | _; 27 | } 28 | 29 | function owner() public view virtual override returns (address) { 30 | return $ownableStorage().owner; 31 | } 32 | 33 | function transferOwnership(address newOwner) public virtual override onlyOwner { 34 | _transferOwnership(newOwner); 35 | } 36 | 37 | function _transferOwnership(address newOwner) internal virtual { 38 | address oldOwner = $ownableStorage().owner; 39 | $ownableStorage().owner = newOwner; 40 | emit Lens_Ownable_OwnershipTransferred(oldOwner, newOwner); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /abis/LensFees.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "treasuryAddress", 7 | "type": "address", 8 | "internalType": "address" 9 | }, 10 | { 11 | "name": "treasuryFeeBps", 12 | "type": "uint16", 13 | "internalType": "uint16" 14 | } 15 | ], 16 | "stateMutability": "nonpayable" 17 | }, 18 | { 19 | "type": "function", 20 | "name": "getLensFeesData", 21 | "inputs": [], 22 | "outputs": [ 23 | { 24 | "name": "", 25 | "type": "tuple", 26 | "internalType": "struct LensFeesData", 27 | "components": [ 28 | { 29 | "name": "treasuryAddress", 30 | "type": "address", 31 | "internalType": "address" 32 | }, 33 | { 34 | "name": "treasuryFeeBps", 35 | "type": "uint16", 36 | "internalType": "uint16" 37 | } 38 | ] 39 | } 40 | ], 41 | "stateMutability": "view" 42 | }, 43 | { 44 | "type": "function", 45 | "name": "getTreasuryAddress", 46 | "inputs": [], 47 | "outputs": [ 48 | { 49 | "name": "", 50 | "type": "address", 51 | "internalType": "address" 52 | } 53 | ], 54 | "stateMutability": "view" 55 | }, 56 | { 57 | "type": "function", 58 | "name": "getTreasuryFeeBps", 59 | "inputs": [], 60 | "outputs": [ 61 | { 62 | "name": "", 63 | "type": "uint16", 64 | "internalType": "uint16" 65 | } 66 | ], 67 | "stateMutability": "view" 68 | } 69 | ] -------------------------------------------------------------------------------- /contracts/extensions/factories/AccessControlFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IRoleBasedAccessControl} from "lens-modules/contracts/core/interfaces/IRoleBasedAccessControl.sol"; 6 | import {OwnerAdminOnlyAccessControl} from "lens-modules/contracts/extensions/access/OwnerAdminOnlyAccessControl.sol"; 7 | import {ILock} from "lens-modules/contracts/core/interfaces/ILock.sol"; 8 | 9 | contract AccessControlFactory { 10 | /// @custom:keccak lens.role.Admin 11 | uint256 constant ADMIN_ROLE_ID = uint256(0xfcbeadd75a96b5f8140d8c80f7c8d81ccbd7c4caa9592217bc8936b9eaabee75); 12 | 13 | event Lens_AccessControlFactory_OwnerAdminDeployment(address indexed accessControl, address owner); 14 | 15 | address immutable LOCK; 16 | 17 | constructor(address lock) { 18 | LOCK = lock; 19 | ILock(LOCK).isLocked(); // Aims to verify the given address follows ILock interface 20 | } 21 | 22 | function deployOwnerAdminOnlyAccessControl(address owner, address[] calldata admins) 23 | external 24 | returns (IRoleBasedAccessControl) 25 | { 26 | OwnerAdminOnlyAccessControl accessControl = new OwnerAdminOnlyAccessControl({owner: address(this), lock: LOCK}); 27 | emit Lens_AccessControlFactory_OwnerAdminDeployment(address(accessControl), owner); 28 | for (uint256 i = 0; i < admins.length; i++) { 29 | accessControl.grantRole(admins[i], ADMIN_ROLE_ID); 30 | } 31 | accessControl.transferOwnership(owner); 32 | return accessControl; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/generate-deployments.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from "url"; 2 | import fs from "fs"; 3 | import path from "path"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | const mainnetFilePath = path.resolve(__dirname, "../deployments/addressBook.mainnet.json"); 8 | const testnetFilePath = path.resolve(__dirname, "../deployments/addressBook.testnet.json"); 9 | const mainnetData = JSON.parse(fs.readFileSync(mainnetFilePath, "utf-8")); 10 | const testnetData = JSON.parse(fs.readFileSync(testnetFilePath, "utf-8")); 11 | 12 | const processAddressBook = data => 13 | Object.entries(data).reduce((acc, [key, value]) => { 14 | if (value.contractName === "Lock") return acc; // Skip Lock contracts 15 | acc[key] = { 16 | contractName: value.contractName, 17 | address: value.address, 18 | implementation: value.implementation || undefined, 19 | }; 20 | return acc; 21 | }, {}); 22 | 23 | const lensDeployments = { 24 | mainnet: processAddressBook(mainnetData), 25 | testnet: processAddressBook(testnetData), 26 | }; 27 | 28 | // Custom function to format JSON without quotes on property names 29 | const formatWithoutQuotes = obj => { 30 | const json = JSON.stringify(obj, null, 2); 31 | return json.replace(/"([^"]+)":/g, "$1:"); 32 | }; 33 | 34 | const outputContent = `export const lensDeployments = ${formatWithoutQuotes(lensDeployments)} as const;`; 35 | 36 | const outputPath = path.join(__dirname, "../src/deployments.ts"); 37 | fs.writeFileSync(outputPath, outputContent, "utf8"); 38 | 39 | console.log("Converted address books to deployments.ts successfully."); 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lens Modules 2 | 3 | This repository contains the contracts from the core Lens Protocol repo ([link](https://github.com/lens-protocol/lens-v3/tree/latest-mainnet)) as a standalone library, useful in Hardhat and Foundry projects. 4 | 5 | It includes the Solidity source code of the contracts, their ABIs, and deployment addresses for Lens Chain mainnet and testnet. 6 | 7 | The files are kept in sync with the `latest-mainnet` tag. 8 | 9 | ## Installation 10 | 11 | ``` 12 | npm i lens-modules 13 | ``` 14 | 15 | ## Usage 16 | 17 | #### Contracts 18 | 19 | Import Lens contracts you want to use in your Solidity project. The paths mirror the `lens-v3` repo structure. Eg: 20 | 21 | ```solidity 22 | import {Account} from "lens-modules/contracts/extensions/account/Account.sol"; 23 | import {IGraph} from "lens-modules/contracts/core/interfaces/IGraph.sol"; 24 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 25 | ``` 26 | 27 | #### Deployments 28 | 29 | Use the `Deployments` helper JavaScript class to get the contract addresses of the Lens deployments on mainnet and testnet. Eg: 30 | 31 | ```javascript 32 | import { lensDeployments } from "lens-modules/deployments"; 33 | 34 | const lensFactoryAddress = lensDeployments.mainnet.LensFactory.address; 35 | ``` 36 | 37 | #### ABIs 38 | 39 | Use the `ABIs` helper JavaScript class to get the ABI of any Lens contract. Eg: 40 | 41 | ```javascript 42 | import { accountAbi } from "lens-modules/abis"; 43 | 44 | await walletClient.writeContract({ 45 | address: "0xYourAccountContractAddress", 46 | abi: accountAbi, 47 | functionName: "executeTransaction", 48 | args: [ 49 | // ... your function arguments 50 | ], 51 | }); 52 | ``` -------------------------------------------------------------------------------- /abis/AccessControlled.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getAccessControl", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "contract IAccessControl" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "setAccessControl", 18 | "inputs": [ 19 | { 20 | "name": "newAccessControl", 21 | "type": "address", 22 | "internalType": "contract IAccessControl" 23 | } 24 | ], 25 | "outputs": [], 26 | "stateMutability": "nonpayable" 27 | }, 28 | { 29 | "type": "event", 30 | "name": "Lens_AccessControlAdded", 31 | "inputs": [ 32 | { 33 | "name": "accessControl", 34 | "type": "address", 35 | "indexed": true, 36 | "internalType": "address" 37 | }, 38 | { 39 | "name": "accessControlType", 40 | "type": "bytes32", 41 | "indexed": true, 42 | "internalType": "bytes32" 43 | } 44 | ], 45 | "anonymous": false 46 | }, 47 | { 48 | "type": "event", 49 | "name": "Lens_AccessControlUpdated", 50 | "inputs": [ 51 | { 52 | "name": "accessControl", 53 | "type": "address", 54 | "indexed": true, 55 | "internalType": "address" 56 | }, 57 | { 58 | "name": "accessControlType", 59 | "type": "bytes32", 60 | "indexed": true, 61 | "internalType": "bytes32" 62 | } 63 | ], 64 | "anonymous": false 65 | }, 66 | { 67 | "type": "error", 68 | "name": "AccessDenied", 69 | "inputs": [] 70 | } 71 | ] -------------------------------------------------------------------------------- /contracts/core/upgradeability/Lock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {ILock} from "lens-modules/contracts/core/interfaces/ILock.sol"; 6 | import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol"; 7 | import {EventEmitterEarly} from "lens-modules/contracts/migration/EventEmitterEarly.sol"; 8 | 9 | contract Lock is Ownable, ILock, EventEmitterEarly { 10 | event Lens_Lock_LockStatusSet(bool indexed locked); 11 | event Lens_Lock_LockStatusSet(address indexed target, bool indexed locked); 12 | 13 | bool internal _areAllAddressesUnlocked; 14 | mapping(address => bool) internal _isAddressUnlocked; 15 | 16 | constructor(address owner, bool locked) Ownable() { 17 | _transferOwnership(owner); 18 | _setLockStatus(locked); 19 | } 20 | 21 | function isLocked() external view override returns (bool) { 22 | if (_areAllAddressesUnlocked) { 23 | return false; 24 | } else { 25 | return !_isAddressUnlocked[msg.sender]; 26 | } 27 | } 28 | 29 | function setLockStatus(bool locked) external onlyOwner { 30 | _setLockStatus(locked); 31 | } 32 | 33 | // Only to unlock specific addresses before the global lock is released. 34 | function setLockStatusForAddress(address target, bool locked) external onlyOwner { 35 | _isAddressUnlocked[target] = !locked; 36 | emit Lens_Lock_LockStatusSet(target, locked); 37 | } 38 | 39 | function _setLockStatus(bool locked) internal { 40 | _areAllAddressesUnlocked = !locked; 41 | emit Lens_Lock_LockStatusSet(locked); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/extensions/factories/AppFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {AppInitialProperties, App} from "lens-modules/contracts/extensions/primitives/app/App.sol"; 7 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 9 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 10 | 11 | contract AppFactory { 12 | event Lens_AppFactory_Deployment(address indexed app, string metadataURI, KeyValue[] extraData); 13 | 14 | address internal immutable _beacon; 15 | address internal immutable _lock; 16 | 17 | constructor(address beacon, address lock) { 18 | _beacon = beacon; 19 | _lock = lock; 20 | } 21 | 22 | function deployApp( 23 | string memory metadataURI, 24 | bool sourceStampVerificationEnabled, 25 | IAccessControl accessControl, 26 | address proxyAdminOwner, 27 | AppInitialProperties calldata initialProperties, 28 | KeyValue[] calldata extraData 29 | ) external returns (address) { 30 | address proxyAdmin = address(new ProxyAdmin(proxyAdminOwner, _lock)); 31 | App app = App(address(new BeaconProxy(proxyAdmin, _beacon))); 32 | app.initialize(metadataURI, sourceStampVerificationEnabled, accessControl, initialProperties, extraData); 33 | emit Lens_AppFactory_Deployment(address(app), metadataURI, extraData); 34 | return address(app); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /abis/TransparentUpgradeableProxy.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "_logic", 7 | "type": "address", 8 | "internalType": "address" 9 | }, 10 | { 11 | "name": "admin_", 12 | "type": "address", 13 | "internalType": "address" 14 | }, 15 | { 16 | "name": "_data", 17 | "type": "bytes", 18 | "internalType": "bytes" 19 | } 20 | ], 21 | "stateMutability": "payable" 22 | }, 23 | { 24 | "type": "fallback", 25 | "stateMutability": "payable" 26 | }, 27 | { 28 | "type": "receive", 29 | "stateMutability": "payable" 30 | }, 31 | { 32 | "type": "event", 33 | "name": "AdminChanged", 34 | "inputs": [ 35 | { 36 | "name": "previousAdmin", 37 | "type": "address", 38 | "indexed": false, 39 | "internalType": "address" 40 | }, 41 | { 42 | "name": "newAdmin", 43 | "type": "address", 44 | "indexed": false, 45 | "internalType": "address" 46 | } 47 | ], 48 | "anonymous": false 49 | }, 50 | { 51 | "type": "event", 52 | "name": "BeaconUpgraded", 53 | "inputs": [ 54 | { 55 | "name": "beacon", 56 | "type": "address", 57 | "indexed": true, 58 | "internalType": "address" 59 | } 60 | ], 61 | "anonymous": false 62 | }, 63 | { 64 | "type": "event", 65 | "name": "Upgraded", 66 | "inputs": [ 67 | { 68 | "name": "implementation", 69 | "type": "address", 70 | "indexed": true, 71 | "internalType": "address" 72 | } 73 | ], 74 | "anonymous": false 75 | } 76 | ] -------------------------------------------------------------------------------- /abis/IERC20Permit.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "DOMAIN_SEPARATOR", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "bytes32", 10 | "internalType": "bytes32" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "nonces", 18 | "inputs": [ 19 | { 20 | "name": "owner", 21 | "type": "address", 22 | "internalType": "address" 23 | } 24 | ], 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "uint256", 29 | "internalType": "uint256" 30 | } 31 | ], 32 | "stateMutability": "view" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "permit", 37 | "inputs": [ 38 | { 39 | "name": "owner", 40 | "type": "address", 41 | "internalType": "address" 42 | }, 43 | { 44 | "name": "spender", 45 | "type": "address", 46 | "internalType": "address" 47 | }, 48 | { 49 | "name": "value", 50 | "type": "uint256", 51 | "internalType": "uint256" 52 | }, 53 | { 54 | "name": "deadline", 55 | "type": "uint256", 56 | "internalType": "uint256" 57 | }, 58 | { 59 | "name": "v", 60 | "type": "uint8", 61 | "internalType": "uint8" 62 | }, 63 | { 64 | "name": "r", 65 | "type": "bytes32", 66 | "internalType": "bytes32" 67 | }, 68 | { 69 | "name": "s", 70 | "type": "bytes32", 71 | "internalType": "bytes32" 72 | } 73 | ], 74 | "outputs": [], 75 | "stateMutability": "nonpayable" 76 | } 77 | ] -------------------------------------------------------------------------------- /contracts/core/base/EntityExtraDataBased.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 5 | import {ExtraStorageBased} from "lens-modules/contracts/core/base/ExtraStorageBased.sol"; 6 | 7 | abstract contract EntityExtraDataBased is ExtraStorageBased { 8 | function _emitEntityExtraDataAddedEvent(uint256 entityId, KeyValue memory extraDataAdded) internal virtual; 9 | 10 | function _emitEntityExtraDataUpdatedEvent(uint256 entityId, KeyValue memory extraDataUpdated) internal virtual; 11 | 12 | function _emitEntityExtraDataRemovedEvent(uint256 entityId, KeyValue memory extraDataRemoved) internal virtual; 13 | 14 | function _setEntityExtraData(uint256 entityId, KeyValue[] memory extraDataToSet) internal virtual { 15 | for (uint256 i = 0; i < extraDataToSet.length; i++) { 16 | bool hadAValueSetBefore = _setEntityExtraStorage_Account(entityId, extraDataToSet[i]); 17 | bool isNewValueEmpty = extraDataToSet[i].value.length == 0; 18 | if (hadAValueSetBefore) { 19 | if (isNewValueEmpty) { 20 | _emitEntityExtraDataRemovedEvent(entityId, extraDataToSet[i]); 21 | } else { 22 | _emitEntityExtraDataUpdatedEvent(entityId, extraDataToSet[i]); 23 | } 24 | } else if (!isNewValueEmpty) { 25 | _emitEntityExtraDataAddedEvent(entityId, extraDataToSet[i]); 26 | } 27 | } 28 | } 29 | 30 | function _getEntityExtraData(address addressScope, uint256 entityId, bytes32 key) 31 | internal 32 | view 33 | returns (bytes memory) 34 | { 35 | return _getEntityExtraStorage_Account(addressScope, entityId, key); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/core/types/Errors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | library Errors { 6 | error AccessDenied(); 7 | error AllAnyOfRulesReverted(); 8 | error AlreadyExists(); 9 | error AlreadyInitialized(); 10 | error AlreadyProcessed(); 11 | error AutoUpgradeEnabled(); 12 | error Banned(); 13 | error Blocked(); 14 | error CannotFollowAgain(); 15 | error CannotHaveRules(); 16 | error CannotStartWithThat(); 17 | error ConfigureCallReverted(); 18 | error Disabled(); 19 | error DoesNotExist(); 20 | error DuplicatedValue(); 21 | error Expired(); 22 | error FailedToTransferNative(); 23 | error Immutable(); 24 | error InsufficientAllowance(); 25 | error InvalidConfigSalt(); 26 | error InvalidMsgSender(); 27 | error InvalidParameter(); 28 | error InvalidSignature(); 29 | error InvalidSourceStampOriginalMsgSender(); 30 | error LimitReached(); 31 | error Locked(); 32 | error NonceUsed(); 33 | error NotAContract(); 34 | error NotAllowed(); 35 | error NotAMember(); 36 | error NotEnough(); 37 | error NotEnoughBalance(); 38 | error NotFollowing(); 39 | error NotFound(); 40 | error NotImplemented(); 41 | error RedundantStateChange(); 42 | error RequiredRuleReverted(); 43 | error RuleNotConfigured(); 44 | error SelectorEnabledForDifferentRuleType(); 45 | error ActionOnSelf(); 46 | error SingleAnyOfRule(); 47 | error UnexpectedContractImpl(); 48 | error UnexpectedValue(); 49 | error UnsupportedSelector(); 50 | error UnsupportedOperation(); 51 | error Untrusted(); 52 | error UsernameAssigned(); 53 | error TransferFailed(); 54 | error WrongSigner(); 55 | } 56 | -------------------------------------------------------------------------------- /contracts/extensions/factories/FeedFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {Feed} from "lens-modules/contracts/core/primitives/feed/Feed.sol"; 7 | import {RuleChange, KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 9 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 10 | import {PrimitiveFactory} from "lens-modules/contracts/extensions/factories/PrimitiveFactory.sol"; 11 | 12 | contract FeedFactory is PrimitiveFactory { 13 | event Lens_FeedFactory_Deployment(address indexed feed, string metadataURI); 14 | 15 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 16 | PrimitiveFactory(primitiveBeacon, proxyAdminLock, lensFactory) 17 | {} 18 | 19 | function deployFeed( 20 | string memory metadataURI, 21 | IAccessControl accessControl, 22 | address proxyAdminOwner, 23 | RuleChange[] calldata ruleChanges, 24 | KeyValue[] calldata extraData 25 | ) external onlyLensFactory returns (address) { 26 | address proxyAdmin = address(new ProxyAdmin(proxyAdminOwner, PROXY_ADMIN_LOCK)); 27 | Feed feed = Feed(address(new BeaconProxy(proxyAdmin, PRIMITIVE_BEACON))); 28 | feed.initialize(metadataURI, TEMPORARY_ACCESS_CONTROL); 29 | feed.changeFeedRules(ruleChanges); 30 | feed.setExtraData(extraData); 31 | feed.setAccessControl(accessControl); 32 | emit Lens_FeedFactory_Deployment(address(feed), metadataURI); 33 | return address(feed); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/extensions/factories/GraphFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {Graph} from "lens-modules/contracts/core/primitives/graph/Graph.sol"; 7 | import {RuleChange, KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 9 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 10 | import {PrimitiveFactory} from "lens-modules/contracts/extensions/factories/PrimitiveFactory.sol"; 11 | 12 | contract GraphFactory is PrimitiveFactory { 13 | event Lens_GraphFactory_Deployment(address indexed graph, string metadataURI); 14 | 15 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 16 | PrimitiveFactory(primitiveBeacon, proxyAdminLock, lensFactory) 17 | {} 18 | 19 | function deployGraph( 20 | string memory metadataURI, 21 | IAccessControl accessControl, 22 | address proxyAdminOwner, 23 | RuleChange[] calldata ruleChanges, 24 | KeyValue[] calldata extraData 25 | ) external onlyLensFactory returns (address) { 26 | address proxyAdmin = address(new ProxyAdmin(proxyAdminOwner, PROXY_ADMIN_LOCK)); 27 | Graph graph = Graph(address(new BeaconProxy(proxyAdmin, PRIMITIVE_BEACON))); 28 | graph.initialize(metadataURI, TEMPORARY_ACCESS_CONTROL); 29 | graph.changeGraphRules(ruleChanges); 30 | graph.setExtraData(extraData); 31 | graph.setAccessControl(accessControl); 32 | emit Lens_GraphFactory_Deployment(address(graph), metadataURI); 33 | return address(graph); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/core/interfaces/IRoleBasedAccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | 7 | enum Access { 8 | UNDEFINED, 9 | GRANTED, 10 | DENIED 11 | } 12 | 13 | struct Role { 14 | address account; 15 | uint256 roleId; 16 | } 17 | 18 | interface IRoleBasedAccessControl is IAccessControl { 19 | event Lens_AccessControl_RoleGranted(address indexed account, uint256 indexed roleId); 20 | event Lens_AccessControl_RoleRevoked(address indexed account, uint256 indexed roleId); 21 | 22 | event Lens_AccessControl_AccessAdded( 23 | uint256 indexed roleId, address indexed contractAddress, uint256 indexed permissionId, bool granted 24 | ); 25 | event Lens_AccessControl_AccessUpdated( 26 | uint256 indexed roleId, address indexed contractAddress, uint256 indexed permissionId, bool granted 27 | ); 28 | event Lens_AccessControl_AccessRemoved( 29 | uint256 indexed roleId, address indexed contractAddress, uint256 indexed permissionId 30 | ); 31 | 32 | // Role functions 33 | function grantRole(address account, uint256 roleId) external; 34 | 35 | function revokeRole(address account, uint256 roleId) external; 36 | 37 | function grantRoles(Role[] calldata roles) external; 38 | 39 | function revokeRoles(Role[] calldata roles) external; 40 | 41 | function hasRole(address account, uint256 roleId) external view returns (bool); 42 | 43 | // Access functions 44 | function setAccess(uint256 roleId, address contractAddress, uint256 permissionId, Access access) external; 45 | 46 | function getAccess(uint256 roleId, address contractAddress, uint256 permissionId) external view returns (Access); 47 | } 48 | -------------------------------------------------------------------------------- /contracts/extensions/factories/GroupFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {Group} from "lens-modules/contracts/core/primitives/group/Group.sol"; 7 | import {RuleChange, RuleProcessingParams, KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 9 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 10 | import {PrimitiveFactory} from "lens-modules/contracts/extensions/factories/PrimitiveFactory.sol"; 11 | 12 | contract GroupFactory is PrimitiveFactory { 13 | event Lens_GroupFactory_Deployment(address indexed group, string metadataURI); 14 | 15 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 16 | PrimitiveFactory(primitiveBeacon, proxyAdminLock, lensFactory) 17 | {} 18 | 19 | function deployGroup( 20 | string memory metadataURI, 21 | IAccessControl accessControl, 22 | address proxyAdminOwner, 23 | RuleChange[] calldata ruleChanges, 24 | KeyValue[] calldata extraData, 25 | address foundingMember 26 | ) external onlyLensFactory returns (address) { 27 | address proxyAdmin = address(new ProxyAdmin(proxyAdminOwner, PROXY_ADMIN_LOCK)); 28 | Group group = Group(address(new BeaconProxy(proxyAdmin, PRIMITIVE_BEACON))); 29 | group.initialize(metadataURI, TEMPORARY_ACCESS_CONTROL, foundingMember); 30 | group.changeGroupRules(ruleChanges); 31 | group.setExtraData(extraData); 32 | group.setAccessControl(accessControl); 33 | emit Lens_GroupFactory_Deployment(address(group), metadataURI); 34 | return address(group); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/migration/primitives/MigrationNamespace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Namespace} from "lens-modules/contracts/core/primitives/namespace/Namespace.sol"; 6 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 7 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {KeyValueStorageLib} from "lens-modules/contracts/core/libraries/KeyValueStorageLib.sol"; 9 | 10 | contract MigrationNamespace is Namespace, EventEmitter { 11 | using KeyValueStorageLib for mapping(bytes32 => bytes); 12 | 13 | function $migrationExtraStorage() private pure returns (ExtraStorage storage _storage) { 14 | assembly { 15 | _storage.slot := STORAGE__EXTRA_STORAGE 16 | } 17 | } 18 | 19 | function _setEntityExtraData(uint256 tokenId, KeyValue[] memory extraDataToSet) internal override { 20 | address usernameOwner = ownerOf(tokenId); 21 | for (uint256 i = 0; i < extraDataToSet.length; i++) { 22 | // Storing extra data in the native extra storage for data integrity 23 | _setEntityExtraStorage(tokenId, extraDataToSet[i]); 24 | // Forcing ExtraStorageBased::_setEntityExtraStorage_Account with injected addressScope 25 | _migration_force__setEntityExtraStorage_Account(usernameOwner, tokenId, extraDataToSet[i]); 26 | emit Lens_Username_ExtraDataAdded( 27 | tokenId, extraDataToSet[i].key, extraDataToSet[i].value, extraDataToSet[i].value 28 | ); 29 | } 30 | } 31 | 32 | function _migration_force__setEntityExtraStorage_Account( 33 | address addressScope, 34 | uint256 entityId, 35 | KeyValue memory extraDataToSet 36 | ) private { 37 | // In this release we always set the entityType to zero 38 | $migrationExtraStorage().slot[addressScope][0][entityId].set(extraDataToSet); 39 | emit Lens_ExtraStorageSet(addressScope, 0, entityId, extraDataToSet.key, extraDataToSet.value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/extensions/factories/AccountFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Account, AccountManagerPermissions} from "lens-modules/contracts/extensions/account/Account.sol"; 6 | import {KeyValue, SourceStamp} from "lens-modules/contracts/core/types/Types.sol"; 7 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 8 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 9 | 10 | contract AccountFactory { 11 | event Lens_Account_Created( 12 | address indexed account, 13 | address indexed owner, 14 | string metadataURI, 15 | address[] accountManagers, 16 | AccountManagerPermissions[] accountManagersPermissions, 17 | address indexed source, 18 | KeyValue[] extraData 19 | ); 20 | 21 | address internal immutable _beacon; 22 | address internal immutable _lock; 23 | 24 | constructor(address beacon, address lock) { 25 | _beacon = beacon; 26 | _lock = lock; 27 | } 28 | 29 | function deployAccount( 30 | address owner, 31 | string calldata metadataURI, 32 | address[] calldata accountManagers, 33 | AccountManagerPermissions[] calldata accountManagersPermissions, 34 | SourceStamp calldata sourceStamp, 35 | KeyValue[] calldata extraData 36 | ) external returns (address) { 37 | address proxyAdmin = address(new ProxyAdmin(owner, _lock)); // Owner of Proxy Admin same as owner of Account 38 | Account account = Account(payable(new BeaconProxy(proxyAdmin, _beacon))); 39 | account.initialize(owner, metadataURI, accountManagers, accountManagersPermissions, sourceStamp, extraData); 40 | emit Lens_Account_Created( 41 | address(account), 42 | owner, 43 | metadataURI, 44 | accountManagers, 45 | accountManagersPermissions, 46 | sourceStamp.source, 47 | extraData 48 | ); 49 | return payable(account); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lens-modules", 3 | "version": "3.1.5", 4 | "description": "Contracts, ABIs, and utilities for Lens Protocol.", 5 | "type": "module", 6 | "sideEffects": false, 7 | "main": "dist/index.cjs", 8 | "module": "dist/index.js", 9 | "types": "dist/index.d.ts", 10 | "files": [ 11 | "contracts/**/*.sol", 12 | "dist" 13 | ], 14 | "exports": { 15 | ".": { 16 | "types": "./dist/index.d.ts", 17 | "import": "./dist/index.js", 18 | "require": "./dist/index.cjs" 19 | }, 20 | "./abis": { 21 | "types": "./dist/abis.d.ts", 22 | "import": "./dist/abis.js", 23 | "require": "./dist/abis.cjs" 24 | }, 25 | "./deployments": { 26 | "types": "./dist/deployments.d.ts", 27 | "import": "./dist/deployments.js", 28 | "require": "./dist/deployments.cjs" 29 | } 30 | }, 31 | "typesVersions": { 32 | "*": { 33 | "abis": [ 34 | "dist/abis.d.ts" 35 | ], 36 | "deployments": [ 37 | "dist/deployments.d.ts" 38 | ] 39 | } 40 | }, 41 | "scripts": { 42 | "build": "tsup", 43 | "prepublish": "npm run build", 44 | "prettier": "prettier --write .", 45 | "generate-abis": "npx wagmi generate", 46 | "generate-deployments": "node ./scripts/generate-deployments.js", 47 | "generate": "npm run generate-abis && npm run generate-deployments && npm run prettier" 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "https://github.com/iPaulPro/lens-modules.git" 52 | }, 53 | "keywords": [ 54 | "lens-protocol", 55 | "lens", 56 | "solidity", 57 | "ethereum", 58 | "smart", 59 | "contracts", 60 | "web3-social", 61 | "web3" 62 | ], 63 | "author": "Paul Burke ", 64 | "license": "MIT", 65 | "devDependencies": { 66 | "@eslint/eslintrc": "^3.3.1", 67 | "@types/node": "^22.15.21", 68 | "@wagmi/cli": "^2.3.1", 69 | "esbuild": "0.25.4", 70 | "eslint": "^9.26.0", 71 | "eslint-config-prettier": "^10.1.3", 72 | "eslint-plugin-prettier": "^5.4.0", 73 | "prettier": "^3.5.3", 74 | "tsup": "8.5.0", 75 | "typescript": "^5.4.2", 76 | "viem": "^2.30.0" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /contracts/core/base/MetadataBased.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | import {IMetadataBased} from "lens-modules/contracts/core/interfaces/IMetadataBased.sol"; 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | 7 | abstract contract MetadataBased is IMetadataBased { 8 | // source = address(0) => Global MetadataURI 9 | // source = any other address => MetadataURI set by specific source 10 | struct MetadataURIStorage { 11 | mapping(address => string) metadataURI; 12 | } 13 | 14 | /// @custom:keccak lens.storage.metadataURI 15 | bytes32 constant STORAGE__METADATA_URI = 0x1e3609457e69da9dd0dabac13fb8ca9b651f93d6966199d652f92264e8b2ea10; 16 | 17 | function $metadataStorage() internal pure returns (MetadataURIStorage storage _storage) { 18 | assembly { 19 | _storage.slot := STORAGE__METADATA_URI 20 | } 21 | } 22 | 23 | function setMetadataURI(string memory metadataURI) external override { 24 | _beforeMetadataURIUpdate(metadataURI); 25 | // solc-ignore-next-line unreachable 26 | _setMetadataURI(metadataURI); 27 | } 28 | 29 | function _setMetadataURI(string memory metadataURI) internal { 30 | $metadataStorage().metadataURI[address(0)] = metadataURI; 31 | _emitMetadataURISet(metadataURI, address(0)); 32 | } 33 | 34 | function _setMetadataURI(string memory metadataURI, address source) internal { 35 | $metadataStorage().metadataURI[source] = metadataURI; 36 | _emitMetadataURISet(metadataURI, source); 37 | } 38 | 39 | function _beforeMetadataURIUpdate(string memory /* metadataURI */ ) internal virtual { 40 | revert Errors.NotImplemented(); 41 | } 42 | 43 | function _emitMetadataURISet(string memory, /* metadataURI */ address /* source */ ) internal virtual; 44 | 45 | function getMetadataURI() external view override returns (string memory) { 46 | return $metadataStorage().metadataURI[address(0)]; 47 | } 48 | 49 | function getMetadataURI(address source) external view returns (string memory) { 50 | return $metadataStorage().metadataURI[source]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /abis/ERC1155Holder.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC1155BatchReceived", 5 | "inputs": [ 6 | { 7 | "name": "", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "", 18 | "type": "uint256[]", 19 | "internalType": "uint256[]" 20 | }, 21 | { 22 | "name": "", 23 | "type": "uint256[]", 24 | "internalType": "uint256[]" 25 | }, 26 | { 27 | "name": "", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ], 32 | "outputs": [ 33 | { 34 | "name": "", 35 | "type": "bytes4", 36 | "internalType": "bytes4" 37 | } 38 | ], 39 | "stateMutability": "nonpayable" 40 | }, 41 | { 42 | "type": "function", 43 | "name": "onERC1155Received", 44 | "inputs": [ 45 | { 46 | "name": "", 47 | "type": "address", 48 | "internalType": "address" 49 | }, 50 | { 51 | "name": "", 52 | "type": "address", 53 | "internalType": "address" 54 | }, 55 | { 56 | "name": "", 57 | "type": "uint256", 58 | "internalType": "uint256" 59 | }, 60 | { 61 | "name": "", 62 | "type": "uint256", 63 | "internalType": "uint256" 64 | }, 65 | { 66 | "name": "", 67 | "type": "bytes", 68 | "internalType": "bytes" 69 | } 70 | ], 71 | "outputs": [ 72 | { 73 | "name": "", 74 | "type": "bytes4", 75 | "internalType": "bytes4" 76 | } 77 | ], 78 | "stateMutability": "nonpayable" 79 | }, 80 | { 81 | "type": "function", 82 | "name": "supportsInterface", 83 | "inputs": [ 84 | { 85 | "name": "interfaceId", 86 | "type": "bytes4", 87 | "internalType": "bytes4" 88 | } 89 | ], 90 | "outputs": [ 91 | { 92 | "name": "", 93 | "type": "bool", 94 | "internalType": "bool" 95 | } 96 | ], 97 | "stateMutability": "view" 98 | } 99 | ] -------------------------------------------------------------------------------- /contracts/core/primitives/group/GroupCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Membership} from "lens-modules/contracts/core/interfaces/IGroup.sol"; 6 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 7 | 8 | library GroupCore { 9 | // Storage 10 | 11 | struct Storage { 12 | uint256 lastMemberIdAssigned; 13 | uint256 numberOfMembers; 14 | mapping(address => Membership) memberships; 15 | } 16 | 17 | /// @custom:keccak lens.storage.GroupCore 18 | bytes32 constant STORAGE__GROUP_CORE = 0x21ab408a492cf8beda2879363dd3a4ec8ba15c85532aa540e0e12415acdd09ed; 19 | 20 | function $storage() internal pure returns (Storage storage _storage) { 21 | assembly { 22 | _storage.slot := STORAGE__GROUP_CORE 23 | } 24 | } 25 | 26 | // Internal functions - Use these functions to be called as an inlined library 27 | 28 | function _isMember(address account) internal view returns (bool) { 29 | return $storage().memberships[account].id != 0; 30 | } 31 | 32 | function _getMembership(address account) internal view returns (Membership memory) { 33 | return $storage().memberships[account]; 34 | } 35 | 36 | function _grantMembership(address account) internal returns (uint256) { 37 | require(account != address(0), Errors.InvalidParameter()); 38 | uint256 membershipId = ++$storage().lastMemberIdAssigned; 39 | $storage().numberOfMembers++; 40 | require($storage().memberships[account].id == 0, Errors.RedundantStateChange()); // Must not be a member yet 41 | $storage().memberships[account] = Membership(membershipId, block.timestamp); 42 | return membershipId; 43 | } 44 | 45 | function _revokeMembership(address account) internal returns (uint256) { 46 | require(account != address(0), Errors.InvalidParameter()); 47 | uint256 membershipId = $storage().memberships[account].id; 48 | require(membershipId != 0, Errors.RedundantStateChange()); // Must be a member 49 | $storage().numberOfMembers--; 50 | delete $storage().memberships[account]; 51 | return membershipId; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /abis/ERC1155Receiver.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC1155BatchReceived", 5 | "inputs": [ 6 | { 7 | "name": "operator", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "from", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "ids", 18 | "type": "uint256[]", 19 | "internalType": "uint256[]" 20 | }, 21 | { 22 | "name": "values", 23 | "type": "uint256[]", 24 | "internalType": "uint256[]" 25 | }, 26 | { 27 | "name": "data", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ], 32 | "outputs": [ 33 | { 34 | "name": "", 35 | "type": "bytes4", 36 | "internalType": "bytes4" 37 | } 38 | ], 39 | "stateMutability": "nonpayable" 40 | }, 41 | { 42 | "type": "function", 43 | "name": "onERC1155Received", 44 | "inputs": [ 45 | { 46 | "name": "operator", 47 | "type": "address", 48 | "internalType": "address" 49 | }, 50 | { 51 | "name": "from", 52 | "type": "address", 53 | "internalType": "address" 54 | }, 55 | { 56 | "name": "id", 57 | "type": "uint256", 58 | "internalType": "uint256" 59 | }, 60 | { 61 | "name": "value", 62 | "type": "uint256", 63 | "internalType": "uint256" 64 | }, 65 | { 66 | "name": "data", 67 | "type": "bytes", 68 | "internalType": "bytes" 69 | } 70 | ], 71 | "outputs": [ 72 | { 73 | "name": "", 74 | "type": "bytes4", 75 | "internalType": "bytes4" 76 | } 77 | ], 78 | "stateMutability": "nonpayable" 79 | }, 80 | { 81 | "type": "function", 82 | "name": "supportsInterface", 83 | "inputs": [ 84 | { 85 | "name": "interfaceId", 86 | "type": "bytes4", 87 | "internalType": "bytes4" 88 | } 89 | ], 90 | "outputs": [ 91 | { 92 | "name": "", 93 | "type": "bool", 94 | "internalType": "bool" 95 | } 96 | ], 97 | "stateMutability": "view" 98 | } 99 | ] -------------------------------------------------------------------------------- /abis/IERC1155Receiver.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "onERC1155BatchReceived", 5 | "inputs": [ 6 | { 7 | "name": "operator", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "from", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "ids", 18 | "type": "uint256[]", 19 | "internalType": "uint256[]" 20 | }, 21 | { 22 | "name": "values", 23 | "type": "uint256[]", 24 | "internalType": "uint256[]" 25 | }, 26 | { 27 | "name": "data", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ], 32 | "outputs": [ 33 | { 34 | "name": "", 35 | "type": "bytes4", 36 | "internalType": "bytes4" 37 | } 38 | ], 39 | "stateMutability": "nonpayable" 40 | }, 41 | { 42 | "type": "function", 43 | "name": "onERC1155Received", 44 | "inputs": [ 45 | { 46 | "name": "operator", 47 | "type": "address", 48 | "internalType": "address" 49 | }, 50 | { 51 | "name": "from", 52 | "type": "address", 53 | "internalType": "address" 54 | }, 55 | { 56 | "name": "id", 57 | "type": "uint256", 58 | "internalType": "uint256" 59 | }, 60 | { 61 | "name": "value", 62 | "type": "uint256", 63 | "internalType": "uint256" 64 | }, 65 | { 66 | "name": "data", 67 | "type": "bytes", 68 | "internalType": "bytes" 69 | } 70 | ], 71 | "outputs": [ 72 | { 73 | "name": "", 74 | "type": "bytes4", 75 | "internalType": "bytes4" 76 | } 77 | ], 78 | "stateMutability": "nonpayable" 79 | }, 80 | { 81 | "type": "function", 82 | "name": "supportsInterface", 83 | "inputs": [ 84 | { 85 | "name": "interfaceId", 86 | "type": "bytes4", 87 | "internalType": "bytes4" 88 | } 89 | ], 90 | "outputs": [ 91 | { 92 | "name": "", 93 | "type": "bool", 94 | "internalType": "bool" 95 | } 96 | ], 97 | "stateMutability": "view" 98 | } 99 | ] -------------------------------------------------------------------------------- /contracts/extensions/factories/NamespaceFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {Namespace} from "lens-modules/contracts/core/primitives/namespace/Namespace.sol"; 7 | import {RuleChange, KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {ITokenURIProvider} from "lens-modules/contracts/core/interfaces/ITokenURIProvider.sol"; 9 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 10 | import {ProxyAdmin} from "lens-modules/contracts/core/upgradeability/ProxyAdmin.sol"; 11 | import {PrimitiveFactory} from "lens-modules/contracts/extensions/factories/PrimitiveFactory.sol"; 12 | 13 | contract NamespaceFactory is PrimitiveFactory { 14 | event Lens_NamespaceFactory_Deployment(address indexed namespaceAddress, string namespace, string metadataURI); 15 | 16 | constructor(address primitiveBeacon, address proxyAdminLock, address lensFactory) 17 | PrimitiveFactory(primitiveBeacon, proxyAdminLock, lensFactory) 18 | {} 19 | 20 | function deployNamespace( 21 | string memory namespace, 22 | string memory metadataURI, 23 | IAccessControl accessControl, 24 | address proxyAdminOwner, 25 | RuleChange[] calldata ruleChanges, 26 | KeyValue[] calldata extraData, 27 | string memory nftName, 28 | string memory nftSymbol, 29 | ITokenURIProvider tokenURIProvider 30 | ) external onlyLensFactory returns (address) { 31 | address proxyAdmin = address(new ProxyAdmin(proxyAdminOwner, PROXY_ADMIN_LOCK)); 32 | Namespace namespacePrimitive = Namespace(address(new BeaconProxy(proxyAdmin, PRIMITIVE_BEACON))); 33 | namespacePrimitive.initialize( 34 | namespace, metadataURI, nftName, nftSymbol, tokenURIProvider, TEMPORARY_ACCESS_CONTROL 35 | ); 36 | namespacePrimitive.changeNamespaceRules(ruleChanges); 37 | namespacePrimitive.setExtraData(extraData); 38 | namespacePrimitive.setAccessControl(accessControl); 39 | emit Lens_NamespaceFactory_Deployment(address(namespacePrimitive), namespace, metadataURI); 40 | return address(namespacePrimitive); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /contracts/actions/post/collect/ISimpleCollectAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IPostAction} from "lens-modules/contracts/extensions/actions/ActionHub.sol"; 6 | import {RecipientData} from "lens-modules/contracts/core/types/Types.sol"; 7 | 8 | /** 9 | * @notice A storage struct containing all data regarding a post's collect action. 10 | * 11 | * @param amount The collecting cost associated with this publication. 0 for free collect. 12 | * @param collectLimit The maximum number of collects for this publication. 0 for no limit. 13 | * @param token The token associated with this publication. 14 | * @param currentCollects The current number of collects for this publication. 15 | * @param recipients Recipients of collect amount. 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. 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. 27 | */ 28 | struct CollectActionData { 29 | uint160 amount; 30 | uint96 collectLimit; 31 | address token; 32 | uint96 currentCollects; 33 | RecipientData[] recipients; 34 | uint72 endTimestamp; 35 | uint16 referralFeeBps; 36 | address followerOnlyGraph; 37 | address collectionAddress; 38 | bool isImmutable; 39 | bool isDisabled; 40 | } 41 | 42 | interface ISimpleCollectAction is IPostAction { 43 | function getCollectActionData(address feed, uint256 postId) external view returns (CollectActionData memory); 44 | } 45 | -------------------------------------------------------------------------------- /contracts/actions/account/base/BaseAccountAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 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 | 10 | abstract contract BaseAccountAction is BaseAction, IAccountAction { 11 | constructor(address actionHub) BaseAction(actionHub) {} 12 | 13 | function configure(address originalMsgSender, address account, KeyValue[] calldata params) 14 | external 15 | payable 16 | override 17 | onlyActionHub 18 | returns (bytes memory) 19 | { 20 | return _configure(originalMsgSender, account, params); 21 | } 22 | 23 | function execute(address originalMsgSender, address account, KeyValue[] calldata params) 24 | external 25 | payable 26 | override 27 | onlyActionHub 28 | returns (bytes memory) 29 | { 30 | return _execute(originalMsgSender, account, params); 31 | } 32 | 33 | function setDisabled(address originalMsgSender, address account, bool isDisabled, KeyValue[] calldata params) 34 | external 35 | payable 36 | override 37 | onlyActionHub 38 | returns (bytes memory) 39 | { 40 | return _setDisabled(originalMsgSender, account, isDisabled, params); 41 | } 42 | 43 | function _configure(address originalMsgSender, address, /* account */ KeyValue[] calldata /* params */ ) 44 | internal 45 | virtual 46 | returns (bytes memory) 47 | { 48 | return _configureUniversalAction(originalMsgSender); 49 | } 50 | 51 | function _execute(address originalMsgSender, address account, KeyValue[] calldata params) 52 | internal 53 | virtual 54 | returns (bytes memory); 55 | 56 | function _setDisabled( 57 | address, /* originalMsgSender */ 58 | address, /* account */ 59 | bool, /* isDisabled */ 60 | KeyValue[] calldata /* params */ 61 | ) internal virtual returns (bytes memory) { 62 | revert Errors.NotImplemented(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /contracts/core/upgradeability/ProxyAdmin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {ILock} from "lens-modules/contracts/core/interfaces/ILock.sol"; 6 | import {BeaconProxy} from "lens-modules/contracts/core/upgradeability/BeaconProxy.sol"; 7 | import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol"; 8 | import {CallLib} from "lens-modules/contracts/core/libraries/CallLib.sol"; 9 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 10 | 11 | contract ProxyAdmin is Ownable { 12 | using CallLib for address; 13 | 14 | ILock immutable LOCK; 15 | 16 | constructor(address proxyAdminOwner, address lock) Ownable() { 17 | _transferOwnership(proxyAdminOwner); 18 | LOCK = ILock(lock); 19 | LOCK.isLocked(); // Aims to verify the given address follows ILock interface 20 | } 21 | 22 | function call(address to, uint256 value, bytes calldata data) external payable onlyOwner returns (bytes memory) { 23 | bytes4 selector = bytes4(data); 24 | if (LOCK.isLocked()) { 25 | // While the Proxy Admin is locked it: 26 | // - Cannot change Proxy Admin in the Proxy, only in the ProxyAdmin contract itself 27 | require(selector != BeaconProxy.proxy__changeProxyAdmin.selector, Errors.Locked()); 28 | // - Cannot change the Beacon in the Proxy 29 | require(selector != BeaconProxy.proxy__setBeacon.selector, Errors.Locked()); 30 | // - Cannot change the implementation in the Proxy 31 | require(selector != BeaconProxy.proxy__setImplementation.selector, Errors.Locked()); 32 | // - Cannot trigger an upgrade in the Proxy 33 | require(selector != BeaconProxy.proxy__triggerUpgradeToVersion.selector, Errors.Locked()); 34 | require(selector != BeaconProxy.proxy__triggerUpgrade.selector, Errors.Locked()); 35 | // - Cannot opt-out from auto-upgrade in the Proxy 36 | require(selector != BeaconProxy.proxy__optOutFromAutoUpgrade.selector, Errors.Locked()); 37 | // - Cannot opt-in to auto-upgrade in the Proxy 38 | require(selector != BeaconProxy.proxy__optInToAutoUpgrade.selector, Errors.Locked()); 39 | } 40 | return to.handledsafecall(value, data); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /contracts/core/upgradeability/Beacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol"; 6 | import {IVersionedBeacon} from "lens-modules/contracts/core/interfaces/IVersionedBeacon.sol"; 7 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 8 | import {EventEmitterEarly} from "lens-modules/contracts/migration/EventEmitterEarly.sol"; 9 | 10 | contract Beacon is Ownable, IVersionedBeacon, EventEmitterEarly { 11 | event ImplementationSetForVersion(uint256 indexed version, address indexed implementation); 12 | event DefaultVersionSet(uint256 indexed version); 13 | 14 | mapping(uint256 => address) internal _implementations; 15 | uint256 internal _defaultVersion; 16 | 17 | constructor(address owner, uint256 version, address initialImplementation) Ownable() { 18 | _transferOwnership(owner); 19 | require(initialImplementation != address(0), Errors.InvalidParameter()); 20 | _implementations[version] = initialImplementation; 21 | emit ImplementationSetForVersion(version, initialImplementation); 22 | _defaultVersion = version; 23 | emit DefaultVersionSet(version); 24 | } 25 | 26 | function implementation() external view override returns (address) { 27 | return _implementations[_defaultVersion]; 28 | } 29 | 30 | function implementation(uint256 implementationVersion) external view override returns (address) { 31 | address implementationByVersion = _implementations[implementationVersion]; 32 | require(implementationByVersion != address(0), Errors.InvalidParameter()); 33 | return implementationByVersion; 34 | } 35 | 36 | function setImplementationForVersion(uint256 version, address implementationToSet) external onlyOwner { 37 | if (_defaultVersion == version) { 38 | require(implementationToSet != address(0), Errors.InvalidParameter()); 39 | } 40 | _implementations[version] = implementationToSet; 41 | emit ImplementationSetForVersion(version, implementationToSet); 42 | } 43 | 44 | function setDefaultVersion(uint256 version) external onlyOwner { 45 | require(_implementations[version] != address(0), Errors.InvalidParameter()); 46 | _defaultVersion = version; 47 | emit DefaultVersionSet(version); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/actions/post/base/BasePostAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 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 | 10 | abstract contract BasePostAction is BaseAction, IPostAction { 11 | constructor(address actionHub) BaseAction(actionHub) {} 12 | 13 | function configure(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params) 14 | external 15 | payable 16 | override 17 | onlyActionHub 18 | returns (bytes memory) 19 | { 20 | return _configure(originalMsgSender, feed, postId, params); 21 | } 22 | 23 | function execute(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params) 24 | external 25 | payable 26 | override 27 | onlyActionHub 28 | returns (bytes memory) 29 | { 30 | return _execute(originalMsgSender, feed, postId, params); 31 | } 32 | 33 | function setDisabled( 34 | address originalMsgSender, 35 | address feed, 36 | uint256 postId, 37 | bool isDisabled, 38 | KeyValue[] calldata params 39 | ) external payable override onlyActionHub returns (bytes memory) { 40 | return _setDisabled(originalMsgSender, feed, postId, isDisabled, params); 41 | } 42 | 43 | function _configure( 44 | address originalMsgSender, 45 | address, /* feed */ 46 | uint256, /* postId */ 47 | KeyValue[] calldata /* params */ 48 | ) internal virtual returns (bytes memory) { 49 | return _configureUniversalAction(originalMsgSender); 50 | } 51 | 52 | function _execute(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params) 53 | internal 54 | virtual 55 | returns (bytes memory); 56 | 57 | function _setDisabled( 58 | address, /* originalMsgSender */ 59 | address, /* feed */ 60 | uint256, /* postId */ 61 | bool, /* isDisabled */ 62 | KeyValue[] calldata /* params */ 63 | ) internal virtual returns (bytes memory) { 64 | revert Errors.NotImplemented(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /abis/ProxyAdmin.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "inputs": [ 5 | { 6 | "name": "proxyAdminOwner", 7 | "type": "address", 8 | "internalType": "address" 9 | }, 10 | { 11 | "name": "lock", 12 | "type": "address", 13 | "internalType": "address" 14 | } 15 | ], 16 | "stateMutability": "nonpayable" 17 | }, 18 | { 19 | "type": "function", 20 | "name": "call", 21 | "inputs": [ 22 | { 23 | "name": "to", 24 | "type": "address", 25 | "internalType": "address" 26 | }, 27 | { 28 | "name": "value", 29 | "type": "uint256", 30 | "internalType": "uint256" 31 | }, 32 | { 33 | "name": "data", 34 | "type": "bytes", 35 | "internalType": "bytes" 36 | } 37 | ], 38 | "outputs": [ 39 | { 40 | "name": "", 41 | "type": "bytes", 42 | "internalType": "bytes" 43 | } 44 | ], 45 | "stateMutability": "payable" 46 | }, 47 | { 48 | "type": "function", 49 | "name": "owner", 50 | "inputs": [], 51 | "outputs": [ 52 | { 53 | "name": "", 54 | "type": "address", 55 | "internalType": "address" 56 | } 57 | ], 58 | "stateMutability": "view" 59 | }, 60 | { 61 | "type": "function", 62 | "name": "transferOwnership", 63 | "inputs": [ 64 | { 65 | "name": "newOwner", 66 | "type": "address", 67 | "internalType": "address" 68 | } 69 | ], 70 | "outputs": [], 71 | "stateMutability": "nonpayable" 72 | }, 73 | { 74 | "type": "event", 75 | "name": "Lens_Ownable_OwnershipTransferred", 76 | "inputs": [ 77 | { 78 | "name": "previousOwner", 79 | "type": "address", 80 | "indexed": true, 81 | "internalType": "address" 82 | }, 83 | { 84 | "name": "newOwner", 85 | "type": "address", 86 | "indexed": true, 87 | "internalType": "address" 88 | } 89 | ], 90 | "anonymous": false 91 | }, 92 | { 93 | "type": "error", 94 | "name": "InvalidMsgSender", 95 | "inputs": [] 96 | }, 97 | { 98 | "type": "error", 99 | "name": "Locked", 100 | "inputs": [] 101 | }, 102 | { 103 | "type": "error", 104 | "name": "NotAContract", 105 | "inputs": [] 106 | } 107 | ] -------------------------------------------------------------------------------- /contracts/core/libraries/CallLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | 7 | library CallLib { 8 | function safecall(address target, uint256 value, bytes memory data) internal returns (bool, bytes memory) { 9 | (bool callSucceeded, bytes memory returnData) = target.call{value: value}(data); 10 | if (callSucceeded) { 11 | require(returnData.length != 0 || target.code.length != 0, Errors.NotAContract()); 12 | } 13 | return (callSucceeded, returnData); 14 | } 15 | 16 | function handledcall(address target, uint256 value, bytes memory data) internal returns (bytes memory) { 17 | (bool callSucceeded, bytes memory returnData) = target.call{value: value}(data); 18 | return _handleCall(callSucceeded, returnData); 19 | } 20 | 21 | function handledsafecall(address target, uint256 value, bytes memory data) internal returns (bytes memory) { 22 | (bool callSucceeded, bytes memory returnData) = safecall(target, value, data); 23 | return _handleCall(callSucceeded, returnData); 24 | } 25 | 26 | function safecall(address target, bytes memory data) internal returns (bool, bytes memory) { 27 | return safecall(target, 0, data); 28 | } 29 | 30 | function handledcall(address target, bytes memory data) internal returns (bytes memory) { 31 | return handledcall(target, 0, data); 32 | } 33 | 34 | function handledsafecall(address target, bytes memory data) internal returns (bytes memory) { 35 | return handledsafecall(target, 0, data); 36 | } 37 | 38 | function _handleCall(bool callSucceeded, bytes memory returnData) private pure returns (bytes memory) { 39 | if (!callSucceeded) { 40 | assembly { 41 | // Get the length of the return data, which contains the error message or selector, as the call failed 42 | let length := mload(returnData) 43 | // If the returned data length is greater than zero... 44 | if iszero(iszero(length)) { 45 | // ...revert with the same error message or selector 46 | revert(add(returnData, 32), length) 47 | } 48 | // else, revert without any error message nor selector 49 | revert(0, 0) 50 | } 51 | } 52 | return returnData; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /abis/IFollowRule.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "configure", 5 | "inputs": [ 6 | { 7 | "name": "configSalt", 8 | "type": "bytes32", 9 | "internalType": "bytes32" 10 | }, 11 | { 12 | "name": "account", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "ruleParams", 18 | "type": "tuple[]", 19 | "internalType": "struct KeyValue[]", 20 | "components": [ 21 | { 22 | "name": "key", 23 | "type": "bytes32", 24 | "internalType": "bytes32" 25 | }, 26 | { 27 | "name": "value", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ] 32 | } 33 | ], 34 | "outputs": [], 35 | "stateMutability": "nonpayable" 36 | }, 37 | { 38 | "type": "function", 39 | "name": "processFollow", 40 | "inputs": [ 41 | { 42 | "name": "configSalt", 43 | "type": "bytes32", 44 | "internalType": "bytes32" 45 | }, 46 | { 47 | "name": "originalMsgSender", 48 | "type": "address", 49 | "internalType": "address" 50 | }, 51 | { 52 | "name": "followerAccount", 53 | "type": "address", 54 | "internalType": "address" 55 | }, 56 | { 57 | "name": "accountToFollow", 58 | "type": "address", 59 | "internalType": "address" 60 | }, 61 | { 62 | "name": "primitiveParams", 63 | "type": "tuple[]", 64 | "internalType": "struct KeyValue[]", 65 | "components": [ 66 | { 67 | "name": "key", 68 | "type": "bytes32", 69 | "internalType": "bytes32" 70 | }, 71 | { 72 | "name": "value", 73 | "type": "bytes", 74 | "internalType": "bytes" 75 | } 76 | ] 77 | }, 78 | { 79 | "name": "ruleParams", 80 | "type": "tuple[]", 81 | "internalType": "struct KeyValue[]", 82 | "components": [ 83 | { 84 | "name": "key", 85 | "type": "bytes32", 86 | "internalType": "bytes32" 87 | }, 88 | { 89 | "name": "value", 90 | "type": "bytes", 91 | "internalType": "bytes" 92 | } 93 | ] 94 | } 95 | ], 96 | "outputs": [], 97 | "stateMutability": "nonpayable" 98 | } 99 | ] -------------------------------------------------------------------------------- /abis/TokenGatedRule.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getMetadataURI", 5 | "inputs": [ 6 | { 7 | "name": "source", 8 | "type": "address", 9 | "internalType": "address" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "string", 16 | "internalType": "string" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | }, 21 | { 22 | "type": "function", 23 | "name": "getMetadataURI", 24 | "inputs": [], 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "string", 29 | "internalType": "string" 30 | } 31 | ], 32 | "stateMutability": "view" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "owner", 37 | "inputs": [], 38 | "outputs": [ 39 | { 40 | "name": "", 41 | "type": "address", 42 | "internalType": "address" 43 | } 44 | ], 45 | "stateMutability": "view" 46 | }, 47 | { 48 | "type": "function", 49 | "name": "setMetadataURI", 50 | "inputs": [ 51 | { 52 | "name": "metadataURI", 53 | "type": "string", 54 | "internalType": "string" 55 | } 56 | ], 57 | "outputs": [], 58 | "stateMutability": "nonpayable" 59 | }, 60 | { 61 | "type": "function", 62 | "name": "transferOwnership", 63 | "inputs": [ 64 | { 65 | "name": "newOwner", 66 | "type": "address", 67 | "internalType": "address" 68 | } 69 | ], 70 | "outputs": [], 71 | "stateMutability": "nonpayable" 72 | }, 73 | { 74 | "type": "event", 75 | "name": "Lens_Ownable_OwnershipTransferred", 76 | "inputs": [ 77 | { 78 | "name": "previousOwner", 79 | "type": "address", 80 | "indexed": true, 81 | "internalType": "address" 82 | }, 83 | { 84 | "name": "newOwner", 85 | "type": "address", 86 | "indexed": true, 87 | "internalType": "address" 88 | } 89 | ], 90 | "anonymous": false 91 | }, 92 | { 93 | "type": "event", 94 | "name": "Lens_Rule_MetadataURISet", 95 | "inputs": [ 96 | { 97 | "name": "metadataURI", 98 | "type": "string", 99 | "indexed": false, 100 | "internalType": "string" 101 | } 102 | ], 103 | "anonymous": false 104 | }, 105 | { 106 | "type": "error", 107 | "name": "InvalidMsgSender", 108 | "inputs": [] 109 | } 110 | ] -------------------------------------------------------------------------------- /abis/OwnableMetadataBasedRule.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "getMetadataURI", 5 | "inputs": [ 6 | { 7 | "name": "source", 8 | "type": "address", 9 | "internalType": "address" 10 | } 11 | ], 12 | "outputs": [ 13 | { 14 | "name": "", 15 | "type": "string", 16 | "internalType": "string" 17 | } 18 | ], 19 | "stateMutability": "view" 20 | }, 21 | { 22 | "type": "function", 23 | "name": "getMetadataURI", 24 | "inputs": [], 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "string", 29 | "internalType": "string" 30 | } 31 | ], 32 | "stateMutability": "view" 33 | }, 34 | { 35 | "type": "function", 36 | "name": "owner", 37 | "inputs": [], 38 | "outputs": [ 39 | { 40 | "name": "", 41 | "type": "address", 42 | "internalType": "address" 43 | } 44 | ], 45 | "stateMutability": "view" 46 | }, 47 | { 48 | "type": "function", 49 | "name": "setMetadataURI", 50 | "inputs": [ 51 | { 52 | "name": "metadataURI", 53 | "type": "string", 54 | "internalType": "string" 55 | } 56 | ], 57 | "outputs": [], 58 | "stateMutability": "nonpayable" 59 | }, 60 | { 61 | "type": "function", 62 | "name": "transferOwnership", 63 | "inputs": [ 64 | { 65 | "name": "newOwner", 66 | "type": "address", 67 | "internalType": "address" 68 | } 69 | ], 70 | "outputs": [], 71 | "stateMutability": "nonpayable" 72 | }, 73 | { 74 | "type": "event", 75 | "name": "Lens_Ownable_OwnershipTransferred", 76 | "inputs": [ 77 | { 78 | "name": "previousOwner", 79 | "type": "address", 80 | "indexed": true, 81 | "internalType": "address" 82 | }, 83 | { 84 | "name": "newOwner", 85 | "type": "address", 86 | "indexed": true, 87 | "internalType": "address" 88 | } 89 | ], 90 | "anonymous": false 91 | }, 92 | { 93 | "type": "event", 94 | "name": "Lens_Rule_MetadataURISet", 95 | "inputs": [ 96 | { 97 | "name": "metadataURI", 98 | "type": "string", 99 | "indexed": false, 100 | "internalType": "string" 101 | } 102 | ], 103 | "anonymous": false 104 | }, 105 | { 106 | "type": "error", 107 | "name": "InvalidMsgSender", 108 | "inputs": [] 109 | } 110 | ] -------------------------------------------------------------------------------- /contracts/extensions/access/OwnerAdminOnlyAccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Events} from "lens-modules/contracts/core/types/Events.sol"; 6 | import {RoleBasedAccessControl} from "lens-modules/contracts/core/access/RoleBasedAccessControl.sol"; 7 | import {Access} from "lens-modules/contracts/core/interfaces/IRoleBasedAccessControl.sol"; 8 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 9 | import {ILock} from "lens-modules/contracts/core/interfaces/ILock.sol"; 10 | 11 | contract OwnerAdminOnlyAccessControl is RoleBasedAccessControl { 12 | ILock immutable LOCK; 13 | 14 | /// @custom:keccak lens.role.Admin 15 | uint256 constant ADMIN_ROLE_ID = uint256(0xfcbeadd75a96b5f8140d8c80f7c8d81ccbd7c4caa9592217bc8936b9eaabee75); 16 | /// @custom:keccak lens.contract.AccessControl.OwnerAdminOnlyAccessControl 17 | bytes32 constant OWNER_ADMIN_ONLY_CONTRACT_TYPE = 0x366c180b93c016d94aa781dd984842068840b0dc26dec0c4bf64de7c26ee02bb; 18 | 19 | constructor(address owner, address lock) RoleBasedAccessControl(owner) { 20 | _setAccess(ADMIN_ROLE_ID, ANY_CONTRACT_ADDRESS, ANY_PERMISSION_ID, Access.GRANTED); 21 | LOCK = ILock(lock); 22 | LOCK.isLocked(); // Aims to verify the given address follows ILock interface 23 | } 24 | 25 | function _beforeGrantingRole(address account, uint256 roleId) internal virtual override { 26 | require(roleId == ADMIN_ROLE_ID, Errors.InvalidParameter()); 27 | super._beforeGrantingRole(account, roleId); 28 | } 29 | 30 | function canChangeAccessControl(address account, address /* contractAddress */ ) 31 | external 32 | view 33 | virtual 34 | override 35 | returns (bool) 36 | { 37 | return account == owner() && !LOCK.isLocked(); 38 | } 39 | 40 | function _beforeSettingAccess( 41 | uint256, /*roleId*/ 42 | address, /*contractAddress*/ 43 | uint256, /*permissionId*/ 44 | Access /*access*/ 45 | ) internal virtual override { 46 | revert Errors.NotImplemented(); 47 | } 48 | 49 | function getType() external pure virtual override returns (bytes32) { 50 | return OWNER_ADMIN_ONLY_CONTRACT_TYPE; 51 | } 52 | 53 | function _emitLensContractDeployedEvent() internal virtual override { 54 | emit Events.Lens_Contract_Deployed({ 55 | contractType: "lens.contract.AccessControl", 56 | flavour: "lens.contract.AccessControl.OwnerAdminOnlyAccessControl" 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /contracts/migration/factories/MigrationLensFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import { 6 | LensFactory, FactoryConstructorParams, RuleConstructorParams 7 | } from "lens-modules/contracts/extensions/factories/LensFactory.sol"; 8 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 9 | import {IRoleBasedAccessControl} from "lens-modules/contracts/core/interfaces/IRoleBasedAccessControl.sol"; 10 | import {RuleChange} from "lens-modules/contracts/core/types/Types.sol"; 11 | import {PermissionlessAccessControl} from "lens-modules/contracts/extensions/access/PermissionlessAccessControl.sol"; 12 | 13 | contract MigrationLensFactory is LensFactory, EventEmitter { 14 | constructor(FactoryConstructorParams memory factories, RuleConstructorParams memory rules) 15 | LensFactory(factories, rules) 16 | {} 17 | 18 | function _deployAccessControl(address, /* owner */ address[] memory /* admins */ ) 19 | internal 20 | override 21 | returns (IRoleBasedAccessControl) 22 | { 23 | PermissionlessAccessControl accessControl = new PermissionlessAccessControl(); 24 | return IRoleBasedAccessControl(address(accessControl)); 25 | } 26 | 27 | function _injectRuleAccessControl(RuleChange memory rule, address /* accessControl */ ) 28 | internal 29 | pure 30 | override 31 | returns (RuleChange memory) 32 | { 33 | return rule; 34 | } 35 | 36 | function _injectRuleAccessControl(RuleChange[] memory rules, address /* accessControl */ ) 37 | internal 38 | pure 39 | override 40 | returns (RuleChange[] memory) 41 | { 42 | return rules; 43 | } 44 | 45 | function _prepareRules(RuleChange[] memory rules, bytes4, /* ruleSelector */ address /* accessControl */ ) 46 | internal 47 | pure 48 | override 49 | returns (RuleChange[] memory) 50 | { 51 | return rules; 52 | } 53 | 54 | function _prepareFeedRulesBasedOnGroup( 55 | RuleChange[] memory feedRules, 56 | IRoleBasedAccessControl, /* feedAccessControl */ 57 | address, /* group */ 58 | bool /* allowNonMembersToReply */ 59 | ) internal pure override returns (RuleChange[] memory) { 60 | return feedRules; 61 | } 62 | 63 | function _injectRulesForNamespace(RuleChange[] memory rules, address /* accessControl */ ) 64 | internal 65 | pure 66 | override 67 | returns (RuleChange[] memory) 68 | { 69 | return rules; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /abis/ITransparentUpgradeableProxy.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "admin", 5 | "inputs": [], 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "address", 10 | "internalType": "address" 11 | } 12 | ], 13 | "stateMutability": "view" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "changeAdmin", 18 | "inputs": [ 19 | { 20 | "name": "", 21 | "type": "address", 22 | "internalType": "address" 23 | } 24 | ], 25 | "outputs": [], 26 | "stateMutability": "nonpayable" 27 | }, 28 | { 29 | "type": "function", 30 | "name": "implementation", 31 | "inputs": [], 32 | "outputs": [ 33 | { 34 | "name": "", 35 | "type": "address", 36 | "internalType": "address" 37 | } 38 | ], 39 | "stateMutability": "view" 40 | }, 41 | { 42 | "type": "function", 43 | "name": "upgradeTo", 44 | "inputs": [ 45 | { 46 | "name": "", 47 | "type": "address", 48 | "internalType": "address" 49 | } 50 | ], 51 | "outputs": [], 52 | "stateMutability": "nonpayable" 53 | }, 54 | { 55 | "type": "function", 56 | "name": "upgradeToAndCall", 57 | "inputs": [ 58 | { 59 | "name": "", 60 | "type": "address", 61 | "internalType": "address" 62 | }, 63 | { 64 | "name": "", 65 | "type": "bytes", 66 | "internalType": "bytes" 67 | } 68 | ], 69 | "outputs": [], 70 | "stateMutability": "payable" 71 | }, 72 | { 73 | "type": "event", 74 | "name": "AdminChanged", 75 | "inputs": [ 76 | { 77 | "name": "previousAdmin", 78 | "type": "address", 79 | "indexed": false, 80 | "internalType": "address" 81 | }, 82 | { 83 | "name": "newAdmin", 84 | "type": "address", 85 | "indexed": false, 86 | "internalType": "address" 87 | } 88 | ], 89 | "anonymous": false 90 | }, 91 | { 92 | "type": "event", 93 | "name": "BeaconUpgraded", 94 | "inputs": [ 95 | { 96 | "name": "beacon", 97 | "type": "address", 98 | "indexed": true, 99 | "internalType": "address" 100 | } 101 | ], 102 | "anonymous": false 103 | }, 104 | { 105 | "type": "event", 106 | "name": "Upgraded", 107 | "inputs": [ 108 | { 109 | "name": "implementation", 110 | "type": "address", 111 | "indexed": true, 112 | "internalType": "address" 113 | } 114 | ], 115 | "anonymous": false 116 | } 117 | ] -------------------------------------------------------------------------------- /contracts/core/primitives/namespace/NamespaceCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | 7 | library NamespaceCore { 8 | // Storage 9 | 10 | struct Storage { 11 | string namespace; 12 | mapping(string => bool) usernameExists; 13 | mapping(string => address) usernameToAccount; 14 | mapping(address => string) accountToUsername; 15 | } 16 | 17 | /// @custom:keccak lens.storage.NamespaceCore 18 | bytes32 constant STORAGE__NAMESPACE_CORE = 0x6d374ece44bcfef1b791ff4a0e88360ee8ce91bd6dc8916c39867f03ba1bfb84; 19 | 20 | function $storage() internal pure returns (Storage storage _storage) { 21 | assembly { 22 | _storage.slot := STORAGE__NAMESPACE_CORE 23 | } 24 | } 25 | 26 | // Internal functions 27 | 28 | function _createUsername(string memory username) internal { 29 | require(!$storage().usernameExists[username], Errors.AlreadyExists()); // Username must not exist yet 30 | require(bytes(username).length > 0, Errors.InvalidParameter()); // Username must not be empty 31 | require(bytes(username).length < type(uint8).max, Errors.InvalidParameter()); // Length must be less than 255 32 | $storage().usernameExists[username] = true; 33 | } 34 | 35 | function _removeUsername(string memory username) internal { 36 | require($storage().usernameExists[username], Errors.DoesNotExist()); // Username must exist 37 | require($storage().usernameToAccount[username] == address(0), Errors.UsernameAssigned()); // Username must not be assigned 38 | $storage().usernameExists[username] = false; 39 | } 40 | 41 | function _assignUsername(address account, string memory username) internal { 42 | require($storage().usernameExists[username], Errors.DoesNotExist()); // Username must exist 43 | require($storage().usernameToAccount[username] == address(0), Errors.UsernameAssigned()); // Username must not be assigned yet 44 | require(bytes($storage().accountToUsername[account]).length == 0, Errors.UsernameAssigned()); // Account must not have a username yet 45 | $storage().usernameToAccount[username] = account; 46 | $storage().accountToUsername[account] = username; 47 | } 48 | 49 | function _unassignUsername(string memory username) internal { 50 | address account = $storage().usernameToAccount[username]; 51 | require(account != address(0), Errors.RedundantStateChange()); // Username must be assigned 52 | delete $storage().accountToUsername[account]; 53 | delete $storage().usernameToAccount[username]; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/core/libraries/AccessControlLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 7 | 8 | library AccessControlLib { 9 | function requireAccess(address accessControl, address account, address contractAddress, uint256 permissionId) 10 | internal 11 | view 12 | { 13 | requireAccess(IAccessControl(accessControl), account, contractAddress, permissionId); 14 | } 15 | 16 | function requireAccess(IAccessControl accessControl, address account, address contractAddress, uint256 permissionId) 17 | internal 18 | view 19 | { 20 | require( 21 | accessControl.hasAccess({account: account, contractAddress: contractAddress, permissionId: permissionId}), 22 | Errors.AccessDenied() 23 | ); 24 | } 25 | 26 | function requireAccess(address accessControl, address account, uint256 permissionId) internal view { 27 | requireAccess(IAccessControl(accessControl), account, permissionId); 28 | } 29 | 30 | function requireAccess(IAccessControl accessControl, address account, uint256 permissionId) internal view { 31 | requireAccess(accessControl, account, address(this), permissionId); 32 | } 33 | 34 | function hasAccess(address accessControl, address account, uint256 permissionId) internal view returns (bool) { 35 | return hasAccess(IAccessControl(accessControl), account, permissionId); 36 | } 37 | 38 | function hasAccess(IAccessControl accessControl, address account, uint256 permissionId) 39 | internal 40 | view 41 | returns (bool) 42 | { 43 | return accessControl.hasAccess({account: account, contractAddress: address(this), permissionId: permissionId}); 44 | } 45 | 46 | function verifyHasAccessFunction(address accessControl) internal view { 47 | verifyHasAccessFunction(IAccessControl(accessControl)); 48 | } 49 | 50 | function verifyHasAccessFunction(IAccessControl accessControl) internal view { 51 | accessControl.hasAccess(address(this), address(this), 1); // We expect this to not panic. 52 | } 53 | 54 | function requireCanChangeAccessControl(address accessControl, address account) internal view { 55 | requireCanChangeAccessControl(IAccessControl(accessControl), account); 56 | } 57 | 58 | function requireCanChangeAccessControl(IAccessControl accessControl, address account) internal view { 59 | require( 60 | accessControl.canChangeAccessControl({account: account, contractAddress: address(this)}), 61 | Errors.AccessDenied() 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /abis/BaseSource.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "cancelNonce", 5 | "inputs": [ 6 | { 7 | "name": "nonce", 8 | "type": "uint256", 9 | "internalType": "uint256" 10 | } 11 | ], 12 | "outputs": [], 13 | "stateMutability": "nonpayable" 14 | }, 15 | { 16 | "type": "function", 17 | "name": "getTreasury", 18 | "inputs": [], 19 | "outputs": [ 20 | { 21 | "name": "", 22 | "type": "address", 23 | "internalType": "address" 24 | } 25 | ], 26 | "stateMutability": "view" 27 | }, 28 | { 29 | "type": "function", 30 | "name": "validateSource", 31 | "inputs": [ 32 | { 33 | "name": "sourceStamp", 34 | "type": "tuple", 35 | "internalType": "struct SourceStamp", 36 | "components": [ 37 | { 38 | "name": "source", 39 | "type": "address", 40 | "internalType": "address" 41 | }, 42 | { 43 | "name": "originalMsgSender", 44 | "type": "address", 45 | "internalType": "address" 46 | }, 47 | { 48 | "name": "validator", 49 | "type": "address", 50 | "internalType": "address" 51 | }, 52 | { 53 | "name": "nonce", 54 | "type": "uint256", 55 | "internalType": "uint256" 56 | }, 57 | { 58 | "name": "deadline", 59 | "type": "uint256", 60 | "internalType": "uint256" 61 | }, 62 | { 63 | "name": "signature", 64 | "type": "bytes", 65 | "internalType": "bytes" 66 | } 67 | ] 68 | } 69 | ], 70 | "outputs": [], 71 | "stateMutability": "nonpayable" 72 | }, 73 | { 74 | "type": "event", 75 | "name": "Lens_Source_NonceUsed", 76 | "inputs": [ 77 | { 78 | "name": "nonce", 79 | "type": "uint256", 80 | "indexed": false, 81 | "internalType": "uint256" 82 | } 83 | ], 84 | "anonymous": false 85 | }, 86 | { 87 | "type": "error", 88 | "name": "Expired", 89 | "inputs": [] 90 | }, 91 | { 92 | "type": "error", 93 | "name": "InvalidMsgSender", 94 | "inputs": [] 95 | }, 96 | { 97 | "type": "error", 98 | "name": "InvalidParameter", 99 | "inputs": [] 100 | }, 101 | { 102 | "type": "error", 103 | "name": "NonceUsed", 104 | "inputs": [] 105 | }, 106 | { 107 | "type": "error", 108 | "name": "RedundantStateChange", 109 | "inputs": [] 110 | }, 111 | { 112 | "type": "error", 113 | "name": "WrongSigner", 114 | "inputs": [] 115 | } 116 | ] -------------------------------------------------------------------------------- /contracts/extensions/fees/LensNativePaymentHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 6 | import {LENS_CREATE_2_ADDRESS, ILensCreate2} from "lens-modules/contracts/core/upgradeability/LensCreate2.sol"; 7 | import {CONTRACT__LENS_NATIVE_PAYMENT_HELPER} from "lens-modules/contracts/core/types/Constants.sol"; 8 | 9 | interface ILensNativePaymentHelper { 10 | function transferNative(address to, uint256 amount) external; 11 | function refundNative(address to) external; 12 | } 13 | 14 | /** 15 | * @title LensNativePaymentHelper 16 | * @notice This contract is used to help with native token payments during rules fund distribution. 17 | * @dev We assume that native token is sent here by the primitive at the beginning of the tx before processing rules. 18 | * Then, each rule permissionlessly spends funds until depleted. 19 | * At the end of the tx, if there are any remaining funds, they can be claimed back. 20 | * This contract avoids the complexity of sending native tokens back and forth between the primitive and the rules. 21 | */ 22 | contract LensNativePaymentHelper { 23 | receive() external payable {} 24 | 25 | function transferNative(address to, uint256 amount) external { 26 | require(amount <= address(this).balance, Errors.NotEnoughBalance()); 27 | _transferNative(to, amount); 28 | } 29 | 30 | function refundNative(address to) external { 31 | uint256 amount = address(this).balance; 32 | if (amount > 0) { 33 | _transferNative(to, amount); 34 | } 35 | } 36 | 37 | function _transferNative(address to, uint256 amount) internal { 38 | (bool callSucceeded,) = to.call{value: amount}(""); 39 | require(callSucceeded, Errors.FailedToTransferNative()); 40 | } 41 | } 42 | 43 | abstract contract PayableUsingNativePaymentHelper { 44 | ILensNativePaymentHelper immutable LENS_NATIVE_PAYMENT_HELPER; 45 | 46 | constructor() { 47 | LENS_NATIVE_PAYMENT_HELPER = ILensNativePaymentHelper( 48 | ILensCreate2(LENS_CREATE_2_ADDRESS).getAddress(CONTRACT__LENS_NATIVE_PAYMENT_HELPER) 49 | ); 50 | } 51 | 52 | modifier usingNativePaymentHelper() { 53 | if (msg.value > 0) { 54 | (bool callSucceeded,) = address(LENS_NATIVE_PAYMENT_HELPER).call{value: msg.value}(""); 55 | require(callSucceeded, Errors.FailedToTransferNative()); 56 | } 57 | _; 58 | // We don't do the automatic refund here because of reentrancy and denial-of-service concerns. 59 | // One can always use multi-call to trigger refundNative() after all transactions are completed. 60 | // LENS_NATIVE_PAYMENT_HELPER.refundNative(msg.sender); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contracts/rules/follow/TokenGatedFollowRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IFollowRule} from "lens-modules/contracts/core/interfaces/IFollowRule.sol"; 6 | import {TokenGatedRule} from "lens-modules/contracts/rules/base/TokenGatedRule.sol"; 7 | import {KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 9 | import {Initializable} from "lens-modules/contracts/core/upgradeability/Initializable.sol"; 10 | 11 | contract TokenGatedFollowRule is TokenGatedRule, Initializable, IFollowRule { 12 | /// @custom:keccak lens.storage.TokenGatedFollowRule 13 | bytes32 constant STORAGE__TOKEN_GATED_FOLLOW_RULE = 14 | 0xe97fbf5c7954b514ec4e26886a15690eccfbfbc3d218ff7d2972305cb75c4368; 15 | 16 | struct Storage { 17 | mapping( 18 | address graph => mapping(address account => mapping(bytes32 configSalt => TokenGateConfiguration config)) 19 | ) tokenGateConfig; 20 | } 21 | 22 | function $storage() private pure returns (Storage storage _storage) { 23 | assembly { 24 | _storage.slot := STORAGE__TOKEN_GATED_FOLLOW_RULE 25 | } 26 | } 27 | 28 | constructor() TokenGatedRule(address(0), "") { 29 | _disableInitializers(); 30 | } 31 | 32 | function initialize(address owner, string memory metadataURI) external initializer { 33 | TokenGatedRule._initialize(owner, metadataURI); 34 | } 35 | 36 | function configure(bytes32 configSalt, address account, KeyValue[] calldata ruleParams) external override { 37 | TokenGateConfiguration memory tokenGateConfig = _extractConfigurationFromParams(ruleParams); 38 | _validateTokenGateConfiguration(tokenGateConfig); 39 | $storage().tokenGateConfig[msg.sender][account][configSalt] = tokenGateConfig; 40 | } 41 | 42 | function processFollow( 43 | bytes32 configSalt, 44 | address, /* originalMsgSender */ 45 | address followerAccount, 46 | address accountToFollow, 47 | KeyValue[] calldata, /* primitiveParams */ 48 | KeyValue[] calldata /* ruleParams */ 49 | ) external view override { 50 | _validateTokenBalance($storage().tokenGateConfig[msg.sender][accountToFollow][configSalt], followerAccount); 51 | } 52 | 53 | function _extractConfigurationFromParams(KeyValue[] calldata params) 54 | internal 55 | pure 56 | returns (TokenGateConfiguration memory) 57 | { 58 | for (uint256 i = 0; i < params.length; i++) { 59 | if (params[i].key == PARAM__TOKEN_GATE) { 60 | return abi.decode(params[i].value, (TokenGateConfiguration)); 61 | } 62 | } 63 | revert Errors.NotFound(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contracts/rules/graph/RestrictedSignersGraphRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IGraphRule} from "../../core/interfaces/IGraphRule.sol"; 6 | import {RestrictedSignersRule, EIP712Signature} from "../base/RestrictedSignersRule.sol"; 7 | import {KeyValue, RuleChange} from "../../core/types/Types.sol"; 8 | import {EIP712EncodingLib} from "../../core/libraries/EIP712EncodingLib.sol"; 9 | 10 | contract RestrictedSignersGraphRule is RestrictedSignersRule, IGraphRule { 11 | constructor(address owner, string memory metadataURI) RestrictedSignersRule(owner, metadataURI) {} 12 | 13 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override { 14 | _configure(configSalt, ruleParams); 15 | } 16 | 17 | function processFollow( 18 | bytes32 configSalt, 19 | address originalMsgSender, 20 | address followerAccount, 21 | address accountToFollow, 22 | KeyValue[] calldata primitiveParams, 23 | KeyValue[] calldata ruleParams 24 | ) external override { 25 | _validateRestrictedSignerMessage({ 26 | configSalt: configSalt, 27 | functionSelector: IGraphRule.processFollow.selector, 28 | abiEncodedFunctionParams: abi.encode( 29 | originalMsgSender, followerAccount, accountToFollow, EIP712EncodingLib.encodeForEIP712(primitiveParams) 30 | ), 31 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 32 | }); 33 | } 34 | 35 | function processUnfollow( 36 | bytes32 configSalt, 37 | address originalMsgSender, 38 | address followerAccount, 39 | address accountToUnfollow, 40 | KeyValue[] calldata primitiveParams, 41 | KeyValue[] calldata ruleParams 42 | ) external override { 43 | _validateRestrictedSignerMessage({ 44 | configSalt: configSalt, 45 | functionSelector: IGraphRule.processUnfollow.selector, 46 | abiEncodedFunctionParams: abi.encode( 47 | originalMsgSender, followerAccount, accountToUnfollow, EIP712EncodingLib.encodeForEIP712(primitiveParams) 48 | ), 49 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 50 | }); 51 | } 52 | 53 | function processFollowRuleChanges( 54 | bytes32 configSalt, 55 | address account, 56 | RuleChange[] calldata ruleChanges, 57 | KeyValue[] calldata ruleParams 58 | ) external override { 59 | _validateRestrictedSignerMessage({ 60 | configSalt: configSalt, 61 | functionSelector: IGraphRule.processFollowRuleChanges.selector, 62 | abiEncodedFunctionParams: abi.encode(account, EIP712EncodingLib.encodeForEIP712(ruleChanges)), 63 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/migration/primitives/MigrationGraph.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {GraphCore as Core} from "lens-modules/contracts/core/primitives/graph/GraphCore.sol"; 6 | import {Graph} from "lens-modules/contracts/core/primitives/graph/Graph.sol"; 7 | import {RuleProcessingParams, KeyValue} from "lens-modules/contracts/core/types/Types.sol"; 8 | import {Follow} from "lens-modules/contracts/core/interfaces/IGraph.sol"; 9 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 10 | import {EventEmitter} from "lens-modules/contracts/migration/EventEmitter.sol"; 11 | 12 | /** 13 | * Special Graph implementation to allow data migrations from Lens V2 to Lens V3 14 | */ 15 | contract MigrationGraph is Graph, EventEmitter { 16 | function follow( 17 | address followerAccount, 18 | address accountToFollow, 19 | KeyValue[] calldata customParams, 20 | RuleProcessingParams[] calldata graphRulesProcessingParams, 21 | RuleProcessingParams[] calldata followRulesProcessingParams, 22 | KeyValue[] calldata extraData 23 | ) external override returns (uint256) { 24 | require(customParams.length > 0, Errors.InvalidParameter()); 25 | (uint256 followId, uint256 timestamp) = abi.decode(customParams[0].value, (uint256, uint256)); 26 | _migrateFollow(followerAccount, accountToFollow, followId, timestamp); 27 | emit Lens_Graph_Followed( 28 | followerAccount, 29 | accountToFollow, 30 | followId, 31 | customParams, 32 | graphRulesProcessingParams, 33 | followRulesProcessingParams, 34 | address(0), 35 | extraData 36 | ); 37 | return followId; 38 | } 39 | 40 | function _migrateFollow(address followerAccount, address accountToFollow, uint256 followId, uint256 timestamp) 41 | internal 42 | { 43 | require(followerAccount != accountToFollow, Errors.ActionOnSelf()); 44 | require(followId != 0, Errors.InvalidParameter()); 45 | require(followerAccount != address(0), Errors.InvalidParameter()); 46 | require(accountToFollow != address(0), Errors.InvalidParameter()); 47 | require(Core.$storage().follows[followerAccount][accountToFollow].id == 0, Errors.CannotFollowAgain()); 48 | require(Core.$storage().followers[accountToFollow][followId] == address(0), Errors.AlreadyExists()); 49 | if (Core.$storage().lastFollowIdAssigned[accountToFollow] < followId) { 50 | Core.$storage().lastFollowIdAssigned[accountToFollow] = followId; 51 | } 52 | Core.$storage().follows[followerAccount][accountToFollow] = Follow({id: followId, timestamp: timestamp}); 53 | Core.$storage().followers[accountToFollow][followId] = followerAccount; 54 | Core.$storage().followersCount[accountToFollow]++; 55 | Core.$storage().followingCount[followerAccount]++; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/actions/account/TippingAccountAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {OwnableMetadataBasedAccountAction} from "lens-modules/contracts/actions/account/base/OwnableMetadataBasedAccountAction.sol"; 6 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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"; 12 | 13 | contract TippingAccountAction is LensPaymentHandler, OwnableMetadataBasedAccountAction, Initializable { 14 | using SafeERC20 for IERC20; 15 | 16 | /// @custom:keccak lens.param.amount 17 | bytes32 constant PARAM__TIP_AMOUNT = 0xc8a06abcb0f2366f32dc2741bdf075c3215e3108918311ec0ac742f1ffd37f49; 18 | /// @custom:keccak lens.param.token 19 | bytes32 public constant PARAM__TIP_TOKEN = 0xee737c77be2981e91c179485406e6d793521b20aca5e2137b6c497949a74bc94; 20 | /// @custom:keccak lens.param.referrals 21 | bytes32 constant PARAM__REFERRALS = 0x183a1b7fdb9626f5ae4e8cac88ee13cc03b29800d2690f61e2a2566f76d8773f; 22 | 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 | } 32 | 33 | function _execute(address originalMsgSender, address account, KeyValue[] calldata params) 34 | internal 35 | override 36 | returns (bytes memory) 37 | { 38 | address erc20Token; 39 | uint256 tipAmount; 40 | RecipientData[] memory referrals = new RecipientData[](0); 41 | for (uint256 i = 0; i < params.length; i++) { 42 | if (params[i].key == PARAM__TIP_AMOUNT) { 43 | tipAmount = abi.decode(params[i].value, (uint256)); 44 | } else if (params[i].key == PARAM__TIP_TOKEN) { 45 | erc20Token = abi.decode(params[i].value, (address)); 46 | } else if (params[i].key == PARAM__REFERRALS) { 47 | referrals = abi.decode(params[i].value, (RecipientData[])); 48 | } 49 | } 50 | require(tipAmount > 0, Errors.InvalidParameter()); 51 | _handlePayment({ 52 | payer: originalMsgSender, 53 | token: erc20Token, 54 | amount: tipAmount, 55 | recipient: account, 56 | referrals: referrals, 57 | referralFeeBps: REFERRALS_FEE_MAX_BPS 58 | }); 59 | return ""; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/rules/base/TokenGatedRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; 6 | import {OwnableMetadataBasedRule} from "lens-modules/contracts/rules/base/OwnableMetadataBasedRule.sol"; 7 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 8 | 9 | interface IToken { 10 | /** 11 | * @dev Returns the amount of ERC20/ERC721 tokens owned by `account`. 12 | */ 13 | function balanceOf(address account) external view returns (uint256); 14 | } 15 | 16 | abstract contract TokenGatedRule is OwnableMetadataBasedRule { 17 | uint256 internal constant ERC20 = 20; 18 | uint256 internal constant ERC721 = 721; 19 | uint256 internal constant ERC1155 = 1155; 20 | 21 | /// @custom:keccak lens.param.tokenGate 22 | bytes32 constant PARAM__TOKEN_GATE = 0xb395c61ecf6294b637d557db500d79f61694bd0d2e3c9b0d54383cc4a6c6dcea; 23 | 24 | struct TokenGateConfiguration { 25 | uint256 tokenStandard; 26 | address token; 27 | uint256 typeId; // Optional, only for ERC-1155 tokens. Use 0 for ERC-20/ERC-721 tokens. 28 | uint256 amount; 29 | } 30 | 31 | constructor(address owner, string memory metadataURI) OwnableMetadataBasedRule(owner, metadataURI) {} 32 | 33 | function _initialize(address owner, string memory metadataURI) internal override { 34 | super._initialize(owner, metadataURI); 35 | } 36 | 37 | function _validateTokenGateConfiguration(TokenGateConfiguration memory configuration) internal view { 38 | require(configuration.amount > 0, Errors.InvalidParameter()); 39 | if (configuration.tokenStandard == ERC20 || configuration.tokenStandard == ERC721) { 40 | // Expects token to support ERC-20/ERC-721 balanceOf by not reverting 41 | IToken(configuration.token).balanceOf(address(this)); 42 | } else if (configuration.tokenStandard == ERC1155) { 43 | // Expects token to support ERC-1155 balanceOf by not reverting 44 | IERC1155(configuration.token).balanceOf(address(this), configuration.typeId); 45 | } else { 46 | revert Errors.InvalidParameter(); 47 | } 48 | } 49 | 50 | function _validateTokenBalance(TokenGateConfiguration memory configuration, address owner) internal view { 51 | require(_checkTokenBalance(configuration, owner), Errors.NotEnough()); 52 | } 53 | 54 | function _checkTokenBalance(TokenGateConfiguration memory configuration, address owner) 55 | internal 56 | view 57 | returns (bool) 58 | { 59 | uint256 balance; 60 | if (configuration.tokenStandard == ERC20 || configuration.tokenStandard == ERC721) { 61 | balance = IToken(configuration.token).balanceOf(owner); 62 | } else { 63 | balance = IERC1155(configuration.token).balanceOf(owner, configuration.typeId); 64 | } 65 | return balance >= configuration.amount; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /contracts/core/access/AccessControlled.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IAccessControl} from "lens-modules/contracts/core/interfaces/IAccessControl.sol"; 6 | import {AccessControlLib} from "lens-modules/contracts/core/libraries/AccessControlLib.sol"; 7 | import {IAccessControlled} from "lens-modules/contracts/core/interfaces/IAccessControlled.sol"; 8 | 9 | abstract contract AccessControlled is IAccessControlled { 10 | using AccessControlLib for IAccessControl; 11 | using AccessControlLib for address; 12 | 13 | event Lens_AccessControlAdded(address indexed accessControl, bytes32 indexed accessControlType); 14 | event Lens_AccessControlUpdated(address indexed accessControl, bytes32 indexed accessControlType); 15 | 16 | struct AccessControlledStorage { 17 | address accessControl; 18 | } 19 | 20 | /// @custom:keccak lens.storage.AccessControlledStorage.AccessControlledStorage 21 | bytes32 constant STORAGE__ACCESS_CONTROLLED = 0xbd033a0ffbb1596134cd289270549cdbb5543523671bd5bbfcdc89a3f6decd75; 22 | 23 | function $accessControlledStorage() private pure returns (AccessControlledStorage storage _storage) { 24 | assembly { 25 | _storage.slot := STORAGE__ACCESS_CONTROLLED 26 | } 27 | } 28 | 29 | function _initialize(IAccessControl accessControl) internal { 30 | accessControl.verifyHasAccessFunction(); 31 | _setAccessControl(accessControl); 32 | } 33 | 34 | function _emitPIDs() internal virtual {} 35 | 36 | function _requireAccess(address account, uint256 permissionId) internal view { 37 | _accessControl().requireAccess(account, permissionId); 38 | } 39 | 40 | function _hasAccess(address account, uint256 permissionId) internal view returns (bool) { 41 | return _accessControl().hasAccess(account, permissionId); 42 | } 43 | 44 | // Access Controlled Functions 45 | function setAccessControl(IAccessControl newAccessControl) external { 46 | _accessControl().requireCanChangeAccessControl(msg.sender); 47 | newAccessControl.verifyHasAccessFunction(); 48 | _setAccessControl(newAccessControl); 49 | } 50 | 51 | // Internal functions 52 | 53 | function _accessControl() internal view returns (IAccessControl) { 54 | return IAccessControl($accessControlledStorage().accessControl); 55 | } 56 | 57 | function _setAccessControl(IAccessControl newAccessControl) internal { 58 | address oldAccessControl = $accessControlledStorage().accessControl; 59 | $accessControlledStorage().accessControl = address(newAccessControl); 60 | if (oldAccessControl == address(0)) { 61 | emit Lens_AccessControlAdded(address(newAccessControl), newAccessControl.getType()); 62 | } else { 63 | emit Lens_AccessControlUpdated(address(newAccessControl), newAccessControl.getType()); 64 | } 65 | } 66 | 67 | // Getters 68 | 69 | function getAccessControl() external view override returns (IAccessControl) { 70 | return _accessControl(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /contracts/actions/post/TippingPostAction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {OwnableMetadataBasedPostAction} from "lens-modules/contracts/actions/post/base/OwnableMetadataBasedPostAction.sol"; 6 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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"; 13 | 14 | contract TippingPostAction is LensPaymentHandler, OwnableMetadataBasedPostAction, Initializable { 15 | using SafeERC20 for IERC20; 16 | 17 | /// @custom:keccak lens.param.amount 18 | bytes32 constant PARAM__TIP_AMOUNT = 0xc8a06abcb0f2366f32dc2741bdf075c3215e3108918311ec0ac742f1ffd37f49; 19 | /// @custom:keccak lens.param.token 20 | bytes32 constant PARAM__TIP_TOKEN = 0xee737c77be2981e91c179485406e6d793521b20aca5e2137b6c497949a74bc94; 21 | /// @custom:keccak lens.param.referrals 22 | bytes32 constant PARAM__REFERRALS = 0x183a1b7fdb9626f5ae4e8cac88ee13cc03b29800d2690f61e2a2566f76d8773f; 23 | 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 | } 33 | 34 | function _execute(address originalMsgSender, address feed, uint256 postId, KeyValue[] calldata params) 35 | internal 36 | override 37 | returns (bytes memory) 38 | { 39 | address erc20Token; 40 | uint256 tipAmount; 41 | RecipientData[] memory referrals = new RecipientData[](0); 42 | for (uint256 i = 0; i < params.length; i++) { 43 | if (params[i].key == PARAM__TIP_AMOUNT) { 44 | tipAmount = abi.decode(params[i].value, (uint256)); 45 | } else if (params[i].key == PARAM__TIP_TOKEN) { 46 | erc20Token = abi.decode(params[i].value, (address)); 47 | } else if (params[i].key == PARAM__REFERRALS) { 48 | referrals = abi.decode(params[i].value, (RecipientData[])); 49 | } 50 | } 51 | require(tipAmount > 0, Errors.InvalidParameter()); 52 | address account = IFeed(feed).getPostAuthor(postId); 53 | _handlePayment({ 54 | payer: originalMsgSender, 55 | token: erc20Token, 56 | amount: tipAmount, 57 | recipient: account, 58 | referrals: referrals, 59 | referralFeeBps: REFERRALS_FEE_MAX_BPS 60 | }); 61 | return abi.encode(account); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/core/primitives/graph/GraphCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {Follow} from "lens-modules/contracts/core/interfaces/IGraph.sol"; 6 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 7 | 8 | library GraphCore { 9 | // Storage 10 | 11 | struct Storage { 12 | mapping(address => uint256) lastFollowIdAssigned; 13 | mapping(address => mapping(address => Follow)) follows; 14 | mapping(address => mapping(uint256 => address)) followers; 15 | mapping(address => uint256) followersCount; 16 | mapping(address => uint256) followingCount; 17 | } 18 | 19 | /// @custom:keccak lens.storage.GraphCore 20 | bytes32 constant STORAGE__GRAPH_CORE = 0x5863e3ed01973a22e9d816ccf1175242559c6aa633e210d5eef6ba360542fe03; 21 | 22 | function $storage() internal pure returns (Storage storage _storage) { 23 | assembly { 24 | _storage.slot := STORAGE__GRAPH_CORE 25 | } 26 | } 27 | 28 | // Internal functions - Use these functions to be called as an inlined library 29 | 30 | function _follow(address followerAccount, address accountToFollow, uint256 followId, uint256 timestamp) 31 | internal 32 | returns (uint256) 33 | { 34 | require(followerAccount != address(0), Errors.InvalidParameter()); 35 | require(accountToFollow != address(0), Errors.InvalidParameter()); 36 | require(followerAccount != accountToFollow, Errors.ActionOnSelf()); 37 | require($storage().follows[followerAccount][accountToFollow].id == 0, Errors.CannotFollowAgain()); 38 | if (followId == 0) { 39 | followId = ++$storage().lastFollowIdAssigned[accountToFollow]; 40 | } else { 41 | require(followId <= $storage().lastFollowIdAssigned[accountToFollow], Errors.InvalidParameter()); // Only previous Follow IDs allowed to be reused 42 | require($storage().followers[accountToFollow][followId] == address(0), Errors.AlreadyExists()); // Follow ID is already taken 43 | } 44 | $storage().follows[followerAccount][accountToFollow] = Follow({id: followId, timestamp: timestamp}); 45 | $storage().followers[accountToFollow][followId] = followerAccount; 46 | $storage().followersCount[accountToFollow]++; 47 | $storage().followingCount[followerAccount]++; 48 | return followId; 49 | } 50 | 51 | function _unfollow(address followerAccount, address accountToUnfollow) internal returns (uint256) { 52 | require(followerAccount != address(0), Errors.InvalidParameter()); 53 | require(accountToUnfollow != address(0), Errors.InvalidParameter()); 54 | uint256 followId = $storage().follows[followerAccount][accountToUnfollow].id; 55 | require(followId != 0, Errors.NotFollowing()); // Must be following 56 | $storage().followersCount[accountToUnfollow]--; 57 | $storage().followingCount[followerAccount]--; 58 | delete $storage().followers[accountToUnfollow][followId]; 59 | delete $storage().follows[followerAccount][accountToUnfollow]; 60 | return followId; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /abis/IAccountAction.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "configure", 5 | "inputs": [ 6 | { 7 | "name": "originalMsgSender", 8 | "type": "address", 9 | "internalType": "address" 10 | }, 11 | { 12 | "name": "account", 13 | "type": "address", 14 | "internalType": "address" 15 | }, 16 | { 17 | "name": "params", 18 | "type": "tuple[]", 19 | "internalType": "struct KeyValue[]", 20 | "components": [ 21 | { 22 | "name": "key", 23 | "type": "bytes32", 24 | "internalType": "bytes32" 25 | }, 26 | { 27 | "name": "value", 28 | "type": "bytes", 29 | "internalType": "bytes" 30 | } 31 | ] 32 | } 33 | ], 34 | "outputs": [ 35 | { 36 | "name": "", 37 | "type": "bytes", 38 | "internalType": "bytes" 39 | } 40 | ], 41 | "stateMutability": "payable" 42 | }, 43 | { 44 | "type": "function", 45 | "name": "execute", 46 | "inputs": [ 47 | { 48 | "name": "originalMsgSender", 49 | "type": "address", 50 | "internalType": "address" 51 | }, 52 | { 53 | "name": "account", 54 | "type": "address", 55 | "internalType": "address" 56 | }, 57 | { 58 | "name": "params", 59 | "type": "tuple[]", 60 | "internalType": "struct KeyValue[]", 61 | "components": [ 62 | { 63 | "name": "key", 64 | "type": "bytes32", 65 | "internalType": "bytes32" 66 | }, 67 | { 68 | "name": "value", 69 | "type": "bytes", 70 | "internalType": "bytes" 71 | } 72 | ] 73 | } 74 | ], 75 | "outputs": [ 76 | { 77 | "name": "", 78 | "type": "bytes", 79 | "internalType": "bytes" 80 | } 81 | ], 82 | "stateMutability": "payable" 83 | }, 84 | { 85 | "type": "function", 86 | "name": "setDisabled", 87 | "inputs": [ 88 | { 89 | "name": "originalMsgSender", 90 | "type": "address", 91 | "internalType": "address" 92 | }, 93 | { 94 | "name": "account", 95 | "type": "address", 96 | "internalType": "address" 97 | }, 98 | { 99 | "name": "isDisabled", 100 | "type": "bool", 101 | "internalType": "bool" 102 | }, 103 | { 104 | "name": "params", 105 | "type": "tuple[]", 106 | "internalType": "struct KeyValue[]", 107 | "components": [ 108 | { 109 | "name": "key", 110 | "type": "bytes32", 111 | "internalType": "bytes32" 112 | }, 113 | { 114 | "name": "value", 115 | "type": "bytes", 116 | "internalType": "bytes" 117 | } 118 | ] 119 | } 120 | ], 121 | "outputs": [ 122 | { 123 | "name": "", 124 | "type": "bytes", 125 | "internalType": "bytes" 126 | } 127 | ], 128 | "stateMutability": "payable" 129 | } 130 | ] -------------------------------------------------------------------------------- /contracts/rules/base/SimplePaymentRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | import {OwnableMetadataBasedRule} from "lens-modules/contracts/rules/base/OwnableMetadataBasedRule.sol"; 8 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 9 | import {TrustBasedRule} from "lens-modules/contracts/rules/base/TrustBasedRule.sol"; 10 | import {LensRulePaymentHandler} from "lens-modules/contracts/extensions/fees/LensRulePaymentHandler.sol"; 11 | import {RecipientData} from "lens-modules/contracts/core/types/Types.sol"; 12 | import {NATIVE_TOKEN} from "lens-modules/contracts/core/types/Constants.sol"; 13 | 14 | abstract contract SimplePaymentRule is LensRulePaymentHandler, TrustBasedRule, OwnableMetadataBasedRule { 15 | using SafeERC20 for IERC20; 16 | 17 | /// @custom:keccak lens.param.paymentConfiguration 18 | bytes32 constant PARAM__PAYMENT_CONFIG = 0x1d614931e4da442dfded7a7b2023927603d40081577686bb6fd4debb2fd73fc0; 19 | 20 | struct PaymentConfiguration { 21 | address token; 22 | uint256 amount; 23 | address recipient; 24 | } 25 | 26 | constructor(address owner, string memory metadataURI) OwnableMetadataBasedRule(owner, metadataURI) {} 27 | 28 | function _initialize(address owner, string memory metadataURI) internal override { 29 | super._initialize(owner, metadataURI); 30 | } 31 | 32 | function _validatePaymentConfiguration(PaymentConfiguration memory configuration) internal view virtual { 33 | require(configuration.amount > 0, Errors.InvalidParameter()); 34 | _validateToken(configuration.token); 35 | } 36 | 37 | function _beforePayment( 38 | PaymentConfiguration memory configuration, 39 | PaymentConfiguration memory expectedConfiguration, 40 | address payer, 41 | RecipientData[] memory, /* referrals */ 42 | uint16 /* referralFeeBps */ 43 | ) internal view virtual { 44 | require(configuration.token == expectedConfiguration.token, Errors.InvalidParameter()); 45 | require(configuration.amount == expectedConfiguration.amount, Errors.InvalidParameter()); 46 | require(configuration.recipient == expectedConfiguration.recipient, Errors.InvalidParameter()); 47 | if (configuration.token != NATIVE_TOKEN) { 48 | // Requires payer to trust the msg.sender (we assume msg.sender is the primitive) 49 | _requireTrust({fromAccount: payer, toTarget: msg.sender}); 50 | } 51 | } 52 | 53 | function _processPayment( 54 | PaymentConfiguration memory configuration, 55 | PaymentConfiguration memory expectedConfiguration, 56 | address payer, 57 | RecipientData[] memory referrals, 58 | uint16 referralFeeBps 59 | ) internal virtual { 60 | _beforePayment(configuration, expectedConfiguration, payer, referrals, referralFeeBps); 61 | _handlePayment({ 62 | payer: payer, 63 | token: configuration.token, 64 | amount: configuration.amount, 65 | recipient: configuration.recipient, 66 | referrals: referrals, 67 | referralFeeBps: referralFeeBps 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/core/upgradeability/LensCreate2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import { 6 | TransparentUpgradeableProxy, 7 | ITransparentUpgradeableProxy 8 | } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 9 | import {Ownable} from "lens-modules/contracts/core/access/Ownable.sol"; 10 | import {Errors} from "lens-modules/contracts/core/types/Errors.sol"; 11 | import {Initializable} from "lens-modules/contracts/core/upgradeability/Initializable.sol"; 12 | 13 | // If using the [0] nonce of 0xfe4Ad59637Cab6A5AbAEe896D3d01dA67f418e76 deployer: 14 | address constant LENS_CREATE_2_ADDRESS = 0x52AF9CF29976C310E3DE03C509E108edB6edb8c0; 15 | 16 | interface ILensCreate2 { 17 | function getAddress(bytes32 salt) external view returns (address); 18 | 19 | function createTransparentUpgradeableProxy( 20 | bytes32 salt, 21 | address implementation, 22 | address proxyAdmin, 23 | bytes calldata initializerCall, 24 | address expectedAddress 25 | ) external returns (address); 26 | } 27 | 28 | contract LensCreate2 is ILensCreate2, Initializable, Ownable { 29 | bytes32 public immutable PROXY_BYTECODE_HASH; 30 | bytes32 public immutable SENDER_BYTES; 31 | bytes32 public immutable CREATE2_PREFIX; 32 | bytes32 public immutable CONSTRUCTOR_ARGS_HASH; 33 | 34 | constructor() { 35 | address proxy = address(new TransparentUpgradeableProxy(LENS_CREATE_2_ADDRESS, LENS_CREATE_2_ADDRESS, "")); 36 | bytes32 bytecodeHash; 37 | assembly { 38 | bytecodeHash := extcodehash(proxy) 39 | } 40 | PROXY_BYTECODE_HASH = bytecodeHash; 41 | CREATE2_PREFIX = keccak256("zksyncCreate2"); 42 | SENDER_BYTES = bytes32(uint256(uint160(LENS_CREATE_2_ADDRESS))); 43 | CONSTRUCTOR_ARGS_HASH = keccak256(abi.encode(LENS_CREATE_2_ADDRESS, LENS_CREATE_2_ADDRESS, "")); 44 | _disableInitializers(); 45 | } 46 | 47 | function initialize(address owner) external initializer { 48 | _transferOwnership(owner); 49 | } 50 | 51 | function getAddress(bytes32 salt) external view override returns (address) { 52 | return address( 53 | uint160( 54 | uint256( 55 | keccak256( 56 | bytes.concat(CREATE2_PREFIX, SENDER_BYTES, salt, PROXY_BYTECODE_HASH, CONSTRUCTOR_ARGS_HASH) 57 | ) 58 | ) 59 | ) 60 | ); 61 | } 62 | 63 | function createTransparentUpgradeableProxy( 64 | bytes32 salt, 65 | address implementation, 66 | address proxyAdmin, 67 | bytes calldata initializerCall, 68 | address expectedAddress 69 | ) external override onlyOwner returns (address) { 70 | ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( 71 | address(new TransparentUpgradeableProxy{salt: salt}(LENS_CREATE_2_ADDRESS, LENS_CREATE_2_ADDRESS, "")) 72 | ); 73 | require(expectedAddress == address(0) || expectedAddress == address(proxy), Errors.UnexpectedValue()); 74 | if (initializerCall.length > 0) { 75 | proxy.upgradeToAndCall(implementation, initializerCall); 76 | } else { 77 | proxy.upgradeTo(implementation); 78 | } 79 | proxy.changeAdmin(proxyAdmin); 80 | return address(proxy); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /contracts/rules/feed/RestrictedSignersFeedRule.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // Copyright (C) 2024 Lens Labs. All Rights Reserved. 3 | pragma solidity ^0.8.26; 4 | 5 | import {CreatePostParams, EditPostParams} from "../../core/interfaces/IFeed.sol"; 6 | import {IFeedRule} from "../../core/interfaces/IFeedRule.sol"; 7 | import {RestrictedSignersRule, EIP712Signature} from "../base/RestrictedSignersRule.sol"; 8 | import {KeyValue, RuleChange} from "../../core/types/Types.sol"; 9 | import {EIP712EncodingLib} from "../../core/libraries/EIP712EncodingLib.sol"; 10 | 11 | contract RestrictedSignersFeedRule is RestrictedSignersRule, IFeedRule { 12 | constructor(address owner, string memory metadataURI) RestrictedSignersRule(owner, metadataURI) {} 13 | 14 | function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override { 15 | _configure(configSalt, ruleParams); 16 | } 17 | 18 | function processCreatePost( 19 | bytes32 configSalt, 20 | uint256 postId, 21 | CreatePostParams calldata postParams, 22 | KeyValue[] calldata primitiveParams, 23 | KeyValue[] calldata ruleParams 24 | ) external override { 25 | _validateRestrictedSignerMessage({ 26 | configSalt: configSalt, 27 | functionSelector: IFeedRule.processCreatePost.selector, 28 | abiEncodedFunctionParams: abi.encode( 29 | postId, EIP712EncodingLib.encodeForEIP712(postParams), EIP712EncodingLib.encodeForEIP712(primitiveParams) 30 | ), 31 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 32 | }); 33 | } 34 | 35 | function processEditPost( 36 | bytes32 configSalt, 37 | uint256 postId, 38 | EditPostParams calldata postParams, 39 | KeyValue[] calldata primitiveParams, 40 | KeyValue[] calldata ruleParams 41 | ) external override { 42 | _validateRestrictedSignerMessage({ 43 | configSalt: configSalt, 44 | functionSelector: IFeedRule.processEditPost.selector, 45 | abiEncodedFunctionParams: abi.encode( 46 | postId, EIP712EncodingLib.encodeForEIP712(postParams), EIP712EncodingLib.encodeForEIP712(primitiveParams) 47 | ), 48 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 49 | }); 50 | } 51 | 52 | function processDeletePost( 53 | bytes32 configSalt, 54 | uint256 postId, 55 | KeyValue[] calldata primitiveParams, 56 | KeyValue[] calldata ruleParams 57 | ) external override { 58 | _validateRestrictedSignerMessage({ 59 | configSalt: configSalt, 60 | functionSelector: IFeedRule.processDeletePost.selector, 61 | abiEncodedFunctionParams: abi.encode(postId, EIP712EncodingLib.encodeForEIP712(primitiveParams)), 62 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 63 | }); 64 | } 65 | 66 | function processPostRuleChanges( 67 | bytes32 configSalt, 68 | uint256 postId, 69 | RuleChange[] calldata ruleChanges, 70 | KeyValue[] calldata ruleParams 71 | ) external override { 72 | _validateRestrictedSignerMessage({ 73 | configSalt: configSalt, 74 | functionSelector: IFeedRule.processPostRuleChanges.selector, 75 | abiEncodedFunctionParams: abi.encode(postId, EIP712EncodingLib.encodeForEIP712(ruleChanges)), 76 | signature: abi.decode(ruleParams[0].value, (EIP712Signature)) 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /abis/EventEmitter.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "function", 4 | "name": "emitEventsLog1", 5 | "inputs": [ 6 | { 7 | "name": "events", 8 | "type": "tuple[]", 9 | "internalType": "struct Log1EventData[]", 10 | "components": [ 11 | { 12 | "name": "topic1", 13 | "type": "bytes32", 14 | "internalType": "bytes32" 15 | }, 16 | { 17 | "name": "data", 18 | "type": "bytes", 19 | "internalType": "bytes" 20 | } 21 | ] 22 | } 23 | ], 24 | "outputs": [], 25 | "stateMutability": "nonpayable" 26 | }, 27 | { 28 | "type": "function", 29 | "name": "emitEventsLog2", 30 | "inputs": [ 31 | { 32 | "name": "events", 33 | "type": "tuple[]", 34 | "internalType": "struct Log2EventData[]", 35 | "components": [ 36 | { 37 | "name": "topic1", 38 | "type": "bytes32", 39 | "internalType": "bytes32" 40 | }, 41 | { 42 | "name": "topic2", 43 | "type": "bytes32", 44 | "internalType": "bytes32" 45 | }, 46 | { 47 | "name": "data", 48 | "type": "bytes", 49 | "internalType": "bytes" 50 | } 51 | ] 52 | } 53 | ], 54 | "outputs": [], 55 | "stateMutability": "nonpayable" 56 | }, 57 | { 58 | "type": "function", 59 | "name": "emitEventsLog3", 60 | "inputs": [ 61 | { 62 | "name": "events", 63 | "type": "tuple[]", 64 | "internalType": "struct Log3EventData[]", 65 | "components": [ 66 | { 67 | "name": "topic1", 68 | "type": "bytes32", 69 | "internalType": "bytes32" 70 | }, 71 | { 72 | "name": "topic2", 73 | "type": "bytes32", 74 | "internalType": "bytes32" 75 | }, 76 | { 77 | "name": "topic3", 78 | "type": "bytes32", 79 | "internalType": "bytes32" 80 | }, 81 | { 82 | "name": "data", 83 | "type": "bytes", 84 | "internalType": "bytes" 85 | } 86 | ] 87 | } 88 | ], 89 | "outputs": [], 90 | "stateMutability": "nonpayable" 91 | }, 92 | { 93 | "type": "function", 94 | "name": "emitEventsLog4", 95 | "inputs": [ 96 | { 97 | "name": "events", 98 | "type": "tuple[]", 99 | "internalType": "struct Log4EventData[]", 100 | "components": [ 101 | { 102 | "name": "topic1", 103 | "type": "bytes32", 104 | "internalType": "bytes32" 105 | }, 106 | { 107 | "name": "topic2", 108 | "type": "bytes32", 109 | "internalType": "bytes32" 110 | }, 111 | { 112 | "name": "topic3", 113 | "type": "bytes32", 114 | "internalType": "bytes32" 115 | }, 116 | { 117 | "name": "topic4", 118 | "type": "bytes32", 119 | "internalType": "bytes32" 120 | }, 121 | { 122 | "name": "data", 123 | "type": "bytes", 124 | "internalType": "bytes" 125 | } 126 | ] 127 | } 128 | ], 129 | "outputs": [], 130 | "stateMutability": "nonpayable" 131 | } 132 | ] --------------------------------------------------------------------------------