Skip to content

Commit

Permalink
feat: Restricted signers rules updated after interface changes
Browse files Browse the repository at this point in the history
  • Loading branch information
donosonaumczuk committed Dec 20, 2024
1 parent faba432 commit 567808a
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 104 deletions.
99 changes: 99 additions & 0 deletions contracts/core/libraries/EIP712EncodingLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Copyright (C) 2024 Lens Labs. All Rights Reserved.
pragma solidity ^0.8.17;

import {KeyValue, RuleChange, RuleConfigurationChange, RuleSelectorChange} from "../types/Types.sol";
import {CreatePostParams, EditPostParams} from "../interfaces/IFeed.sol";

library EIP712EncodingLib {
function encodeForEIP712(bytes[] memory bytesArray) internal pure returns (bytes32) {
bytes32[] memory bytesArrayEncodedElements = new bytes32[](bytesArray.length);
Expand Down Expand Up @@ -33,6 +36,102 @@ library EIP712EncodingLib {
return keccak256(abi.encodePacked(bytes32Array));
}

function encodeForEIP712(KeyValue[] memory keyValueArray) internal pure returns (bytes32) {
bytes32[] memory keyValueEncodedElements = new bytes32[](keyValueArray.length);
for (uint256 i = 0; i < keyValueArray.length; i++) {
keyValueEncodedElements[i] = encodeForEIP712(keyValueArray[i]);
}
return encodeForEIP712(keyValueEncodedElements);
}

function encodeForEIP712(RuleChange[] memory ruleChangeArray) internal pure returns (bytes32) {
bytes32[] memory ruleChangeEncodedElements = new bytes32[](ruleChangeArray.length);
for (uint256 i = 0; i < ruleChangeArray.length; i++) {
ruleChangeEncodedElements[i] = encodeForEIP712(ruleChangeArray[i]);
}
return encodeForEIP712(ruleChangeEncodedElements);
}

function encodeForEIP712(RuleSelectorChange[] memory ruleSelectorChangeArray) internal pure returns (bytes32) {
bytes32[] memory ruleSelectorChangeEncodedElements = new bytes32[](ruleSelectorChangeArray.length);
for (uint256 i = 0; i < ruleSelectorChangeArray.length; i++) {
ruleSelectorChangeEncodedElements[i] = encodeForEIP712(ruleSelectorChangeArray[i]);
}
return encodeForEIP712(ruleSelectorChangeEncodedElements);
}

function encodeForEIP712(KeyValue memory keyValue) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256("KeyValue(bytes32 key,bytes value)"), // Type Hash
keyValue.key,
encodeForEIP712(keyValue.value)
)
);
}

function encodeForEIP712(RuleChange memory ruleChange) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256(
"RuleChange(address ruleAddress,bytes32 configSalt,RuleConfigurationChange configurationChanges,RuleSelectorChange[] selectorChanges)"
), // Type Hash
ruleChange.ruleAddress,
ruleChange.configSalt,
encodeForEIP712(ruleChange.configurationChanges),
encodeForEIP712(ruleChange.selectorChanges)
)
);
}

function encodeForEIP712(RuleConfigurationChange memory ruleConfigurationChange) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256("RuleConfigurationChange(bool configure,KeyValue[] ruleParams)"), // Type Hash
ruleConfigurationChange.configure,
encodeForEIP712(ruleConfigurationChange.ruleParams)
)
);
}

function encodeForEIP712(RuleSelectorChange memory ruleSelectorChange) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256("RuleSelectorChange(bytes4 ruleSelector,bool isRequired,bool enabled)"), // Type Hash
ruleSelectorChange.ruleSelector,
ruleSelectorChange.isRequired,
ruleSelectorChange.enabled
)
);
}

function encodeForEIP712(CreatePostParams memory createPostParams) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256(
"CreatePostParams(address author,string contentURI,uint256 repostedPostId,uint256 quotedPostId,uint256 repliedPostId,RuleChange[] ruleChanges,KeyValue[] extraData)"
), // Type Hash
createPostParams.author,
encodeForEIP712(createPostParams.contentURI),
createPostParams.repostedPostId,
createPostParams.quotedPostId,
createPostParams.repliedPostId,
encodeForEIP712(createPostParams.ruleChanges),
encodeForEIP712(createPostParams.extraData)
)
);
}

