Proxies

Proxies are used in the T-REX protocol to provide the mechanism for upgradeability and flexibility in the deployment and operation of smart contracts. Each contract in the T-REX suite has a specific proxy contract that is adapted to its constructor and calls the correct implementation contract from the implementation authority contract. This ensures that the T-REX protocol can be upgraded and maintained without redeploying all the smart contracts, thus preserving their state and addresses.

How Proxies Work

Proxies in the T-REX protocol follow the proxy pattern, where the proxy contract delegates calls to an implementation contract. The implementation contract contains the actual logic, while the proxy holds the state and delegates calls to the implementation.

  1. Initialization:

    • When a proxy is deployed, it is initialized with the address of the implementation authority contract. This address is stored in a predefined storage slot using the keccak256 hash of a specific string to ensure uniqueness.

  2. Delegate Calls:

    • The proxy contract uses the delegatecall opcode to delegate function calls to the implementation contract. This opcode runs the code of the implementation contract in the context of the proxy contract, meaning that the proxy's state is used while executing the logic of the implementation contract.

  3. Fallback Function:

    • The proxy contains a fallback function that delegates any calls that do not match any existing function to the implementation contract. This allows the proxy to handle a wide range of function calls dynamically.

  4. Upgradeability:

    • The implementation authority contract can be updated, allowing the proxy to point to a new implementation contract. This upgradeability is managed through the setImplementationAuthority function, which ensures that the new implementation authority is valid and contains all necessary implementation addresses.

Example Proxy Contract

Below is an example of a proxy contract for the Claim Topics Registry, demonstrating the initialization and fallback mechanisms:

contract ClaimTopicsRegistryProxy is AbstractProxy {

    constructor(address implementationAuthority) {
        require(implementationAuthority != address(0), "invalid argument - zero address");
        _storeImplementationAuthority(implementationAuthority);
        emit ImplementationAuthoritySet(implementationAuthority);

        address logic = (ITREXImplementationAuthority(getImplementationAuthority())).getCTRImplementation();

        (bool success, ) = logic.delegatecall(abi.encodeWithSignature("init()"));
        require(success, "Initialization failed.");
    }

    fallback() external payable {
        address logic = (ITREXImplementationAuthority(getImplementationAuthority())).getCTRImplementation();

        assembly {
            calldatacopy(0x0, 0x0, calldatasize())
            let success := delegatecall(sub(gas(), 10000), logic, 0x0, calldatasize(), 0, 0)
            let retSz := returndatasize()
            returndatacopy(0, 0, retSz)
            switch success
            case 0 {
                revert(0, retSz)
            }
            default {
                return(0, retSz)
            }
        }
    }
}

Abstract Proxy Contract

All proxies in the T-REX protocol implement the AbstractProxy contract, which provides the foundational mechanisms for handling the implementation authority and delegating calls. Below is the AbstractProxy contract:

abstract contract AbstractProxy is IProxy, Initializable {

    function setImplementationAuthority(address _newImplementationAuthority) external override {
        require(msg.sender == getImplementationAuthority(), "only current implementationAuthority can call");
        require(_newImplementationAuthority != address(0), "invalid argument - zero address");
        require(
            (ITREXImplementationAuthority(_newImplementationAuthority)).getTokenImplementation() != address(0)
            && (ITREXImplementationAuthority(_newImplementationAuthority)).getCTRImplementation() != address(0)
            && (ITREXImplementationAuthority(_newImplementationAuthority)).getIRImplementation() != address(0)
            && (ITREXImplementationAuthority(_newImplementationAuthority)).getIRSImplementation() != address(0)
            && (ITREXImplementationAuthority(_newImplementationAuthority)).getMCImplementation() != address(0)
            && (ITREXImplementationAuthority(_newImplementationAuthority)).getTIRImplementation() != address(0)
        , "invalid Implementation Authority");
        _storeImplementationAuthority(_newImplementationAuthority);
        emit ImplementationAuthoritySet(_newImplementationAuthority);
    }

    function getImplementationAuthority() public override view returns(address) {
        address implemAuth;
        assembly {
            implemAuth := sload(0x821f3e4d3d679f19eacc940c87acf846ea6eae24a63058ea750304437a62aafc)
        }
        return implemAuth;
    }

    function _storeImplementationAuthority(address implementationAuthority) internal {
        assembly {
            sstore(0x821f3e4d3d679f19eacc940c87acf846ea6eae24a63058ea750304437a62aafc, implementationAuthority)
        }
    }
}

Last updated

Logo

ERC3643 ASBL - 2024 - contact@erc3643.org