Skip to content

Latest commit

 

History

History
1018 lines (815 loc) · 29.3 KB

ModulesProxyRegistry.md

File metadata and controls

1018 lines (815 loc) · 29.3 KB

ModulesProxyRegistry.sol

View Source: contracts/proxy/modules/ModulesProxyRegistry.sol

↗ Extends: IModulesProxyRegistry, ProxyOwnable ↘ Derived Contracts: ModulesProxy

ModulesProxyRegistry contract

Contract Members

Constants & Variables

bytes32 internal constant KEY_IMPLEMENTATION;

Functions


constructor

Constructor is internal to make contract abstract

function () internal nonpayable
Source Code
constructor() internal {
        // abstract
    }

addModule

⤾ overrides IModulesProxyRegistry.addModule

Add module functions. Overriding functions is not allowed. To replace modules use replaceModule function.

function addModule(address _impl) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_impl address Module implementation address
Source Code
function addModule(address _impl) external onlyProxyOwner {
        _addModule(_impl);
    }

addModules

⤾ overrides IModulesProxyRegistry.addModules

Add modules functions.

function addModules(address[] _implementations) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_implementations address[] Modules implementation addresses
Source Code
function addModules(address[] calldata _implementations) external onlyProxyOwner {
        _addModules(_implementations);
    }

replaceModule

⤾ overrides IModulesProxyRegistry.replaceModule

Replace module - remove the previous, add the new one

function replaceModule(address _oldModuleImpl, address _newModuleImpl) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_oldModuleImpl address Module implementation address to remove
_newModuleImpl address Module implementation address to add
Source Code
function replaceModule(address _oldModuleImpl, address _newModuleImpl)
        external
        onlyProxyOwner
    {
        _replaceModule(_oldModuleImpl, _newModuleImpl);
    }

replaceModules

⤾ overrides IModulesProxyRegistry.replaceModules

Add modules functions.

function replaceModules(address[] _implementationsFrom, address[] _implementationsTo) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_implementationsFrom address[] Modules to replace
_implementationsTo address[] Replacing modules
Source Code
function replaceModules(
        address[] calldata _implementationsFrom,
        address[] calldata _implementationsTo
    ) external onlyProxyOwner {
        require(
            _implementationsFrom.length == _implementationsTo.length,
            "ModulesProxyRegistry::replaceModules: arrays sizes must be equal"
        ); //MR10

        // because the order of addresses is arbitrary, all modules are removed first to avoid collisions
        _removeModules(_implementationsFrom);
        _addModules(_implementationsTo);
    }

removeModule

⤾ overrides IModulesProxyRegistry.removeModule

To disable module - set all its functions implementation to address(0)

function removeModule(address _impl) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_impl address implementation address
Source Code
function removeModule(address _impl) external onlyProxyOwner {
        _removeModule(_impl);
    }

removeModules

⤾ overrides IModulesProxyRegistry.removeModules

Add modules functions.

function removeModules(address[] _implementations) external nonpayable onlyProxyOwner 

Arguments

Name Type Description
_implementations address[] Modules implementation addresses
Source Code
function removeModules(address[] calldata _implementations) external onlyProxyOwner {
        _removeModules(_implementations);
    }

getFuncImplementation

⤾ overrides IModulesProxyRegistry.getFuncImplementation

function getFuncImplementation(bytes4 _sig) external view
returns(address)

Arguments

Name Type Description
_sig bytes4 Function signature to get impmementation address for

Returns

Function's contract implelementation address

Source Code
function getFuncImplementation(bytes4 _sig) external view returns (address) {
        return _getFuncImplementation(_sig);
    }

canAddModule

⤾ overrides IModulesProxyRegistry.canAddModule

Verifies if no functions from the module already registered

function canAddModule(address _impl) external view
returns(bool)

Arguments

Name Type Description
_impl address Module implementation address to verify

Returns

True if module can be added

Source Code
function canAddModule(address _impl) external view returns (bool) {
        return _canAddModule(_impl);
    }

canNotAddModules

⤾ overrides IModulesProxyRegistry.canNotAddModules

Multiple modules verification if there are functions from the modules already registered

function canNotAddModules(address[] _implementations) public view
returns(address[])

Arguments

