Skip to content

Commit

Permalink
do not allow non-contract address as new implementations (#120)
Browse files Browse the repository at this point in the history
* do not allow non-contract address as new implementations

* linting

* lint fixes
  • Loading branch information
josojo authored Dec 11, 2023
1 parent 8caf613 commit 509f899
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 4 deletions.
59 changes: 59 additions & 0 deletions contracts/ForkingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.20;

import {ERC20PresetMinterPauser} from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
Expand Down Expand Up @@ -97,11 +98,69 @@ contract ForkingManager is IForkingManager, ForkableStructure {
);

disputeData = _disputeData;
require(
verifyNewImplementations(_newImplementations),
"Invalid new implementations"
);
proposedImplementations = _newImplementations;
// solhint-disable-next-line not-rely-on-time
executionTimeForProposal = (block.timestamp + forkPreparationTime);
}

/**
* @notice function to check that the new implementations are properly set and are actual contracts
* @param _newImplementations the addresses of the new implementations that will
* be used in the fork
* @return true if the new implementations are properly formed
*/
function verifyNewImplementations(
NewImplementations calldata _newImplementations
) internal view returns (bool) {
// address zero is placeholder for no change and hence allowed. CreateChildren library will then read out the parent address and use it
require(
_newImplementations.bridgeImplementation == address(0) ||
AddressUpgradeable.isContract(
_newImplementations.bridgeImplementation
),
"bridge not contract"
);
require(
_newImplementations.zkEVMImplementation == address(0) ||
AddressUpgradeable.isContract(
_newImplementations.zkEVMImplementation
),
"zkEVM not contract"
);
require(
_newImplementations.forkonomicTokenImplementation == address(0) ||
AddressUpgradeable.isContract(
_newImplementations.forkonomicTokenImplementation
),
"forkonomic token not contract"
);
require(
_newImplementations.forkingManagerImplementation == address(0) ||
AddressUpgradeable.isContract(
_newImplementations.forkingManagerImplementation
),
"forking manager not contract"
);

require(
_newImplementations.zkEVMImplementation == address(0) ||
AddressUpgradeable.isContract(
_newImplementations.globalExitRootImplementation
),
"global exit root not contract"
);
require(
_newImplementations.verifier == address(0) ||
AddressUpgradeable.isContract(_newImplementations.verifier),
"verifier not contract"
);
return true;
}

/**
* @dev function that executes a fork proposal
*/
Expand Down
45 changes: 44 additions & 1 deletion test/ForkingManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.20;
/* solhint-disable not-rely-on-time */

import {Test} from "forge-std/Test.sol";
import {VerifierRollupHelperMock} from "@RealityETH/zkevm-contracts/contracts/mocks/VerifierRollupHelperMock.sol";
import {ForkingManager} from "../contracts/ForkingManager.sol";
import {ForkableBridge} from "../contracts/ForkableBridge.sol";
import {ForkableZkEVM} from "../contracts/ForkableZkEVM.sol";
Expand Down Expand Up @@ -69,7 +70,7 @@ contract ForkingManagerTest is Test {
address public newForkmanagerImplementation = address(new ForkingManager());
address public newZkevmImplementation = address(new ForkableZkEVM());
address public newVerifierImplementation =
address(0x1234567890123456789012345678901234567894);
address(new VerifierRollupHelperMock());
address public newGlobalExitRootImplementation =
address(new ForkableGlobalExitRoot());
address public newForkonomicTokenImplementation =
Expand Down Expand Up @@ -246,6 +247,48 @@ contract ForkingManagerTest is Test {
assertFalse(forkmanager.canFork());
}

function testVerifyNewImplementationsRejectsNonContractBridgeImplementation()
public
{
forkonomicToken.approve(address(forkmanager), arbitrationFee);
vm.prank(address(this));
forkonomicToken.mint(address(this), arbitrationFee);
IForkingManager.NewImplementations
memory implementations = IForkingManager.NewImplementations({
bridgeImplementation: address(0x1), // non contract
zkEVMImplementation: newZkevmImplementation,
forkonomicTokenImplementation: newForkonomicTokenImplementation,
forkingManagerImplementation: newForkmanagerImplementation,
globalExitRootImplementation: newGlobalExitRootImplementation,
verifier: newVerifierImplementation,
forkID: newForkID
});

vm.expectRevert("bridge not contract");
forkmanager.initiateFork(disputeData, implementations);
}

function testVerifyNewImplementationsRejectsNonContractZkEVMImplementation()
public
{
forkonomicToken.approve(address(forkmanager), arbitrationFee);
vm.prank(address(this));
forkonomicToken.mint(address(this), arbitrationFee);
IForkingManager.NewImplementations
memory implementations = IForkingManager.NewImplementations({
bridgeImplementation: newBridgeImplementation, // non contract
zkEVMImplementation: address(0x234),
forkonomicTokenImplementation: newForkonomicTokenImplementation,
forkingManagerImplementation: newForkmanagerImplementation,
globalExitRootImplementation: newGlobalExitRootImplementation,
verifier: newVerifierImplementation,
forkID: newForkID
});

vm.expectRevert("zkEVM not contract");
forkmanager.initiateFork(disputeData, implementations);
}

function testInitiateForkChargesFees() public {
// Call the initiateFork function to create a new fork
vm.expectRevert(bytes("ERC20: insufficient allowance"));
Expand Down
4 changes: 3 additions & 1 deletion test/L1GlobalChainInfoPublisher.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {Arbitrator} from "../contracts/lib/reality-eth/Arbitrator.sol";
// TODO: Replace this with whatever zkEVM or whatever platform we're on uses
import {IAMB} from "../contracts/interfaces/IAMB.sol";

import {VerifierRollupHelperMock} from "@RealityETH/zkevm-contracts/contracts/mocks/VerifierRollupHelperMock.sol";
import {IRealityETH} from "../contracts/interfaces/IRealityETH.sol";
import {IERC20} from "../contracts/interfaces/IERC20.sol";
import {ForkableRealityETH_ERC20} from "../contracts/ForkableRealityETH_ERC20.sol";
Expand Down Expand Up @@ -93,8 +94,9 @@ contract L1GlobalChainInfoPublisherTest is Test {
address public newBridgeImplementation = address(new ForkableBridge());
address public newForkmanagerImplementation = address(new ForkingManager());
address public newZkevmImplementation = address(new ForkableZkEVM());

address public newVerifierImplementation =
address(0x1234567890123456789012345678901234567894);
address(new VerifierRollupHelperMock());
address public newGlobalExitRootImplementation =
address(new ForkableGlobalExitRoot());
address public newForkonomicTokenImplementation =
Expand Down
14 changes: 12 additions & 2 deletions test/L1GlobalForkRequester.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.20;
/* solhint-disable not-rely-on-time */

import {Test} from "forge-std/Test.sol";
import {VerifierRollupHelperMock} from "@RealityETH/zkevm-contracts/contracts/mocks/VerifierRollupHelperMock.sol";
import {ForkingManager} from "../contracts/ForkingManager.sol";
import {ForkableBridge} from "../contracts/ForkableBridge.sol";
import {ForkableZkEVM} from "../contracts/ForkableZkEVM.sol";
Expand Down Expand Up @@ -76,7 +77,7 @@ contract L1GlobalForkRequesterTest is Test {
address public newForkmanagerImplementation = address(new ForkingManager());
address public newZkevmImplementation = address(new ForkableZkEVM());
address public newVerifierImplementation =
address(0x1234567890123456789012345678901234567894);
address(new VerifierRollupHelperMock());
address public newGlobalExitRootImplementation =
address(new ForkableGlobalExitRoot());
address public newForkonomicTokenImplementation =
Expand Down Expand Up @@ -322,7 +323,16 @@ contract L1GlobalForkRequesterTest is Test {
vm.prank(address(this));
forkonomicToken.approve(address(forkmanager), fee);
// Assume the data contains the questionId and pass it directly to the forkmanager in the fork request
IForkingManager.NewImplementations memory newImplementations;
IForkingManager.NewImplementations
memory newImplementations = IForkingManager.NewImplementations(
newBridgeImplementation,
newZkevmImplementation,
newForkonomicTokenImplementation,
newForkmanagerImplementation,
newGlobalExitRootImplementation,
newVerifierImplementation,
uint64(0x7)
);
IForkingManager.DisputeData memory disputeData = IForkingManager
.DisputeData(false, address(this), requestId);
forkmanager.initiateFork(disputeData, newImplementations);
Expand Down

0 comments on commit 509f899

Please sign in to comment.