function encodeForEIP712(EditPostParams memory editPostParams) internal pure returns (bytes32) {
return keccak256(
abi.encodePacked(
keccak256("EditPostParams(string contentURI,KeyValue[] extraData)"), // Type Hash
encodeForEIP712(editPostParams.contentURI),
encodeForEIP712(editPostParams.extraData)
)
);
}

function encodeForEIP712(string memory stringValue) internal pure returns (bytes32) {
return keccak256(bytes(stringValue));
}
Expand Down
32 changes: 20 additions & 12 deletions contracts/rules/base/RestrictedSignersRule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.0;

import {EIP712EncodingLib} from "./../../core/libraries/EIP712EncodingLib.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {KeyValue} from "./../../core/types/Types.sol";

// Move to types
struct EIP712Signature {
Expand All @@ -28,7 +29,7 @@ abstract contract RestrictedSignersRule {
event Lens_RestrictedSignersRule_SignerNonceUsed(address indexed signer, uint256 indexed nonce);

struct RulesStorage {
mapping(address => InnerStorage) rulesStorage;
mapping(address => mapping(bytes32 => InnerStorage)) rulesStorage;
}

struct InnerStorage {
Expand All @@ -39,15 +40,19 @@ abstract contract RestrictedSignersRule {
// keccak256('lens.rule.restricted.storage')
bytes32 constant RESTRICTED_RULE_STORAGE_SLOT = 0xcf6ecf8730d498cbf6701bc1140f2b12e988e1c416a85799d241dcfbb3ed90df;

function $rulesStorage() private pure returns (mapping(address => InnerStorage) storage _storage) {
function $rulesStorage()
private
pure
returns (mapping(address => mapping(bytes32 => InnerStorage)) storage _storage)
{
assembly {
_storage.slot := RESTRICTED_RULE_STORAGE_SLOT
}
}

function $rulesStorage(address primitiveAddress) private view returns (InnerStorage storage) {
mapping(address => InnerStorage) storage _rulesStorage = $rulesStorage();
return _rulesStorage[primitiveAddress];
function $rulesStorage(address primitiveAddress, bytes32 configSalt) private view returns (InnerStorage storage) {
mapping(address => mapping(bytes32 => InnerStorage)) storage _rulesStorage = $rulesStorage();
return _rulesStorage[primitiveAddress][configSalt];
}

bytes4 constant EIP1271_MAGIC_VALUE = 0x1626ba7e;
Expand All @@ -59,21 +64,23 @@ abstract contract RestrictedSignersRule {
"RestrictedSignerMessage(bytes4 functionSelector,bytes abiEncodedParams,uint256 nonce,uint256 deadline)"
);

function _configure(bytes calldata data) internal virtual {
function _configure(bytes32 configSalt, KeyValue[] calldata ruleParams) internal virtual {
require(ruleParams.length > 0);
require(ruleParams[0].key == "restrictedSigners"); // TODO: Use proper constant
(address[] memory signers, string[] memory labels, bool[] memory isWhitelisted) =
abi.decode(data, (address[], string[], bool[]));
abi.decode(ruleParams[0].value, (address[], string[], bool[]));
require(signers.length == isWhitelisted.length);
require(signers.length == labels.length);
for (uint256 i = 0; i < signers.length; i++) {
bool wasWhitelisted = $rulesStorage(msg.sender).isWhitelistedSigner[signers[i]];
bool wasWhitelisted = $rulesStorage(msg.sender, configSalt).isWhitelistedSigner[signers[i]];
if (wasWhitelisted == isWhitelisted[i]) {
if (isWhitelisted[i]) {
// Signal removal and re-addition in order to update the label
emit Lens_RestrictedSignersRule_SignerRemoved(signers[i]);
emit Lens_RestrictedSignersRule_SignerAdded(signers[i], labels[i]);
}
} else {
$rulesStorage(msg.sender).isWhitelistedSigner[signers[i]] = isWhitelisted[i];
$rulesStorage(msg.sender, configSalt).isWhitelistedSigner[signers[i]] = isWhitelisted[i];
if (isWhitelisted[i]) {
emit Lens_RestrictedSignersRule_SignerAdded(signers[i], labels[i]);
} else {
Expand All @@ -84,6 +91,7 @@ abstract contract RestrictedSignersRule {
}

function _validateRestrictedSignerMessage(
bytes32 configSalt,
bytes4 functionSelector,
bytes memory abiEncodedFunctionParams,
EIP712Signature memory signature
Expand All @@ -93,12 +101,12 @@ abstract contract RestrictedSignersRule {
if (block.timestamp > signature.deadline) {
revert("Errors.SignatureExpired()");
}
if ($rulesStorage(msg.sender).wasSignerNonceUsed[signature.signer][signature.nonce]) {
if ($rulesStorage(msg.sender, configSalt).wasSignerNonceUsed[signature.signer][signature.nonce]) {
revert("Errors.SignatureNonceUsed()");
}
$rulesStorage(msg.sender).wasSignerNonceUsed[signature.signer][signature.nonce] = true;
$rulesStorage(msg.sender, configSalt).wasSignerNonceUsed[signature.signer][signature.nonce] = true;
emit Lens_RestrictedSignersRule_SignerNonceUsed(signature.signer, signature.nonce);
if (!$rulesStorage(msg.sender).isWhitelistedSigner[signature.signer]) {
if (!$rulesStorage(msg.sender, configSalt).isWhitelistedSigner[signature.signer]) {
revert("Errors.SignerNotWhitelisted()");
}
bytes32 hashStruct = _calculateMessageHashStruct(message);
Expand Down
77 changes: 77 additions & 0 deletions contracts/rules/feed/RestrictedSignersFeedRule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (C) 2024 Lens Labs. All Rights Reserved.
pragma solidity ^0.8.0;

import {CreatePostParams, EditPostParams} from "./../../core/interfaces/IFeed.sol";
import {IFeedRule} from "./../../core/interfaces/IFeedRule.sol";
import {RestrictedSignersRule, EIP712Signature} from "./../base/RestrictedSignersRule.sol";
import {KeyValue, RuleChange} from "./../../core/types/Types.sol";
import {EIP712EncodingLib} from "./../../core/libraries/EIP712EncodingLib.sol";

contract RestrictedSignersFeedRule is RestrictedSignersRule, IFeedRule {
function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override {
_configure(configSalt, ruleParams);
}

function processCreatePost(
bytes32 configSalt,
uint256 postId,
CreatePostParams calldata postParams,
KeyValue[] calldata primitiveParams,
KeyValue[] calldata ruleParams
) external override {
_validateRestrictedSignerMessage({
configSalt: configSalt,
functionSelector: IFeedRule.processCreatePost.selector,
abiEncodedFunctionParams: abi.encode(
postId, EIP712EncodingLib.encodeForEIP712(postParams), EIP712EncodingLib.encodeForEIP712(primitiveParams)
),
signature: abi.decode(ruleParams[0].value, (EIP712Signature))
});
}

function processEditPost(
bytes32 configSalt,
uint256 postId,
EditPostParams calldata postParams,
KeyValue[] calldata primitiveParams,
KeyValue[] calldata ruleParams
) external override {
_validateRestrictedSignerMessage({
configSalt: configSalt,
functionSelector: IFeedRule.processEditPost.selector,
abiEncodedFunctionParams: abi.encode(
postId, EIP712EncodingLib.encodeForEIP712(postParams), EIP712EncodingLib.encodeForEIP712(primitiveParams)
),
signature: abi.decode(ruleParams[0].value, (EIP712Signature))
});
}

function processRemovePost(
bytes32 configSalt,
uint256 postId,
KeyValue[] calldata primitiveParams,
KeyValue[] calldata ruleParams
) external override {
_validateRestrictedSignerMessage({
configSalt: configSalt,
functionSelector: IFeedRule.processRemovePost.selector,
abiEncodedFunctionParams: abi.encode(postId, EIP712EncodingLib.encodeForEIP712(primitiveParams)),
signature: abi.decode(ruleParams[0].value, (EIP712Signature))
});
}

function processPostRuleChanges(
bytes32 configSalt,
uint256 postId,
RuleChange[] calldata ruleChanges,
KeyValue[] calldata ruleParams
) external override {
_validateRestrictedSignerMessage({
configSalt: configSalt,
functionSelector: IFeedRule.processPostRuleChanges.selector,
abiEncodedFunctionParams: abi.encode(postId, EIP712EncodingLib.encodeForEIP712(ruleChanges)),
signature: abi.decode(ruleParams[0].value, (EIP712Signature))
});
}
}
53 changes: 0 additions & 53 deletions contracts/rules/feed/RestrictedSignersFeedRule.sol.bak

This file was deleted.

Loading

0 comments on commit 567808a

Please sign in to comment.