Name Type Description
_implementations address[] modules implementation addresses to verify

Returns

addresses of registered modules

Source Code
function canNotAddModules(address[] memory _implementations)
        public
        view
        returns (address[] memory)
    {
        for (uint256 i = 0; i < _implementations.length; i++) {
            if (_canAddModule(_implementations[i])) {
                delete _implementations[i];
            }
        }
        return _implementations;
    }

checkClashingFuncSelectors

⤾ overrides IModulesProxyRegistry.checkClashingFuncSelectors

Used externally to verify module being added for clashing

function checkClashingFuncSelectors(address _newModule) external view
returns(clashingModules address[], clashingModulesFuncSelectors bytes4[], clashingProxyRegistryFuncSelectors bytes4[])

Arguments

Name Type Description
_newModule address module implementation which functions to verify

Returns

Clashing functions signatures and corresponding modules (contracts) addresses

Source Code
function checkClashingFuncSelectors(address _newModule)
        external
        view
        returns (
            address[] memory clashingModules,
            bytes4[] memory clashingModulesFuncSelectors,
            bytes4[] memory clashingProxyRegistryFuncSelectors
        )
    {
        require(
            _newModule.isContract(),
            "ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract"
        ); //MR06
        bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();
        bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list
        uint256 clashingProxyRegistryFuncsSize;
        uint256 clashingArraySize;
        uint256 clashingArrayIndex;
        uint256 clashingRegistryArrayIndex;

        for (uint256 i = 0; i < newModuleFunctions.length; i++) {
            address funcImpl = _getFuncImplementation(newModuleFunctions[i]);
            if (funcImpl != address(0) && funcImpl != _newModule) {
                clashingArraySize++;
            } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))
                clashingProxyRegistryFuncsSize++;
        }
        clashingModules = new address[](clashingArraySize);
        clashingModulesFuncSelectors = new bytes4[](clashingArraySize);
        clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);

        if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)
            //return empty arrays
            return (
                clashingModules,
                clashingModulesFuncSelectors,
                clashingProxyRegistryFuncSelectors
            );
        for (uint256 i = 0; i < newModuleFunctions.length; i++) {
            address funcImpl = _getFuncImplementation(newModuleFunctions[i]);
            if (funcImpl != address(0)) {
                clashingModules[clashingArrayIndex] = funcImpl;
                clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];
                clashingArrayIndex++;
            }
            for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {
                //ModulesProxyRegistry has a clashing function selector
                if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {
                    clashingProxyRegistryFuncSelectors[
                        clashingRegistryArrayIndex
                    ] = proxyRegistryFunctions[j];
                    clashingRegistryArrayIndex++;
                }
            }
        }
    }

isModuleRegistered

function isModuleRegistered(address _impl) external view
returns(bool)

Arguments

Name Type Description
_impl address deployment address to verify

Returns

true if _impl address is a registered module

Source Code
function isModuleRegistered(address _impl) external view returns (bool) {
        return _getFirstRegisteredModuleAddress(_impl) == _impl;
    }

_getFirstRegisteredModuleAddress

function _getFirstRegisteredModuleAddress(address _impl) internal view
returns(address)

Arguments

Name Type Description
_impl address
Source Code
function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {
        require(
            _impl.isContract(),
            "ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract"
        );
        bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();
        for (uint256 i = 0; i < functions.length; i++) {
            address _moduleImpl = _getFuncImplementation(functions[i]);
            if (_moduleImpl != address(0)) {
                return (_moduleImpl);
            }
        }
        return address(0);
    }

_getFuncImplementation

function _getFuncImplementation(bytes4 _sig) internal view
returns(address)

Arguments

Name Type Description
_sig bytes4
Source Code
function _getFuncImplementation(bytes4 _sig) internal view returns (address) {
        //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:
        bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));
        address implementation;
        assembly {
            implementation := sload(key)
        }
        return implementation;
    }

_addModule

function _addModule(address _impl) internal nonpayable

Arguments

