Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rework): implement fix-bug #163

Open
wants to merge 4 commits into
base: feature/rework
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ name: test
on:
push:
branches:
- 'feature/*'
- 'features/*'
- 'implement-feature/**'
- 'implement-feature/**/**'
- "feature/*"
- "features/*"
- "implement-feature/**"
- "implement-feature/**/**"
pull_request:
branches:
- mainnet
- testnet
- 'feature/*'
- 'features/*'
- "feature/*"
- "features/*"

env:
FOUNDRY_PROFILE: ci
Expand All @@ -30,9 +30,7 @@ jobs:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-2b1f8d6dd90f9790faf0528e05e60e573a7569ce
uses: foundry-rs/foundry-toolchain@v1

- name: Install soldeer
run: forge soldeer install
Expand Down
18 changes: 11 additions & 7 deletions generate-artifact.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,18 @@ if [[ -z "$name" || -z "$args" || -z "$value" || -z "$nonce" || -z "$deployer" |
exit 1
fi

source_name=$(basename $absolute_path)
# Remove .json or .sol extension
source_name=${source_name%.*}

# Generate the artifact
abi=$(forge inspect $name abi)
devdoc=$(forge inspect $name devdoc)
userdoc=$(forge inspect $name userdoc)
metadata=$(forge inspect $name metadata)
storage_layout=$(forge inspect $name storageLayout)
bytecode=$(forge inspect $name bytecode)
deployed_bytecode=$(forge inspect $name deployedBytecode)
abi=$(forge inspect $source_name abi)
devdoc=$(forge inspect $source_name devdoc)
userdoc=$(forge inspect $source_name userdoc)
metadata=$(forge inspect $source_name metadata)
storage_layout=$(forge inspect $source_name storageLayout)
bytecode=$(forge inspect $source_name bytecode)
deployed_bytecode=$(forge inspect $source_name deployedBytecode)

# Create the JSON object
json_content=$(
Expand Down
2 changes: 1 addition & 1 deletion run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ if [[ ! $extra_argument == *"sender"* ]] && [[ ! $extra_argument == *"trezor"* ]
if [[ $(eval "echo \$$account_label") == *"op://"* ]]; then
echo "\033[32mFound 'op://' in ${account_label}\033[0m"
op_command="op run --env-file="./.env" --"
elif [[ $(eval "echo \$$account_label") == *""* ]]; then
elif [[ -z $(eval "echo \$$account_label") ]]; then
echo "\033[33mWARNING: Not found private key in ${account_label}\033[0m"
fi
else
Expand Down
16 changes: 16 additions & 0 deletions script/BaseMigration.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,17 @@ abstract contract BaseMigration is ScriptExtended {
) internal virtual { }

function _beforeRunningScript() internal virtual override {
vm.pauseTracing();
vm.recordLogs();
vm.startStateDiffRecording();
vm.resumeTracing();
}

function _afterRunningScript() internal virtual override {
vm.pauseTracing();
Vm.Log[] memory recordedLogs = vm.getRecordedLogs();
Vm.AccountAccess[] memory stateDiffs = vm.stopAndReturnStateDiff();
vm.resumeTracing();

LibInitializeGuard.validate({ logs: recordedLogs, stateDiffs: stateDiffs });
}
Expand All @@ -77,6 +81,18 @@ abstract contract BaseMigration is ScriptExtended {
vme.logSenderInfo();
}

function switchBack(TNetwork prvNetwork, uint256 prvForkId) public virtual override {
super.switchBack(prvNetwork, prvForkId);
// Should rebuild the shared arguments since different chain may have different shared arguments
_storeRawSharedArguments();
// Should rebuild runtime config since different chain may have different runtime config
vme.buildRuntimeConfig();
// Should rebuild the contract data since different chain may have different contract data
vme.setUpDefaultContracts();
// Log Sender Info of current network
vme.logSenderInfo();
}

function loadContractOrDeploy(
TContract contractType
) public virtual returns (address payable contractAddr) {
Expand Down
3 changes: 0 additions & 3 deletions script/libraries/LibArtifact.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ 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 { JSONParserLib } from "../../dependencies/solady-0.0.228/src/utils/JSONParserLib.sol";
import { LibString } from "../../dependencies/solady-0.0.228/src/utils/LibString.sol";
import { IGeneralConfig } from "../interfaces/IGeneralConfig.sol";
import { IRuntimeConfig } from "../interfaces/configs/IRuntimeConfig.sol";
Expand All @@ -32,8 +31,6 @@ library LibArtifact {
using stdJson for string;
using LibString for string;
using LibString for address;
using JSONParserLib for string;
using JSONParserLib for JSONParserLib.Item;

Vm private constant vm = Vm(LibSharedAddress.VM);
IGeneralConfig private constant vme = IGeneralConfig(LibSharedAddress.VME);
Expand Down
2 changes: 1 addition & 1 deletion script/libraries/LibDeploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ library LibDeploy {
DeployInfo memory proxyInfo;
proxyInfo.callValue = callValue;
proxyInfo.by = implInfo.by;
proxyInfo.contractName = "TransparentProxyOZv4_9_5";
proxyInfo.contractName = "RoninTransparentProxy";
proxyInfo.absolutePath = string.concat(proxyInfo.contractName, ".sol:", proxyInfo.contractName);
proxyInfo.artifactName = string.concat(vm.replace(implInfo.artifactName, "Logic", ""), "Proxy");
proxyInfo.constructorArgs = abi.encode(impl, proxyAdmin, callData);
Expand Down
3 changes: 3 additions & 0 deletions script/libraries/LibInitializeGuard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ library LibInitializeGuard {
* @param stateDiffs The state diffs of the transactions.
*/
function validate(Vm.Log[] memory logs, Vm.AccountAccess[] memory stateDiffs) internal {
vm.pauseGasMetering();
Cache storage $ = _getCacheStorage();

_recordUpgradesAndInitializations({ $cache: $, logs: logs });
Expand Down Expand Up @@ -116,6 +117,7 @@ library LibInitializeGuard {

_validateLogicsVersion({ $cache: $ });
_validateProxiesVersion({ $cache: $ });
vm.resumeTracing();
}

/**
Expand Down Expand Up @@ -340,6 +342,7 @@ library LibInitializeGuard {
string memory path
) internal pure returns (string memory contractName) {
uint256 length = bytes(path).length;
// Remove ".sol"
contractName = path;
if (path.endsWith(".sol")) contractName = path.slice(0, length - 4);
string[] memory parts = contractName.split(":");
Expand Down
118 changes: 104 additions & 14 deletions src/RoninTransparentProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { ERC1967Utils } from "../dependencies/openzeppelin-5.0.2/contracts/proxy
import { ITransparentUpgradeableProxy } from
"../dependencies/openzeppelin-5.0.2/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import { IRoninTransparentProxy } from "./interfaces/IRoninTransparentProxy.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
* - Preserve legacy function (`upgradeTo`, `admin`, `implementation`, `changeAdmin`) for legacy `ProxyAdmin`
*/
contract RoninTransparentProxy is ERC1967Proxy {
/**
Expand All @@ -25,24 +28,18 @@ contract RoninTransparentProxy is ERC1967Proxy {
*/
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;
receive() external payable {
_fallback();
}

/**
* @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());
ERC1967Utils.changeAdmin(admin);
}

/**
Expand Down Expand Up @@ -79,30 +76,123 @@ contract RoninTransparentProxy is ERC1967Proxy {
* @dev Returns the admin of this proxy.
*/
function _proxyAdmin() internal virtual returns (address admin) {
return _ADMIN;
return ERC1967Utils.getAdmin();
}

/**
* @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();
bytes memory ret;

if (msg.sig == IRoninTransparentProxy.changeAdmin.selector) {
// Change the admin of the proxy
ret = _dispatchChangeAdmin();
} else if (msg.sig == ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
// Upgrade the implementation of the proxy and call a function
ret = _dispatchUpgradeToAndCall();
} else if (msg.sig == IRoninTransparentProxy.upgradeTo.selector) {
// Upgrade the implementation of the proxy
ret = _dispatchUpgradeTo();
} else if (msg.sig == IRoninTransparentProxy.admin.selector) {
// Get the admin of the proxy
ret = _dispatchAdmin();
} else if (msg.sig == IRoninTransparentProxy.implementation.selector) {
// Get the implementation of the proxy
ret = _dispatchImplementation();
} else {
revert ProxyDeniedAdminAccess();
}

assembly ("memory-safe") {
return(add(ret, 0x20), mload(ret))
}
} else {
super._fallback();
}
}

/**
* @dev Returns the current implementation.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function _dispatchImplementation() private returns (bytes memory) {
_requireZeroValue();

address implementation = _implementation();

return abi.encode(implementation);
}

/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function _dispatchAdmin() private returns (bytes memory) {
_requireZeroValue();

address admin = ERC1967Utils.getAdmin();

return abi.encode(admin);
}

/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _dispatchChangeAdmin() private returns (bytes memory ret) {
_requireZeroValue();

(address newAdmin) = abi.decode(msg.data[4:], (address));

ERC1967Utils.changeAdmin(newAdmin);

return "";
}

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

ERC1967Utils.upgradeToAndCall(newImplementation, data);

return "";
}

/**
* @dev Supports legacy upgradeTo without additional data.
*
* Requirements:
* - `msg.value` must be zero.
*/
function _dispatchUpgradeTo() private returns (bytes memory ret) {
(address newImplementation) = abi.decode(msg.data[4:], (address));

// Already checks for zero value
ERC1967Utils.upgradeToAndCall(newImplementation, "");

return "";
}

/**
* @dev To keep this contract fully transparent, all functions for `admin` must be payable. This helper is here to
* emulate some proxy functions being non-payable while still allowing value to pass through.
*/
function _requireZeroValue() private {
if (msg.value != 0) revert ERC1967Utils.ERC1967NonPayable();
}
}
12 changes: 12 additions & 0 deletions src/interfaces/IRoninTransparentProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IRoninTransparentProxy {
function changeAdmin(address newAdmin) external;

function upgradeTo(address newImplementation) external;

function implementation() external view returns (address);

function admin() external view returns (address);
}
Loading