DEV Community

Syed Ghufran Hassan
Syed Ghufran Hassan

Posted on

Solidity Pattern - Proxy Delegate and Decorator Patterns

In Solidity, the Proxy Delegate and Decorator patterns are used to enhance contracts, particularly for upgradability and modular functionality. These patterns are key for separating logic and state, allowing contracts to be updated without modifying the original state.

Proxy Delegate Pattern (Upgradable Proxy Pattern) The Proxy Delegate pattern is commonly used for contract upgradability. It involves using a proxy contract to delegate function calls to a logic contract (also called an implementation contract) via the delegatecall opcode. This allows for the separation of contract logic and data storage, making it possible to upgrade the contract logic without altering the contract’s storage or re-deploying it.

Key Concepts: Proxy Contract: A contract that holds the storage and delegates all calls to another contract (the implementation contract). Implementation Contract: The contract that contains the logic. This contract can be replaced without affecting the proxy. delegatecall: A low-level Solidity opcode that executes a function from another contract while preserving the calling context (i.e., the storage and msg.sender).

// Proxy Contract

pragma solidity ^0.8.0;

contract Proxy { address public implementation;

constructor(address _implementation) {
    implementation = _implementation;
}

// Fallback function will delegate the call to the implementation contract
fallback() external payable {
    address impl = implementation;
    require(impl != address(0), "Implementation contract not set");

    // Delegate the call to the implementation contract
    (bool success, bytes memory data) = impl.delegatecall(msg.data);
    require(success, "Delegatecall failed");

    // Return the data returned by the implementation contract
    assembly {
        return(add(data, 0x20), mload(data))
    }
}

// Upgrading the contract by changing the implementation address
function upgradeTo(address _newImplementation) external {
    implementation = _newImplementation;
}
}
Enter fullscreen mode Exit fullscreen mode

How it Works: Proxy Contract: This contract holds the state, and any function calls to it are delegated to the Implementation Contract via delegatecall. The storage layout of the proxy remains unchanged even when the implementation logic is upgraded. Implementation Contract: This contains the actual logic (functions) but does not hold any state. By using delegatecall, it can modify the proxy contract's storage.

// Implementation Contract

pragma solidity ^0.8.0;

contract MyLogic { uint public x;

function setX(uint _x) external {
    x = _x;
}
}

Enter fullscreen mode Exit fullscreen mode

We will continue with decorator pattern in next post.

Thank you for viewing.

Top comments (0)