mirror of
https://github.com/lens-protocol/core.git
synced 2026-01-10 14:48:15 -05:00
feat: Permissionless modules - Impl in progress
Co-authored-by: Victor Naumik <vicnaum@gmail.com>
This commit is contained in:
@@ -536,8 +536,9 @@ contract LensHub is
|
||||
function getPublication(
|
||||
uint256 profileId,
|
||||
uint256 pubId
|
||||
) external view override returns (Types.Publication memory) {
|
||||
return _publications[profileId][pubId];
|
||||
) external view override returns (Types.PublicationMemory memory) {
|
||||
// TODO: Maybe we need to add some assembly here if this doesn't work
|
||||
return Types.PublicationMemory(_publications[profileId][pubId]);
|
||||
}
|
||||
|
||||
/// @inheritdoc ILensProtocol
|
||||
@@ -547,8 +548,4 @@ contract LensHub is
|
||||
) external view override returns (Types.PublicationType) {
|
||||
return PublicationLib.getPublicationType(profileId, pubId);
|
||||
}
|
||||
|
||||
function getActionModuleById(uint256 id) external view override returns (address) {
|
||||
return _actionModules[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +55,7 @@ abstract contract LensHubStorage {
|
||||
|
||||
mapping(uint256 blockerProfileId => mapping(uint256 blockedProfileId => bool isBlocked)) internal _blockedStatus; // Slot 27
|
||||
|
||||
mapping(uint256 id => address actionModule) internal _actionModules; // Slot 28
|
||||
uint256 internal _profileRoyaltiesBps; // Slot 28
|
||||
|
||||
uint256 internal _maxActionModuleIdUsed; // Slot 29
|
||||
|
||||
uint256 internal _profileRoyaltiesBps; // Slot 30
|
||||
|
||||
mapping(address migrationAdmin => bool allowed) internal _migrationAdminWhitelisted; // Slot 31
|
||||
mapping(address migrationAdmin => bool allowed) internal _migrationAdminWhitelisted; // Slot 29
|
||||
}
|
||||
|
||||
@@ -405,15 +405,6 @@ interface ILensProtocol {
|
||||
*/
|
||||
function isBlocked(uint256 profileId, uint256 byProfileId) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Returns the address of the action module associated with the given whitelist ID, address(0) if none.
|
||||
*
|
||||
* @param id The ID of the module whose address wants to be queried.
|
||||
*
|
||||
* @return address The address of the action module associated with the given ID.
|
||||
*/
|
||||
function getActionModuleById(uint256 id) external view returns (address);
|
||||
|
||||
/**
|
||||
* @notice Returns the URI associated with a given publication.
|
||||
* This is used to store the publication's metadata, e.g.: content, images, etc.
|
||||
@@ -442,7 +433,7 @@ interface ILensProtocol {
|
||||
*
|
||||
* @return Publication The publication struct associated with the queried publication.
|
||||
*/
|
||||
function getPublication(uint256 profileId, uint256 pubId) external view returns (Types.Publication memory);
|
||||
function getPublication(uint256 profileId, uint256 pubId) external view returns (Types.PublicationMemory memory);
|
||||
|
||||
/**
|
||||
* @notice Returns the type of a given publication.
|
||||
|
||||
28
contracts/interfaces/IModuleRegistry.sol
Normal file
28
contracts/interfaces/IModuleRegistry.sol
Normal file
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.15;
|
||||
|
||||
interface IModuleRegistry {
|
||||
enum ModuleType {
|
||||
__, // Just to avoid 0 as valid ModuleType
|
||||
PUBLICATION_ACTION_MODULE,
|
||||
REFERENCE_MODULE,
|
||||
FOLLOW_MODULE
|
||||
}
|
||||
|
||||
// Modules functions
|
||||
|
||||
function registerModule(address moduleAddress, uint256 moduleType) external returns (bool);
|
||||
|
||||
function getModuleTypes(address moduleAddress) external view returns (uint256);
|
||||
|
||||
function isModuleRegistered(address moduleAddress) external view returns (bool);
|
||||
|
||||
function isModuleRegisteredAs(address moduleAddress, uint256 moduleType) external view returns (bool);
|
||||
|
||||
// Currencies functions
|
||||
|
||||
function registerErc20Currency(address currencyAddress) external returns (bool);
|
||||
|
||||
function isErc20CurrencyRegistered(address currencyAddress) external view returns (bool);
|
||||
}
|
||||
@@ -25,10 +25,7 @@ library ActionLib {
|
||||
publicationActionParams.publicationActedId
|
||||
);
|
||||
|
||||
address actionModuleAddress = publicationActionParams.actionModuleAddress;
|
||||
uint256 actionModuleId = StorageLib.actionModuleRegisterData()[actionModuleAddress].id;
|
||||
|
||||
if (!_isActionEnabled(_actedOnPublication, actionModuleId)) {
|
||||
if (!_isActionEnabled(_actedOnPublication, publicationActionParams.actionModuleAddress)) {
|
||||
// This will also revert for:
|
||||
// - Non-existent action modules
|
||||
// - Non-existent publications
|
||||
@@ -44,19 +41,20 @@ library ActionLib {
|
||||
publicationActionParams.publicationActedId
|
||||
);
|
||||
|
||||
bytes memory actionModuleReturnData = IPublicationActionModule(actionModuleAddress).processPublicationAction(
|
||||
Types.ProcessActionParams({
|
||||
publicationActedProfileId: publicationActionParams.publicationActedProfileId,
|
||||
publicationActedId: publicationActionParams.publicationActedId,
|
||||
actorProfileId: publicationActionParams.actorProfileId,
|
||||
actorProfileOwner: actorProfileOwner,
|
||||
transactionExecutor: transactionExecutor,
|
||||
referrerProfileIds: publicationActionParams.referrerProfileIds,
|
||||
referrerPubIds: publicationActionParams.referrerPubIds,
|
||||
referrerPubTypes: referrerPubTypes,
|
||||
actionModuleData: publicationActionParams.actionModuleData
|
||||
})
|
||||
);
|
||||
bytes memory actionModuleReturnData = IPublicationActionModule(publicationActionParams.actionModuleAddress)
|
||||
.processPublicationAction(
|
||||
Types.ProcessActionParams({
|
||||
publicationActedProfileId: publicationActionParams.publicationActedProfileId,
|
||||
publicationActedId: publicationActionParams.publicationActedId,
|
||||
actorProfileId: publicationActionParams.actorProfileId,
|
||||
actorProfileOwner: actorProfileOwner,
|
||||
transactionExecutor: transactionExecutor,
|
||||
referrerProfileIds: publicationActionParams.referrerProfileIds,
|
||||
referrerPubIds: publicationActionParams.referrerPubIds,
|
||||
referrerPubTypes: referrerPubTypes,
|
||||
actionModuleData: publicationActionParams.actionModuleData
|
||||
})
|
||||
);
|
||||
emit Events.Acted(publicationActionParams, actionModuleReturnData, transactionExecutor, block.timestamp);
|
||||
|
||||
return actionModuleReturnData;
|
||||
@@ -64,12 +62,8 @@ library ActionLib {
|
||||
|
||||
function _isActionEnabled(
|
||||
Types.Publication storage _publication,
|
||||
uint256 actionModuleId
|
||||
address actionModuleAddress
|
||||
) private view returns (bool) {
|
||||
if (actionModuleId == 0) {
|
||||
return false;
|
||||
}
|
||||
uint256 actionModuleIdBitmapMask = 1 << (actionModuleId - 1);
|
||||
return actionModuleIdBitmapMask & _publication.enabledActionModulesBitmap != 0;
|
||||
return _publication.actionModuleEnabled[actionModuleAddress];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {Events} from 'contracts/libraries/constants/Events.sol';
|
||||
import {StorageLib} from 'contracts/libraries/StorageLib.sol';
|
||||
import {IFollowModule} from 'contracts/interfaces/IFollowModule.sol';
|
||||
import {IFollowNFT} from 'contracts/interfaces/IFollowNFT.sol';
|
||||
import {IModuleRegistry} from 'contracts/interfaces/IModuleRegistry.sol';
|
||||
|
||||
library ProfileLib {
|
||||
function ownerOf(uint256 profileId) internal view returns (address) {
|
||||
@@ -75,7 +76,7 @@ library ProfileLib {
|
||||
address followModule,
|
||||
bytes memory followModuleInitData
|
||||
) private returns (bytes memory) {
|
||||
ValidationLib.validateFollowModuleRegistered(followModule);
|
||||
IModuleRegistry(StorageLib.getModuleRegistry()).registerModule(followModule, IModuleRegistry.ModuleType.Follow);
|
||||
return IFollowModule(followModule).initializeFollowModule(profileId, transactionExecutor, followModuleInitData);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,11 @@ import {IReferenceModule} from 'contracts/interfaces/IReferenceModule.sol';
|
||||
import {ILegacyReferenceModule} from 'contracts/interfaces/ILegacyReferenceModule.sol';
|
||||
import {StorageLib} from 'contracts/libraries/StorageLib.sol';
|
||||
import {IPublicationActionModule} from 'contracts/interfaces/IPublicationActionModule.sol';
|
||||
import {IModuleRegistry} from 'contracts/interfaces/IModuleRegistry.sol';
|
||||
|
||||
library PublicationLib {
|
||||
address constant MODULE_REGISTRY = address(0xC0FFEE); // TODO: Pass constant or make libs contracts and manually DELEGATECALL to them
|
||||
|
||||
/**
|
||||
* @notice Publishes a post to a given profile.
|
||||
*
|
||||
@@ -498,25 +501,13 @@ library PublicationLib {
|
||||
}
|
||||
|
||||
bytes[] memory actionModuleInitResults = new bytes[](params.actionModules.length);
|
||||
uint256 enabledActionModulesBitmap;
|
||||
|
||||
uint256 i;
|
||||
while (i < params.actionModules.length) {
|
||||
Types.ActionModuleWhitelistData memory actionModuleWhitelistData = StorageLib.actionModuleRegisterData()[
|
||||
params.actionModules[i]
|
||||
];
|
||||
|
||||
if (!actionModuleRegisterData.isRegistered) {
|
||||
revert Errors.NotRegistered();
|
||||
}
|
||||
|
||||
uint256 actionModuleIdBitmapMask = 1 << (actionModuleRegisterData.id - 1);
|
||||
|
||||
if (enabledActionModulesBitmap & actionModuleIdBitmapMask != 0) {
|
||||
revert Errors.AlreadyEnabled();
|
||||
}
|
||||
|
||||
enabledActionModulesBitmap |= actionModuleIdBitmapMask;
|
||||
IModuleRegistry(MODULE_REGISTRY).registerModule(
|
||||
params.actionModules[i],
|
||||
uint256(IModuleRegistry.ModuleType.PUBLICATION_ACTION_MODULE)
|
||||
);
|
||||
|
||||
actionModuleInitResults[i] = IPublicationActionModule(params.actionModules[i]).initializePublicationAction(
|
||||
params.profileId,
|
||||
@@ -530,10 +521,6 @@ library PublicationLib {
|
||||
}
|
||||
}
|
||||
|
||||
StorageLib
|
||||
.getPublication(params.profileId, params.pubId)
|
||||
.enabledActionModulesBitmap = enabledActionModulesBitmap;
|
||||
|
||||
return actionModuleInitResults;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,8 @@ library StorageLib {
|
||||
//////////////////////////////////
|
||||
uint256 constant DELEGATED_EXECUTOR_CONFIG_MAPPING_SLOT = 26;
|
||||
uint256 constant BLOCKED_STATUS_MAPPING_SLOT = 27;
|
||||
uint256 constant ACTION_MODULES_SLOT = 28;
|
||||
uint256 constant MAX_ACTION_MODULE_ID_USED_SLOT = 29;
|
||||
uint256 constant PROFILE_ROYALTIES_BPS_SLOT = 30;
|
||||
uint256 constant MIGRATION_ADMINS_WHITELISTED_MAPPING_SLOT = 31;
|
||||
|
||||
uint256 constant MAX_ACTION_MODULE_ID_SUPPORTED = 255;
|
||||
uint256 constant PROFILE_ROYALTIES_BPS_SLOT = 28;
|
||||
uint256 constant MIGRATION_ADMINS_WHITELISTED_MAPPING_SLOT = 29;
|
||||
|
||||
function getPublication(
|
||||
uint256 profileId,
|
||||
@@ -142,24 +138,6 @@ library StorageLib {
|
||||
}
|
||||
}
|
||||
|
||||
function actionModuleById() internal pure returns (mapping(uint256 => address) storage _actionModules) {
|
||||
assembly {
|
||||
_actionModules.slot := ACTION_MODULES_SLOT
|
||||
}
|
||||
}
|
||||
|
||||
function incrementMaxActionModuleIdUsed() internal returns (uint256) {
|
||||
uint256 incrementedId;
|
||||
assembly {
|
||||
incrementedId := add(sload(MAX_ACTION_MODULE_ID_USED_SLOT), 1)
|
||||
sstore(MAX_ACTION_MODULE_ID_USED_SLOT, incrementedId)
|
||||
}
|
||||
if (incrementedId > MAX_ACTION_MODULE_ID_SUPPORTED) {
|
||||
revert Errors.MaxActionModuleIdReached();
|
||||
}
|
||||
return incrementedId;
|
||||
}
|
||||
|
||||
function getGovernance() internal view returns (address _governance) {
|
||||
assembly {
|
||||
_governance := sload(GOVERNANCE_SLOT)
|
||||
|
||||
@@ -48,18 +48,6 @@ library ValidationLib {
|
||||
}
|
||||
}
|
||||
|
||||
function validateReferenceModuleRegistered(address referenceModule) internal view {
|
||||
if (!StorageLib.referenceModuleRegistered()[referenceModule]) {
|
||||
revert Errors.NotRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
function validateFollowModuleRegistered(address followModule) internal view {
|
||||
if (!StorageLib.followModuleRegistered()[followModule]) {
|
||||
revert Errors.NotRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
function validateProfileCreatorWhitelisted(address profileCreator) internal view {
|
||||
if (!StorageLib.profileCreatorWhitelisted()[profileCreator]) {
|
||||
revert Errors.NotWhitelisted();
|
||||
|
||||
@@ -32,9 +32,6 @@ library Errors {
|
||||
error NonERC721ReceiverImplementer();
|
||||
error AlreadyEnabled();
|
||||
|
||||
// Internal Errors
|
||||
error MaxActionModuleIdReached(); // This means we need an upgrade
|
||||
|
||||
// Module Errors
|
||||
error InitParamsInvalid();
|
||||
error ActionNotAllowed();
|
||||
|
||||
@@ -130,11 +130,7 @@ library Types {
|
||||
* Posts, V1 publications and publications rooted in V1 publications don't have it set.
|
||||
* @param rootPubId The publication ID of the root post (to determine if comments/quotes and mirrors come from it).
|
||||
* Posts, V1 publications and publications rooted in V1 publications don't have it set.
|
||||
* @param enabledActionModulesBitmap The action modules enabled in a given publication as a bitmap.
|
||||
* The bitmap is a uint256 where each bit represents an action module: 1 if the publication uses it, 0 if not.
|
||||
* You can use getActionModuleById() to get the address of the action module associated with a given bit.
|
||||
* In the future this can be replaced with a getter that allows to query the bitmap by index, if there are more
|
||||
* than 256 action modules.
|
||||
* @param actionModuleEnabled The action modules enabled in a given publication.
|
||||
*/
|
||||
struct Publication {
|
||||
uint256 pointedProfileId;
|
||||
@@ -147,7 +143,21 @@ library Types {
|
||||
PublicationType pubType;
|
||||
uint256 rootProfileId;
|
||||
uint256 rootPubId;
|
||||
uint256 enabledActionModulesBitmap; // In future this can be (uint256 => uint256) mapping if we need >256 modules
|
||||
mapping(address => bool) actionModuleEnabled;
|
||||
}
|
||||
|
||||
struct PublicationMemory {
|
||||
uint256 pointedProfileId;
|
||||
uint256 pointedPubId;
|
||||
string contentURI;
|
||||
address referenceModule;
|
||||
address __DEPRECATED__collectModule; // Deprecated in V2
|
||||
address __DEPRECATED__collectNFT; // Deprecated in V2
|
||||
// Added in Lens V2, so these will be zero for old publications:
|
||||
PublicationType pubType;
|
||||
uint256 rootProfileId;
|
||||
uint256 rootPubId;
|
||||
// bytes32 __ACTION_MODULE_ENABLED_MAPPING; // Mappings are not supported in memory.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,67 +2,71 @@
|
||||
|
||||
pragma solidity ^0.8.15;
|
||||
|
||||
contract ModuleRegistry {
|
||||
event ModuleRegistered(
|
||||
address indexed moduleAddress,
|
||||
ModuleType indexed moduleType,
|
||||
address registrar,
|
||||
import {IModuleRegistry} from 'contracts/interfaces/IModuleRegistry.sol';
|
||||
import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
|
||||
|
||||
contract ModuleRegistry is IModuleRegistry {
|
||||
event ModuleRegistered(address indexed moduleAddress, uint256 indexed moduleType, uint256 timestamp);
|
||||
|
||||
event erc20CurrencyRegistered(
|
||||
address indexed erc20CurrencyAddress,
|
||||
string name,
|
||||
string symbol,
|
||||
uint8 decimals,
|
||||
uint256 timestamp
|
||||
);
|
||||
|
||||
struct Module {
|
||||
address registrar;
|
||||
bool isPublicationActionModule;
|
||||
bool isReferenceModule;
|
||||
bool isFollowModule;
|
||||
}
|
||||
mapping(address moduleAddress => uint256 moduleTypesBitmap) internal registeredModules;
|
||||
|
||||
enum ModuleType {
|
||||
NOT_REGISTERED,
|
||||
PUBLICATION_ACTION_MODULE,
|
||||
REFERENCE_MODULE,
|
||||
FOLLOW_MODULE
|
||||
}
|
||||
mapping(address erc20CurrencyAddress => bool) internal registeredErc20Currencies;
|
||||
|
||||
mapping(address => Module) public modules;
|
||||
// Modules
|
||||
|
||||
/// @dev This is frontrunnable, so...
|
||||
function register(address moduleAddress, ModuleType moduleType) public {
|
||||
if (moduleType == ModuleType.NOT_REGISTERED) {
|
||||
revert('Module type cannot be NOT_REGISTERED');
|
||||
function registerModule(address moduleAddress, uint256 moduleType) public returns (bool registrationWasPerformed) {
|
||||
// This will fail if moduleType is out of range for `IModuleRegistry.ModuleType`
|
||||
require(moduleType > 0 && moduleType < uint256(type(IModuleRegistry.ModuleType).max));
|
||||
|
||||
bool isAlreadyRegisteredAsThatType = registeredModules[moduleAddress] & (1 << moduleType) != 0;
|
||||
if (isAlreadyRegisteredAsThatType) {
|
||||
return false;
|
||||
} else {
|
||||
emit ModuleRegistered(moduleAddress, moduleType, block.timestamp);
|
||||
registeredModules[moduleAddress] |= (1 << moduleType);
|
||||
return true;
|
||||
}
|
||||
if (modules[moduleAddress].moduleType != ModuleType.NOT_REGISTERED) {
|
||||
revert('Module already registered');
|
||||
}
|
||||
|
||||
function getModuleTypes(address moduleAddress) public view returns (uint256) {
|
||||
return registeredModules[moduleAddress];
|
||||
}
|
||||
|
||||
function isModuleRegistered(address moduleAddress) external view returns (bool) {
|
||||
return registeredModules[moduleAddress] != 0;
|
||||
}
|
||||
|
||||
function isModuleRegisteredAs(address moduleAddress, uint256 moduleType) public view returns (bool) {
|
||||
require(moduleType <= type(uint8).max);
|
||||
return registeredModules[moduleAddress] & (1 << moduleType) != 0;
|
||||
}
|
||||
|
||||
// Currencies
|
||||
|
||||
function registerErc20Currency(address currencyAddress) public returns (bool registrationWasPerformed) {
|
||||
bool isAlreadyRegistered = registeredErc20Currencies[currencyAddress];
|
||||
if (isAlreadyRegistered) {
|
||||
return false;
|
||||
} else {
|
||||
uint8 decimals = IERC20Metadata(currencyAddress).decimals();
|
||||
string memory name = IERC20Metadata(currencyAddress).name();
|
||||
string memory symbol = IERC20Metadata(currencyAddress).symbol();
|
||||
|
||||
emit erc20CurrencyRegistered(currencyAddress, name, symbol, decimals, block.timestamp);
|
||||
registeredErc20Currencies[currencyAddress] = true;
|
||||
return true;
|
||||
}
|
||||
if (moduleAddress.code.length == 0) {
|
||||
revert('Module address is not a contract');
|
||||
}
|
||||
modules[moduleAddress] = Module(msg.sender, moduleType);
|
||||
emit ModuleRegistered(moduleAddress, moduleType, msg.sender, block.timestamp);
|
||||
}
|
||||
|
||||
function getModuleType(address moduleAddress) public view returns (ModuleType) {
|
||||
return modules[moduleAddress].moduleType;
|
||||
}
|
||||
|
||||
function getModuleRegistrar(address moduleAddress) public view returns (address) {
|
||||
return modules[moduleAddress].registrar;
|
||||
}
|
||||
|
||||
function isRegistered(address moduleAddress) public view returns (bool) {
|
||||
return modules[moduleAddress].moduleType != ModuleType.NOT_REGISTERED;
|
||||
}
|
||||
|
||||
function areRegistered(address[] calldata moduleAddresses) public view returns (bool) {
|
||||
uint256 i;
|
||||
while (i < moduleAddresses.length) {
|
||||
if (modules[moduleAddresses[i]].moduleType == ModuleType.NOT_REGISTERED) {
|
||||
return false;
|
||||
}
|
||||
unchecked {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
function isErc20CurrencyRegistered(address currencyAddress) external view returns (bool) {
|
||||
return registeredErc20Currencies[currencyAddress];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,14 @@ contract CollectPublicationAction is HubRestricted, IPublicationActionModule {
|
||||
MODULE_GLOBALS = moduleGlobals;
|
||||
}
|
||||
|
||||
function registerCollectModule(address collectModule) external {
|
||||
_collectModuleRegistered[collectModule] = true;
|
||||
function registerCollectModule(address collectModule) public returns (bool) {
|
||||
bool isAlreadyRegistered = _collectModuleRegistered[collectModule];
|
||||
if (isAlreadyRegistered) {
|
||||
return false;
|
||||
}
|
||||
emit CollectModuleRegistered(collectModule, block.timestamp);
|
||||
_collectModuleRegistered[collectModule] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function initializePublicationAction(
|
||||
@@ -85,9 +90,11 @@ contract CollectPublicationAction is HubRestricted, IPublicationActionModule {
|
||||
bytes calldata data
|
||||
) external override onlyHub returns (bytes memory) {
|
||||
(address collectModule, bytes memory collectModuleInitData) = abi.decode(data, (address, bytes));
|
||||
if (!_collectModuleRegistered[collectModule]) {
|
||||
revert Errors.NotRegistered();
|
||||
}
|
||||
registerCollectModule(collectModule);
|
||||
// TODO
|
||||
// if (_collectDataByPub[profileId][pubId].collectModule != address(0)) {
|
||||
// revert Errors.AlreadyInitialized();
|
||||
// }
|
||||
_collectDataByPub[profileId][pubId].collectModule = collectModule;
|
||||
ICollectModule(collectModule).initializePublicationCollectModule(
|
||||
profileId,
|
||||
|
||||
@@ -148,81 +148,6 @@ contract ActTest is ReferralSystemTest {
|
||||
|
||||
testAct();
|
||||
}
|
||||
|
||||
function testGetActionModuleById(address secondActionModule) public {
|
||||
address firstActionModule = makeAddr('FIRST_ACTION_MODULE');
|
||||
vm.assume(firstActionModule != secondActionModule);
|
||||
|
||||
Types.ActionModuleRegisterData memory whitelistData = hub.getActionModuleRegisterData(secondActionModule);
|
||||
vm.assume(whitelistData.id == 0);
|
||||
vm.assume(whitelistData.isRegistered == false);
|
||||
|
||||
hub.registerActionModule(firstActionModule);
|
||||
|
||||
whitelistData = hub.getActionModuleRegisterData(firstActionModule);
|
||||
uint256 firstActionModuleId = whitelistData.id;
|
||||
assertTrue(whitelistData.isRegistered);
|
||||
|
||||
hub.registerActionModule(secondActionModule);
|
||||
|
||||
whitelistData = hub.getActionModuleRegisterData(secondActionModule);
|
||||
uint256 secondActionModuleId = whitelistData.id;
|
||||
assertTrue(whitelistData.isRegistered);
|
||||
|
||||
assertEq(hub.getActionModuleById(firstActionModuleId), firstActionModule);
|
||||
assertEq(hub.getActionModuleById(secondActionModuleId), secondActionModule);
|
||||
}
|
||||
|
||||
// Will not work on fork with more complicated action modules because we don't know how to initialize them
|
||||
function testGetEnabledActionModulesBitmap(uint8 enabledActionModulesBitmap) public {
|
||||
vm.assume(enabledActionModulesBitmap != 0);
|
||||
|
||||
address[] memory actionModules = new address[](9);
|
||||
for (uint256 i = 1; i < actionModules.length; i++) {
|
||||
if (hub.getActionModuleById(i) == address(0)) {
|
||||
actionModules[i] = makeAddr(string.concat('ACTION_MODULE_', vm.toString(i)));
|
||||
vm.etch(actionModules[i], address(mockActionModule).code);
|
||||
hub.registerActionModule(actionModules[i]);
|
||||
} else {
|
||||
actionModules[i] = hub.getActionModuleById(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Count enabledActionModules from a bitmap
|
||||
uint8 enabledActionModulesCount = 0;
|
||||
for (uint256 i = 0; i < 8; i++) {
|
||||
if (enabledActionModulesBitmap & (1 << i) != 0) {
|
||||
enabledActionModulesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick enabledActionModulesCount action modules
|
||||
address[] memory enabledActionModules = new address[](enabledActionModulesCount);
|
||||
uint256 enabledActionModulesIndex = 0;
|
||||
for (uint256 i = 0; i < 8; i++) {
|
||||
if (enabledActionModulesBitmap & (1 << i) != 0) {
|
||||
enabledActionModules[enabledActionModulesIndex] = actionModules[i + 1];
|
||||
enabledActionModulesIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
bytes[] memory enabledActionModulesInitDatas = new bytes[](enabledActionModulesCount);
|
||||
for (uint256 i = 0; i < enabledActionModulesCount; i++) {
|
||||
enabledActionModulesInitDatas[i] = abi.encode(true);
|
||||
}
|
||||
|
||||
Types.PostParams memory postParams = _getDefaultPostParams();
|
||||
postParams.actionModules = enabledActionModules;
|
||||
postParams.actionModulesInitDatas = enabledActionModulesInitDatas;
|
||||
|
||||
vm.prank(defaultAccount.owner);
|
||||
uint256 pubId = hub.post(postParams);
|
||||
|
||||
assertEq(
|
||||
hub.getPublication(defaultAccount.profileId, pubId).enabledActionModulesBitmap,
|
||||
enabledActionModulesBitmap
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
contract ActMetaTxTest is ActTest, MetaTxNegatives {
|
||||
|
||||
@@ -148,43 +148,4 @@ contract GovernanceFunctionsTest is BaseTest {
|
||||
|
||||
assertEq(hub.isReferenceModuleRegistered(referenceModule), true);
|
||||
}
|
||||
|
||||
function testWhitelistActionModule_initially(address actionModule) public {
|
||||
Types.ActionModuleRegisterData memory whitelistData = hub.getActionModuleRegisterData(actionModule);
|
||||
vm.assume(whitelistData.id == 0);
|
||||
vm.assume(whitelistData.isRegistered == false);
|
||||
|
||||
hub.registerActionModule(actionModule);
|
||||
|
||||
whitelistData = hub.getActionModuleRegisterData(actionModule);
|
||||
|
||||
assertTrue(whitelistData.isRegistered);
|
||||
}
|
||||
|
||||
function testGetActionModuleRegisterData(address secondActionModule) public {
|
||||
address firstActionModule = makeAddr('FIRST_ACTION_MODULE');
|
||||
vm.assume(firstActionModule != secondActionModule);
|
||||
|
||||
Types.ActionModuleRegisterData memory registerData = hub.getActionModuleRegisterData(secondActionModule);
|
||||
vm.assume(registerData.id == 0);
|
||||
vm.assume(registerData.isRegistered == false);
|
||||
|
||||
registerData = hub.getActionModuleRegisterData(firstActionModule);
|
||||
assertEq(registerData.id, 0);
|
||||
assertFalse(registerData.isRegistered);
|
||||
|
||||
hub.registerActionModule(firstActionModule);
|
||||
|
||||
registerData = hub.getActionModuleRegisterData(firstActionModule);
|
||||
uint256 firstActionModuleId = registerData.id;
|
||||
assertTrue(registerData.isRegistered);
|
||||
|
||||
hub.registerActionModule(secondActionModule);
|
||||
|
||||
registerData = hub.getActionModuleRegisterData(secondActionModule);
|
||||
uint256 secondActionModuleId = registerData.id;
|
||||
assertTrue(registerData.isRegistered);
|
||||
|
||||
assertEq(secondActionModuleId, firstActionModuleId + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user