Extendable Core

The Extendable module is at the heart of the design pattern.

All variables are housed by this core unit and all function calls are handled by it.

When a transaction is executed and calls a function on an Extendable contract, the call flow happens as below.

The Extendable performs a lookup routine that checks what function the transaction is calling, and delegates the call to the appropriate Extension that implements that function. If the function needs contract state, it will access it.

Extension Lookup

When a contract is extended with a new Extension, it is recorded in a mapping that tells our contract what is implemented by the Extension and what should be delegated to it.

This mapping defines for each function, which Extension implements it.

mapping(bytes4 => address) extensionContracts;

The Extension that is called by a transaction is determined using the function selector which is used as the key to perform the lookup. Once the correct Extension address is retrieved, the transaction call is forwarded to that Extension where function execution continues.

The function selector is extracted from the transaction itself from msg.sig.

The lookup and execution routine (extracted from Extendable.sol) contains the main lookup and subsequent delegation:

ExtendableState storage state = ExtendableStorage._getState();

if (state.extensionContracts[msg.sig] != address(0x0)) {
    _delegate(state.extensionContracts[msg.sig]);
} else {                                                 
    revert ExtensionNotImplemented();
}

If a valid Extension exists for the function, delegate the execution to it, else we revert with ExtensionNotImplemented.

Last updated