diff --git a/contracts/rules/username/ReservedUsernameRule.sol b/contracts/rules/username/ReservedUsernameRule.sol index 91dca33..63b1817 100644 --- a/contracts/rules/username/ReservedUsernameRule.sol +++ b/contracts/rules/username/ReservedUsernameRule.sol @@ -12,46 +12,80 @@ contract ReservedUsernameRule is IUsernameRule { using AccessControlLib for IAccessControl; using AccessControlLib for address; - // uint256(keccak256("CREATE_RESERVED_USERNAME")) - uint256 immutable CREATE_RESERVED_USERNAME_PID = - uint256(0xfb95904fa3067a919177cb314539246e6f76089564454716cce76492e210edfc); + // TODO: Think about renaming Username primitive to Namespace or something else + event Lens_ReservedUsernameRule_UsernameReserved( + address indexed usernamePrimitive, bytes32 indexed configSalt, string indexed indexedUsername, string username + ); + event Lens_ReservedUsernameRule_UsernameReleased( + address indexed usernamePrimitive, bytes32 indexed configSalt, string indexed indexedUsername, string username + ); + event Lens_ReservedUsernameRule_ReservedUsernameCreated( + address indexed usernamePrimitive, + bytes32 indexed configSalt, + string indexed indexedUsername, + string username, + address account, + address createdBy + ); // keccak256("lens.param.key.accessControl"); bytes32 immutable ACCESS_CONTROL_PARAM_KEY = 0x6552dd4db64bdb68f2725e4865ecb072df1c2befcfb455b69e2d2b886a8e185e; - // keccak256("lens.rules.username.CharsetUsernameRule.param.key.CharsetRestrictions.allowNumeric"); - bytes32 immutable ALLOW_NUMERIC_PARAM_KEY = 0x99d79d7e6786d3f6700df19cf91a74d5ed8a7432315a6bd2c8e4b2f31d3ac48a; - // keccak256("lens.rules.username.CharsetUsernameRule.param.key.CharsetRestrictions.allowLatinLowercase"); + // keccak256("lens.param.key.usernamesToReserve"); + bytes32 immutable USERNAMES_TO_RESERVE_PARAM_KEY = 0xe35845d5270ebd172ba5dfaf14a7256cbc847d131e6a9d37dcd9bce7c75e9e77; + // keccak256("lens.param.key.usernamesToRelease"); + bytes32 immutable USERNAMES_TO_RELEASE_PARAM_KEY = 0x68f854736312031d89be36bdf38f9d77e90822b1a6417823a39f8721c4db9cb2; - mapping(address => mapping(bytes4 => mapping(bytes32 => Configuration))) internal _configuration; + uint256 constant CREATE_RESERVED_USERNAME_PID = uint256(keccak256("CREATE_RESERVED_USERNAME")); + mapping(address => mapping(bytes32 => address)) internal _accessControl; mapping(address => mapping(bytes32 => mapping(string => bool))) internal _isUsernameReserved; constructor() { - emit Events.Lens_PermissionId_Available(SKIP_CHARSET_PID, "SKIP_CHARSET"); + emit Events.Lens_PermissionId_Available(CREATE_RESERVED_USERNAME_PID, "CREATE_RESERVED_USERNAME"); } - function configure( - bytes4 ruleSelector, - bytes32 salt, - KeyValue[] calldata ruleConfigurationParams - ) external override { - require(ruleSelector == this.processCreation.selector); - Configuration memory configuration = _extractConfigurationFromParams(ruleConfigurationParams); - configuration.accessControl.verifyHasAccessFunction(); - _configuration[msg.sender][ruleSelector][salt] = configuration; + function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override { + address accessControl; + for (uint256 i = 0; i < ruleParams.length; i++) { + if (ruleParams[i].key == ACCESS_CONTROL_PARAM_KEY) { + accessControl = abi.decode(ruleParams[i].value, (address)); + } else if (ruleParams[i].key == USERNAMES_TO_RESERVE_PARAM_KEY) { + string[] memory usernamesToReserve = abi.decode(ruleParams[i].value, (string[])); + for (uint256 j = 0; j < usernamesToReserve.length; j++) { + require(!_isUsernameReserved[msg.sender][configSalt][usernamesToReserve[j]]); + _isUsernameReserved[msg.sender][configSalt][usernamesToReserve[j]] = true; + emit Lens_ReservedUsernameRule_UsernameReserved( + msg.sender, configSalt, usernamesToReserve[j], usernamesToReserve[j] + ); + } + } else if (ruleParams[i].key == USERNAMES_TO_RELEASE_PARAM_KEY) { + string[] memory usernamesToRelease = abi.decode(ruleParams[i].value, (string[])); + for (uint256 j = 0; j < usernamesToRelease.length; j++) { + require(_isUsernameReserved[msg.sender][configSalt][usernamesToRelease[j]]); + _isUsernameReserved[msg.sender][configSalt][usernamesToRelease[j]] = false; + emit Lens_ReservedUsernameRule_UsernameReleased( + msg.sender, configSalt, usernamesToRelease[j], usernamesToRelease[j] + ); + } + } + } + accessControl.verifyHasAccessFunction(); + _accessControl[msg.sender][configSalt] = accessControl; } function processCreation( bytes32 configSalt, address originalMsgSender, - address, /* account */ + address account, string calldata username, - KeyValue[] calldata, /* primitiveCustomParams */ - KeyValue[] calldata /* ruleExecutionParams */ - ) external view override { - Configuration memory configuration = _configuration[msg.sender][this.processCreation.selector][configSalt]; - if (!configuration.accessControl.hasAccess(originalMsgSender, SKIP_CHARSET_PID)) { - _processRestrictions(username, configuration.charsetRestrictions); + KeyValue[] calldata, /* primitiveParams */ + KeyValue[] calldata /* ruleParams */ + ) external override { + if (_isUsernameReserved[msg.sender][configSalt][username]) { + _accessControl[msg.sender][configSalt].requireAccess(originalMsgSender, CREATE_RESERVED_USERNAME_PID); + emit Lens_ReservedUsernameRule_ReservedUsernameCreated( + msg.sender, configSalt, username, username, account, originalMsgSender + ); } } @@ -59,8 +93,8 @@ contract ReservedUsernameRule is IUsernameRule { bytes32, /* configSalt */ address, /* originalMsgSender */ string calldata, /* username */ - KeyValue[] calldata, /* primitiveCustomParams */ - KeyValue[] calldata /* ruleExecutionParams */ + KeyValue[] calldata, /* primitiveParams */ + KeyValue[] calldata /* ruleParams */ ) external pure override { revert(); } @@ -70,8 +104,8 @@ contract ReservedUsernameRule is IUsernameRule { address, /* originalMsgSender */ address, /* account */ string calldata, /* username */ - KeyValue[] calldata, /* primitiveCustomParams */ - KeyValue[] calldata /* ruleExecutionParams */ + KeyValue[] calldata, /* primitiveParams */ + KeyValue[] calldata /* ruleParams */ ) external pure override { revert(); } @@ -81,8 +115,8 @@ contract ReservedUsernameRule is IUsernameRule { address, /* originalMsgSender */ address, /* account */ string calldata, /* username */ - KeyValue[] calldata, /* primitiveCustomParams */ - KeyValue[] calldata /* ruleExecutionParams */ + KeyValue[] calldata, /* primitiveParams */ + KeyValue[] calldata /* ruleParams */ ) external pure override { revert(); }