Name Type Description
_impl address
Source Code
function _addModule(address _impl) internal {
        require(_impl.isContract(), "ModulesProxyRegistry::_addModule: address is not a contract"); //MR01
        bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();
        for (uint256 i = 0; i < functions.length; i++) {
            require(
                _getFuncImplementation(functions[i]) == address(0),
                "ModulesProxyRegistry::_addModule: function already registered - use replaceModule function"
            ); //MR02
            require(functions[i] != bytes4(0), "does not allow empty function id"); // MR03
            require(
                !_isFuncClashingWithProxyFunctions(functions[i]),
                "ModulesProxyRegistry::_addModule: has a function with the same signature"
            ); //MR09
            _setModuleFuncImplementation(functions[i], _impl);
        }
        emit AddModule(_impl);
    }

_addModules

function _addModules(address[] _implementations) internal nonpayable

Arguments

Name Type Description
_implementations address[]
Source Code
function _addModules(address[] memory _implementations) internal {
        for (uint256 i = 0; i < _implementations.length; i++) {
            _addModule(_implementations[i]);
        }
    }

_removeModule

function _removeModule(address _impl) internal nonpayable onlyProxyOwner 

Arguments

Name Type Description
_impl address
Source Code
function _removeModule(address _impl) internal onlyProxyOwner {
        require(
            _impl.isContract(),
            "ModulesProxyRegistry::_removeModule: address is not a contract"
        ); //MR07
        bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();
        for (uint256 i = 0; i < functions.length; i++)
            _setModuleFuncImplementation(functions[i], address(0));

        emit RemoveModule(_impl);
    }

_removeModules

function _removeModules(address[] _implementations) internal nonpayable

Arguments

Name Type Description
_implementations address[]
Source Code
function _removeModules(address[] memory _implementations) internal {
        for (uint256 i = 0; i < _implementations.length; i++) {
            _removeModule(_implementations[i]);
        }
    }

_replaceModule

function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal nonpayable

Arguments

Name Type Description
_oldModuleImpl address
_newModuleImpl address
Source Code
function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {
        if (_oldModuleImpl != _newModuleImpl) {
            require(
                _newModuleImpl.isContract(),
                "ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract"
            ); //MR03
            require(
                _oldModuleImpl.isContract(),
                "ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract"
            ); //MR04
            _removeModule(_oldModuleImpl);
            _addModule(_newModuleImpl);

            emit ReplaceModule(_oldModuleImpl, _newModuleImpl);
        }
    }

_setModuleFuncImplementation

function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal nonpayable

Arguments

Name Type Description
_sig bytes4
_impl address
Source Code
function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {
        emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);

        bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));
        assembly {
            sstore(key, _impl)
        }
    }

_isFuncClashingWithProxyFunctions

function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure
returns(bool)

Arguments

Name Type Description
_sig bytes4
Source Code
function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {
        bytes4[] memory functionList = _getFunctionsList();
        for (uint256 i = 0; i < functionList.length; i++) {
            if (_sig == functionList[i])
                //ModulesProxyRegistry has function with the same id
                return true;
        }
        return false;
    }

_canAddModule

function _canAddModule(address _impl) internal view
returns(bool)

Arguments

Name Type Description
_impl address
Source Code
function _canAddModule(address _impl) internal view returns (bool) {
        require(
            _impl.isContract(),
            "ModulesProxyRegistry::_canAddModule: address is not a contract"
        ); //MR06
        bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();
        for (uint256 i = 0; i < functions.length; i++)
            if (_getFuncImplementation(functions[i]) != address(0)) return (false);
        return true;
    }

_getFunctionsList

function _getFunctionsList() internal pure
returns(bytes4[])
Source Code
function _getFunctionsList() internal pure returns (bytes4[] memory) {
        bytes4[] memory functionList = new bytes4[](13);
        functionList[0] = this.getFuncImplementation.selector;
        functionList[1] = this.addModule.selector;
        functionList[2] = this.addModules.selector;
        functionList[3] = this.removeModule.selector;
        functionList[4] = this.removeModules.selector;
        functionList[5] = this.replaceModule.selector;
        functionList[6] = this.replaceModules.selector;
        functionList[7] = this.canAddModule.selector;
        functionList[8] = this.canNotAddModules.selector;
        functionList[9] = this.setProxyOwner.selector;
        functionList[10] = this.getProxyOwner.selector;
        functionList[11] = this.checkClashingFuncSelectors.selector;
        functionList[12] = this.isModuleRegistered.selector;
        return functionList;
    }

Contracts