Guides

Registering a Module

Developers wishing to register a module to signal it's availability to the Frontends, Lens API, and users, can do that using the ModuleRegistry contract. Registration is not required - any module will be registered automatically on the first use. Same rules apply to registering currencies.

Registration is declarative, and just emits an event that can be tracked by anyone, and is supposed to let everyone know that this kind of module is available--so they can dive deep into its code and see how it works. The data provided during the registration isn't verified anywhere on-chain, and as it's public and open--it shouldn't be blindly trusted, but rather be treated as a hint of what modules are available and what types they might be.

To allow module to be registered it should conform to our ModuleRegistry standards, i.e.:

ModuleRegistry Standards

IERC165 Interface support requirements

We use IERC165 to distinguish any arbitrary contract from a LensModule.

Each module should confirm the support of two IERC165 interfaces:

  1. The general LENS_MODULE interfaceID (available as LensModule.sol to inherit from):
function supportsInterface(bytes4 interfaceID) public pure virtual override returns (bool) {
    return interfaceID == bytes4(keccak256(abi.encodePacked('LENS_MODULE')));
}
  1. Specific module type interfaceID, which comes automatically when you inherit from our standard module interfaces:
    • interface IFollowModule
    • interface IPublicationActionModule
    • interface IReferenceModule
      Here is an example of a Publication Action Module (OpenAction) inheritance and IERC165 override:
contract CollectPublicationAction is LensModule, IPublicationActionModule {
    function supportsInterface(bytes4 interfaceID) public pure override returns (bool) {
        return interfaceID == type(IPublicationActionModule).interfaceId || super.supportsInterface(interfaceID);
    }

  /// ...
}

MetadataURI Standards

Each module should have a getModuleMetadataURI() getter that returns the metadata for the module (see Module Metadata Standard)

function getModuleMetadataURI() external view returns (string memory) {
    return 'yourMetadataURIgoesHere';
}

We also have a LensModuleMetadata.sol in the repo as an example that you can inherit from to use dynamic metadata with setter and getter, but keep in mind you will have to also trigger refresh of the metadata after you change it manually in the ModuleRegistry (see the section below).

How to register a module

Generally, you're not required to register a module beforehand, cause it will be automatically registered after the first use (for example the first post that has this module enabled). But if you want to signal the availability of your module without posting anything with it yet, you can do so by Registering a module manually.

Registering a module is very simple--you just need to pass it's address and the proper type to the registerModule() function of the ModuleRegistry contract:

enum ModuleType {
    __, // Just to avoid 0 as valid ModuleType
    PUBLICATION_ACTION_MODULE,
    REFERENCE_MODULE,
    FOLLOW_MODULE
}

registerModule(address moduleAddress, uint256 moduleType);

Where moduleType is an enum (number) representing a type of the module:

Module Typeuint256 to pass
Publication Action Module (aka Open Action)1
Reference Module2
Follow Module3

If you've committed a mistake and passed the wrong type during registration--it will not be registered, because the ModuleRegistry will check IERC165 standards of your module, and if it doesn't match the declared type--it will revert. If you want to register a contract that acts like multiple module types--just register it many times, using as many types as needed.

Registration of a module emits an event:

event ModuleRegistered(
    address indexed moduleAddress,
    uint256 indexed moduleType,
    string metadata,
    uint256 timestamp
);

Remember, you don't need to explicitly signal your module via Registration--you can just use it in a publication or profile and it will be registered automatically on the first use with a proper type.

How to register a ERC20 currency

Same as with modules, anyone can register a ERC20 currency--all you need to do is pass its address to registerErc20Currency() function:

function registerErc20Currency(address currencyAddress);

Registering a currency just signals that a currency is available to use and emits an event for the Frontends, Lens API and users to track which currencies are available.

During registration the decimals, name and symbol of the currency is fetched.

Registration of a currency emits an event:

event erc20CurrencyRegistered(
    address indexed erc20CurrencyAddress,
    string name,
    string symbol,
    uint8 decimals,
    uint256 timestamp
);

You don't have to do this registration--the currency will also be registered automatically when first used with any of the modules.

How to refresh the Metadata

If you've decided to use the LensModuleMetadata.sol as a base of your module with setter/getter approach to update metadata - you need to trigger the metadata refresh manually in ModuleRegistry.

This is very simple and involves just triggering the ModuleRegistry.emitModuleMetadataRefresh(address moduleAddress) function. It is public, and anyone can trigger it.

Your module should be already registered to be able to call this function.


What’s Next

Now let's learn how to build another type of Module: