Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatten if structure in checkPermissions #97

Merged
merged 2 commits into from
Apr 15, 2024

Conversation

Ramarti
Copy link

@Ramarti Ramarti commented Apr 14, 2024

Maintaining the same logic, we can reorder the code to:

  • Revert/return early
  • Reduce if nesting

@kingster-will
Copy link

I haven’t reviewed all the logic and cases yet. However, it's generally best to avoid modifying sensitive logic just before a code freeze, unless it's necessary to fix a bug.

Copy link
Member

@LeoHChen LeoHChen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any more test coverage needed ?

Copy link
Member

@LeoHChen LeoHChen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the flatten code, easier to read and understand.

We have to make sure we have 100% branch coverage of this function. And the new code shouldn't break it.

@Ramarti
Copy link
Author

Ramarti commented Apr 15, 2024

@kingster-will already achieved 100% coverage, these changes don't seem to affect coverage

Captura de pantalla 2024-04-15 a las 12 33 42

We could add extra checks to make sure an upgrade doesn't mistakenly add an additional state that is not UNSET, bypassing the check in setPermissions. This would actually lower coverage, since we can't hit those checks.

function checkPermission(address ipAccount, address signer, address to, bytes4 func) external view {
        AccessControllerStorage storage $ = _getAccessControllerStorage();
        // Must be a valid IPAccount
        if (!IIPAccountRegistry($.ipAccountRegistry).isIpAccount(ipAccount)) {
            revert Errors.AccessController__IPAccountIsNotValid(ipAccount);
        }
        // Owner can call any contracts either registered module or unregistered/external contracts
        if (IIPAccount(payable(ipAccount)).owner() == signer) {
            return;
        }

        // If the caller (signer) is not the Owner, IPAccount is limited to interactions with only registered modules.
        // These interactions can be either initiating calls to these modules or receiving calls from them.
        // The IP account can also modify its own Permissions settings.
        if (
            to != address(this) &&
            !IModuleRegistry($.moduleRegistry).isRegistered(to) &&
            !IModuleRegistry($.moduleRegistry).isRegistered(signer)
        ) {
            revert Errors.AccessController__BothCallerAndRecipientAreNotRegisteredModule(signer, to);
        }
        uint functionPermission = getPermission(ipAccount, signer, to, func);
        // This is unreachable, but just in case
        if (functionPermission > AccessPermission.DENY) {
            revert Errors.AccessController__PermissionIsNotValid();  // ----> Unreachable
        }
        // Specific function permission overrides wildcard/general permission
        if (functionPermission == AccessPermission.ALLOW) {
            return;
        }
        // Specific function permission is DENY, revert
        if (functionPermission == AccessPermission.DENY) {
            revert Errors.AccessController__PermissionDenied(ipAccount, signer, to, func);
        }
        // Function permission is UNSET, check module level permission
        uint8 modulePermission = getPermission(ipAccount, signer, to, bytes4(0));
        // This is unreachable, but just in case
        if (modulePermission > AccessPermission.DENY) {
            revert Errors.AccessController__PermissionIsNotValid(); // ----> Unreachable
        }
        // Return true if allow to call all functions of the module
        if (modulePermission == AccessPermission.ALLOW) {
            return;
        }
        // Module level permission is DENY, revert
        if (modulePermission == AccessPermission.DENY) {
            revert Errors.AccessController__PermissionDenied(ipAccount, signer, to, func);
        }
        // Module level permission is UNSET, check transaction signer level permission
        // Pass if the ipAccount allow the signer to call all functions of all modules
        // Otherwise, revert
        if (getPermission(ipAccount, signer, address(0), bytes4(0)) != AccessPermission.ALLOW) {
            revert Errors.AccessController__PermissionDenied(ipAccount, signer, to, func);
        }
        // If the transaction signer is allowed to call all functions of all modules, return
    }

Copy link

@jdubpark jdubpark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flattening looks good, I think this PR can be merged since it's just shuffling around the branches.

contracts/access/AccessController.sol Outdated Show resolved Hide resolved
contracts/access/AccessController.sol Outdated Show resolved Hide resolved
Copy link

@kingster-will kingster-will left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General looks good!
Please handle the naming change and merge.

@LeoHChen LeoHChen merged commit 9471890 into storyprotocol:main Apr 15, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants