Skip to content

Commit

Permalink
feat(RoninTransparentProxy): add standard for transparent proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
TuDo1403 committed Oct 4, 2024
1 parent 2a720f4 commit 67b273f
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 101 deletions.
103 changes: 61 additions & 42 deletions script/BaseMigration.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@
pragma solidity >=0.6.2 <0.9.0;
pragma experimental ABIEncoderV2;

import { TransparentProxyV2 } from "../src/TransparentProxyV2.sol";
import { TransparentProxyOZv4_9_5 } from "../src/TransparentProxyOZv4_9_5.sol";
import { LibString } from "../dependencies/@solady-0.0.228/src/utils/LibString.sol";
import { console } from "../dependencies/@forge-std-1.9.1/src/console.sol";
import { StdStyle } from "../dependencies/@forge-std-1.9.1/src/StdStyle.sol";
import { Vm } from "../dependencies/@forge-std-1.9.1/src/Vm.sol";
import { ScriptExtended, IScriptExtended } from "./extensions/ScriptExtended.s.sol";
import { OnchainExecutor } from "./OnchainExecutor.s.sol"; // cheat to load artifact to parent `out` directory
import { StdStyle } from "../dependencies/forge-std-1.9.3/src/StdStyle.sol";
import { Vm } from "../dependencies/forge-std-1.9.3/src/Vm.sol";
import { console } from "../dependencies/forge-std-1.9.3/src/console.sol";
import { LibString } from "../dependencies/solady-0.0.228/src/utils/LibString.sol";
import { RoninTransparentProxy } from "../src/RoninTransparentProxy.sol";

import { OnchainExecutor } from "./OnchainExecutor.s.sol";
import { IScriptExtended, ScriptExtended } from "./extensions/ScriptExtended.s.sol"; // cheat to load artifact to parent
// `out` directory
import { IMigrationScript } from "./interfaces/IMigrationScript.sol";
import { LibProxy } from "./libraries/LibProxy.sol";

import { DeployInfo, LibDeploy, ProxyInterface, UpgradeInfo } from "./libraries/LibDeploy.sol";
import { LibInitializeGuard } from "./libraries/LibInitializeGuard.sol";
import { LibProxy } from "./libraries/LibProxy.sol";

import { TContract, TNetwork } from "./types/Types.sol";
import { DefaultContract } from "./utils/DefaultContract.sol";
import { ProxyInterface, LibDeploy, DeployInfo, UpgradeInfo } from "./libraries/LibDeploy.sol";
import { cheatBroadcast } from "./utils/Helpers.sol";
import { TContract, TNetwork } from "./types/Types.sol";

abstract contract BaseMigration is ScriptExtended {
using StdStyle for *;
Expand Down Expand Up @@ -58,12 +61,10 @@ abstract contract BaseMigration is ScriptExtended {

function _defaultArguments() internal virtual returns (bytes memory) { }

function switchTo(TNetwork networkType, uint256 forkBlockNumber)
public
virtual
override
returns (TNetwork currNetwork, uint256 currForkId)
{
function switchTo(
TNetwork networkType,
uint256 forkBlockNumber
) public virtual override returns (TNetwork currNetwork, uint256 currForkId) {
(currNetwork, currForkId) = super.switchTo(networkType, forkBlockNumber);
// Should rebuild the shared arguments since different chain may have different shared arguments
_storeRawSharedArguments();
Expand All @@ -75,7 +76,9 @@ abstract contract BaseMigration is ScriptExtended {
vme.logSenderInfo();
}

function loadContractOrDeploy(TContract contractType) public virtual returns (address payable contractAddr) {
function loadContractOrDeploy(
TContract contractType
) public virtual returns (address payable contractAddr) {
string memory contractName = CONFIG.getContractName(contractType);
try this.loadContract(contractType) returns (address payable addr) {
contractAddr = addr;
Expand All @@ -89,7 +92,9 @@ abstract contract BaseMigration is ScriptExtended {
vme.setRawSharedArguments(_sharedArguments());
}

function overrideArgs(bytes memory args) public virtual returns (IMigrationScript) {
function overrideArgs(
bytes memory args
) public virtual returns (IMigrationScript) {
_overriddenArgs = args;
return IMigrationScript(address(this));
}
Expand All @@ -106,7 +111,9 @@ abstract contract BaseMigration is ScriptExtended {
proxyAdmin = loadContract(DefaultContract.ProxyAdmin.key());
}

function _deployImmutable(TContract contractType) internal virtual returns (address payable deployed) {
function _deployImmutable(
TContract contractType
) internal virtual returns (address payable deployed) {
deployed = _deployImmutable({
contractType: contractType,
artifactName: vme.getContractName(contractType),
Expand All @@ -116,11 +123,10 @@ abstract contract BaseMigration is ScriptExtended {
});
}

function _deployImmutable(TContract contractType, bytes memory args)
internal
virtual
returns (address payable deployed)
{
function _deployImmutable(
TContract contractType,
bytes memory args
) internal virtual returns (address payable deployed) {
deployed = _deployImmutable({
contractType: contractType,
artifactName: vme.getContractName(contractType),
Expand Down Expand Up @@ -156,7 +162,9 @@ abstract contract BaseMigration is ScriptExtended {
vme.setAddress(network(), contractType, deployed);
}

function _deployLogic(TContract contractType) internal virtual returns (address payable logic) {
function _deployLogic(
TContract contractType
) internal virtual returns (address payable logic) {
logic = _deployLogic({
contractType: contractType,
artifactName: vme.getContractName(contractType),
Expand All @@ -174,7 +182,12 @@ abstract contract BaseMigration is ScriptExtended {
});
}

function _deployLogic(TContract contractType, string memory artifactName, address by, bytes memory constructorArgs)
function _deployLogic(
TContract contractType,
string memory artifactName,
address by,
bytes memory constructorArgs
)
internal
virtual
logFn(string.concat("_deployLogic ", TContract.unwrap(contractType).unpackOne()))
Expand All @@ -192,15 +205,16 @@ abstract contract BaseMigration is ScriptExtended {
}).deployImplementation();
}

function _deployProxy(TContract contractType) internal virtual returns (address payable deployed) {
function _deployProxy(
TContract contractType
) internal virtual returns (address payable deployed) {
deployed = _deployProxy(contractType, arguments());
}

function _deployProxy(TContract contractType, bytes memory callData)
internal
virtual
returns (address payable deployed)
{
function _deployProxy(
TContract contractType,
bytes memory callData
) internal virtual returns (address payable deployed) {
deployed = _deployProxy({
contractType: contractType,
artifactName: vme.getContractName(contractType),
Expand All @@ -212,11 +226,11 @@ abstract contract BaseMigration is ScriptExtended {
});
}

function _deployProxy(TContract contractType, bytes memory callData, bytes memory logicConstructorArgs)
internal
virtual
returns (address payable deployed)
{
function _deployProxy(
TContract contractType,
bytes memory callData,
bytes memory logicConstructorArgs
) internal virtual returns (address payable deployed) {
deployed = _deployProxy({
contractType: contractType,
artifactName: vme.getContractName(contractType),
Expand Down Expand Up @@ -261,15 +275,21 @@ abstract contract BaseMigration is ScriptExtended {
vme.setAddress(network(), contractType, deployed);
}

function _upgradeProxy(TContract contractType) internal virtual returns (address payable proxy) {
function _upgradeProxy(
TContract contractType
) internal virtual returns (address payable proxy) {
proxy = _upgradeProxy(contractType, arguments());
}

function _upgradeProxy(TContract contractType, bytes memory args) internal virtual returns (address payable proxy) {
proxy = _upgradeProxy(contractType, args, EMPTY_ARGS);
}

function _upgradeProxy(TContract contractType, bytes memory args, bytes memory argsLogicConstructor)
function _upgradeProxy(
TContract contractType,
bytes memory args,
bytes memory argsLogicConstructor
)
internal
virtual
logFn(string.concat("_upgradeProxy ", TContract.unwrap(contractType).unpackOne()))
Expand Down Expand Up @@ -308,7 +328,6 @@ abstract contract BaseMigration is ScriptExtended {
*/
function _precompileProxyContracts() internal pure virtual {
bytes memory dummy;
dummy = type(TransparentProxyV2).creationCode;
dummy = type(TransparentProxyOZv4_9_5).creationCode;
dummy = type(RoninTransparentProxy).creationCode;
}
}
107 changes: 107 additions & 0 deletions src/RoninTransparentProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.20;

import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { ERC1967Utils } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

/**
* @dev Contract TransparentUpgradeableProxy from Openzeppelin v5 with the following modifications:
* - Admin is a parameter in the constructor ( like previous versions) instead of being deployed
* - Let the admin get access to the proxy via `functionDelegateCall`
* - Replace _msgSender() with msg.sender
*/
contract RoninTransparentProxy is ERC1967Proxy {
/**
* @dev The proxy caller is the current admin, and can't fallback to the proxy target. Admin must call via
* `adminDelegate`.
*/
error ProxyDeniedAdminAccess();

/**
* @dev The caller is not the admin.
*/
error OnlyAdmin();

/**
* @dev
* An immutable address for the admin to avoid unnecessary SLOADs before each call
* at the expense of removing the ability to change the admin once it's set.
* This is acceptable if the admin is always a ProxyAdmin instance or similar contract
* with its own ability to transfer the permissions to another account.
*/
address private immutable _ADMIN;

/**
* @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
* backed by the implementation at `logic`, and optionally initialized with `data` as explained in
* {ERC1967Proxy-constructor}.
*/
constructor(address logic, address admin, bytes memory data) payable ERC1967Proxy(logic, data) {
_ADMIN = admin;
// Set the storage value and emit an event for ERC-1967 compatibility
ERC1967Utils.changeAdmin(_proxyAdmin());
}

/**
* @dev Calls a function from the current implementation as specified by `data`, which should be an encoded function
* call.
*
* Requirements:
* - Only the admin can call this function.
*
* Note: The proxy admin is not allowed to interact with the proxy logic through the fallback function to avoid
* triggering some unexpected logic. This is to allow the administrator to explicitly call the proxy, please consider
* reviewing the encoded data `data` and the method which is called before using this.
*
*/
function functionDelegateCall(
bytes memory data
) external payable {
if (msg.sender != _proxyAdmin()) revert OnlyAdmin();

address impl = _implementation();

assembly ("memory-safe") {
let result := delegatecall(gas(), impl, add(data, 32), mload(data), 0, 0)

returndatacopy(0, 0, returndatasize())

switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}

/**
* @dev Returns the admin of this proxy.
*/
function _proxyAdmin() internal virtual returns (address admin) {
return _ADMIN;
}

/**
* @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
*/
function _fallback() internal virtual override {
if (msg.sender == _proxyAdmin()) {
if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) revert ProxyDeniedAdminAccess();
else _dispatchUpgradeToAndCall();
} else {
super._fallback();
}
}

/**
* @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
*
* Requirements:
*
* - If `data` is empty, `msg.value` must be zero.
*/
function _dispatchUpgradeToAndCall() private {
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}
}
21 changes: 0 additions & 21 deletions src/TransparentProxyOZv4_9_5.sol

This file was deleted.

38 changes: 0 additions & 38 deletions src/TransparentProxyV2.sol

This file was deleted.

0 comments on commit 67b273f

Please sign in to comment.