Skip to content

Commit

Permalink
feat: Proxy with enhanced upgrade manager idea
Browse files Browse the repository at this point in the history
  • Loading branch information
donosonaumczuk committed Dec 26, 2024
1 parent f53ce58 commit 164b5af
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
20 changes: 20 additions & 0 deletions contracts/core/upgradeability/IVersionedBeacon.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (C) 2024 Lens Labs. All Rights Reserved.
pragma solidity ^0.8.0;

interface IVersionedBeacon {
/**
* @dev Returns the latest implementation held by the Beacon.
* @return Address of the implementation.
*/
function implementation() external view returns (address);

/**
* @dev Returns the implementation that corresponds to the requested version.
* @param implementationVersion Version of the implementation to return.
* @return Address of the implementation.
*/
function implementation(
uint256 implementationVersion
) external view returns (address);
}
135 changes: 135 additions & 0 deletions contracts/core/upgradeability/Proxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (C) 2024 Lens Labs. All Rights Reserved.
pragma solidity ^0.8.0;

import {IVersionedBeacon} from "./IVersionedBeacon.sol";

contract Proxy {
bool _autoUpgrade;
address _currentImplementation;
address _beacon;
address _proxyAdmin;

event ProxyAdminChanged(address indexed proxyAdmin);
event Upgraded(address indexed implementation);
event BeaconChanged(address indexed beacon);
event AutoUpgrade(bool enabled);

constructor(address proxyAdmin, address beacon) {
_proxyAdmin = proxyAdmin;
emit ProxyAdminChanged(proxyAdmin);
_autoUpgrade = true;
emit AutoUpgrade(true);
_beacon = beacon;
emit BeaconChanged(beacon);
_fetchImplFromBaconAndAutoUpgradeIfNeeded();
}

function optOutFromAutoUpgrade() external {
require(msg.sender == _proxyAdmin);
_autoUpgrade = false;
emit AutoUpgrade(false);
}

function optInFromAutoUpgrade() external {
require(msg.sender == _proxyAdmin);
_autoUpgrade = true;
emit AutoUpgrade(true);
_fetchImplFromBaconAndAutoUpgradeIfNeeded();
}

function setImplementation(
address implementation
) external {
require(msg.sender == _proxyAdmin);
require(_autoUpgrade == false);
if (implementation != _currentImplementation) {
_currentImplementation = implementation;
emit Upgraded(implementation);
}
}

function setBeacon(
address beacon
) external {
require(msg.sender == _proxyAdmin);
if (beacon != _beacon) {
_beacon = beacon;
emit BeaconChanged(beacon);
}
if (_autoUpgrade) {
_fetchImplFromBaconAndAutoUpgradeIfNeeded();
}
}

function triggerUpgrade(
uint256 implementationVersion
) external {
require(msg.sender == _proxyAdmin);
address implementationFromBeacon = IVersionedBeacon(_beacon).implementation(implementationVersion);
if (implementationFromBeacon != _currentImplementation) {
emit Upgraded(implementationFromBeacon);
_currentImplementation = implementationFromBeacon;
}
}

function triggerUpgrade() external {
require(msg.sender == _proxyAdmin);
_fetchImplFromBaconAndAutoUpgradeIfNeeded();
}

// Function copied from @openzeppelin/contracts/proxy/Proxy.sol::_delegate
function _delegateCallToImplementation(
address implementation
) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())

// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

// Copy the returned data.
returndatacopy(0, 0, returndatasize())

switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}

function _resolveImplementation() internal returns (address) {
address implementation;
if (_autoUpgrade) {
implementation = _fetchImplFromBaconAndAutoUpgradeIfNeeded();
} else {
implementation = _currentImplementation;
}
return implementation;
}

function _fetchImplFromBaconAndAutoUpgradeIfNeeded() internal returns (address) {

This comment has been minimized.

Copy link
@yan-man

yan-man Dec 27, 2024

typo Bacon -> Beacon

This comment has been minimized.

Copy link
@donosonaumczuk

donosonaumczuk Dec 28, 2024

Author Member

Thanks!

address implementationFromBeacon = IVersionedBeacon(_beacon).implementation();
if (implementationFromBeacon != _currentImplementation) {
emit Upgraded(implementationFromBeacon);
_currentImplementation = implementationFromBeacon;
}
return implementationFromBeacon;
}

function _proxyCall() internal {
_delegateCallToImplementation(_resolveImplementation());
}

fallback() external payable {
_proxyCall();
}

receive() external payable {
_proxyCall();
}
}

0 comments on commit 164b5af

Please sign in to comment.