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

Making chain id manager owner less #168

Merged
merged 5 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
27 changes: 17 additions & 10 deletions contracts/ChainIdManager.sol
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;

import {Owned} from "./mixin/Owned.sol";
// The ChainIdManager contract provides a list of new usable chainIds via the getNextUsableChainId function.
// If a project uses one chainId, it can be added to the deny list and then no other project will use it.
// The contract does not come with an owner, but anyone can add chainIds to the deny list.
// It costs just gasBurnAmount to deny list a chainId.
// The burnGas function introduces this cost to use up chainIds.
// There are uint64(2**63=9.223372e+18) chainIds minus the publicly used chainIds available.
// Using all of the chainIds would cost 9.223372e+18 * gasBurnAmount = 9.223372e+24 gas = 6.1489147e+17 blocks = 237226647377 years

contract ChainIdManager is Owned {
contract ChainIdManager {
// Counter for the number of Chain IDs
uint64 public chainIdCounter = 0;
// contains a list of denied Chain IDs that should not be used as chainIds
// they are governed by a owner of the contract
// they are anyone who is willing to pay the gas to use them.
mapping(uint64 => bool) public deniedChainIds;
// Fee to use up a Chain ID
// Fee to use up a chain ID
uint256 public immutable gasBurnAmount = 1000000;

constructor(uint64 _chainIdCounter) Owned() {
constructor(uint64 _chainIdCounter) {
chainIdCounter = _chainIdCounter;
}

/**
* @dev Adds a Chain ID to the deny list, this can be done if the chainId is used by another project
* @param chainId The Chain ID to add
*/
function denyListChainId(uint64 chainId) public onlyOwner {
function denyListChainId(uint64 chainId) public {
burnGas();
deniedChainIds[chainId] = true;
}

/**
* @dev Adds multiple Chain IDs to the deny list
* @param chainIds The Chain IDs to add
*/
function denyListChainIds(uint64[] memory chainIds) public onlyOwner {
function denyListChainIds(uint64[] memory chainIds) public {
for (uint256 i = 0; i < chainIds.length; i++) {
denyListChainId(chainIds[i]);
}
Expand All @@ -39,9 +46,6 @@ contract ChainIdManager is Owned {
* @return chainId The next usable Chain ID
*/
function getNextUsableChainId() public returns (uint64 chainId) {
// The burnGas function introduces a cost to use up chainIds.
// There are uint64(2**63=9.223372e+18) chainIds minus the publicly used chainIds available.
// Using all of the chainIds would cost 9.223372e+18 * gasBurnAmount = 9.223372e+24 gas = 6.1489147e+17 blocks = 237226647377 years
burnGas();
while (deniedChainIds[chainIdCounter]) {
chainIdCounter++;
Expand All @@ -50,6 +54,9 @@ contract ChainIdManager is Owned {
chainIdCounter++;
}

/**
* @dev Burns gasBurnAmount gas to incure a cost for everyone calling this function
*/
function burnGas() public view {
uint256 counter = 0;
uint256 _lowestLimit = gasleft() - gasBurnAmount;
Expand Down
4 changes: 3 additions & 1 deletion contracts/ForkableBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ contract ForkableBridge is
bytes calldata metadata,
address destinationAddress
) external onlyParent {
require(originNetwork != networkID, "wrong Token");
if (originNetwork == networkID) {
revert InvalidOriginNetwork();
}
_issueBridgedTokens(
originNetwork,
token,
Expand Down
17 changes: 10 additions & 7 deletions contracts/ForkingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ contract ForkingManager is IForkingManager, ForkableStructure {
function initiateFork(
DisputeData memory _disputeData
) external onlyBeforeForking {
require(executionTimeForProposal == 0, "ForkingManager: fork pending");
if (executionTimeForProposal != 0) {
revert ForkingAlreadyInitiated();
}
// Charge the forking fee
IERC20(forkonomicToken).safeTransferFrom(
msg.sender,
Expand All @@ -106,12 +108,13 @@ contract ForkingManager is IForkingManager, ForkableStructure {
* @dev function that executes a fork proposal
*/
function executeFork() external onlyBeforeForking {
require(
executionTimeForProposal != 0 &&
// solhint-disable-next-line not-rely-on-time
executionTimeForProposal <= block.timestamp,
"ForkingManager: fork not ready"
);
if (
executionTimeForProposal == 0 ||
// solhint-disable-next-line not-rely-on-time
executionTimeForProposal > block.timestamp
) {
revert NotYetReadyToFork();
}

// Create the children of each contract
NewInstances memory newInstances;
Expand Down
18 changes: 7 additions & 11 deletions contracts/ForkonomicToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ contract ForkonomicToken is

/// @inheritdoc IForkonomicToken
function mint(address to, uint256 amount) external {
require(
hasRole(MINTER_ROLE, msg.sender) || msg.sender == parentContract,
"Caller is not a minter"
);
if (!hasRole(MINTER_ROLE, msg.sender) && msg.sender != parentContract) {
revert NotMinterRole();
}
_mint(to, amount);
}

Expand All @@ -59,12 +58,10 @@ contract ForkonomicToken is
bool firstChild,
bool useChildTokenAllowance
) public onlyAfterForking {
require(children[0] != address(0), "Children not created yet");
if (useChildTokenAllowance) {
require(
childTokenAllowances[msg.sender][firstChild] >= amount,
"Not enough allowance"
);
if (childTokenAllowances[msg.sender][firstChild] < amount) {
revert NotSufficientAllowance();
}
childTokenAllowances[msg.sender][firstChild] -= amount;
} else {
_burn(msg.sender, amount);
Expand All @@ -79,8 +76,7 @@ contract ForkonomicToken is
/// @dev Allows anyone to prepare the splitting of tokens
/// by burning them
/// @param amount The amount of tokens to burn
function prepareSplittingTokens(uint256 amount) public {
require(children[0] != address(0), "Children not created yet");
function prepareSplittingTokens(uint256 amount) public onlyAfterForking {
_burn(msg.sender, amount);
childTokenAllowances[msg.sender][false] += amount;
childTokenAllowances[msg.sender][true] += amount;
Expand Down
2 changes: 2 additions & 0 deletions contracts/interfaces/IForkableBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface IForkableBridge is IForkableStructure, IPolygonZkEVMBridge {
error InvalidDestinationForHardAsset();
/// @dev Error thrown when hardasset manager tries to send gas token to a child contract
error GasTokenIsNotHardAsset();
/// @dev Error thrown when trying to send bridged tokens to a child contract
error InvalidOriginNetwork();

/**
* @dev Function to initialize the contract
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IForkingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ pragma solidity ^0.8.20;
import {IForkableStructure} from "./IForkableStructure.sol";

interface IForkingManager is IForkableStructure {
/// @dev Error thrown when the forking manager is not ready to fork
error NotYetReadyToFork();
/// @dev Error thrown when the forking manager is already initiated
error ForkingAlreadyInitiated();

// Dispute contract and call to identify the dispute
// that will be used to initiate/justify the fork
struct DisputeData {
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IForkonomicToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import {IForkableStructure} from "./IForkableStructure.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

interface IForkonomicToken is IForkableStructure, IERC20Upgradeable {
/// @dev Error thrown when activity is started by a non-authorized minter
error NotMinterRole();
/// @dev Error thrown when not sufficient balance has been burn to mint new tokens at the child contracts
error NotSufficientAllowance();

/**
* @notice Allows the forkmanager to initialize the contract
* @param _forkmanager The address of the forkmanager
Expand Down
16 changes: 0 additions & 16 deletions contracts/interfaces/IOperations.sol

This file was deleted.

20 changes: 14 additions & 6 deletions contracts/lib/BridgeAssetOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

library BridgeAssetOperations {
// @dev Error thrown when non-forkable token is intended to be used, but it is not forkable
error TokenNotForkable();
// @dev Error thrown when token is not issued before
error TokenNotIssuedBefore();

/**
* @notice Function to merge tokens from children-bridge contracts
* @param token Address of the token
Expand All @@ -23,11 +28,12 @@ library BridgeAssetOperations {
address child0,
address child1
) public {
require(tokenInfo.originNetwork != 0, "Token not forkable");
require(
tokenInfo.originTokenAddress != address(0),
"Token not issued before"
);
if (tokenInfo.originNetwork == 0) {
revert TokenNotForkable();
}
if (tokenInfo.originTokenAddress == address(0)) {
revert TokenNotIssuedBefore();
}
ForkableBridge(child0).burnForkableTokens(
msg.sender,
tokenInfo.originTokenAddress,
Expand Down Expand Up @@ -57,7 +63,9 @@ library BridgeAssetOperations {
PolygonZkEVMBridge.TokenInformation memory tokenInfo,
address child
) public {
require(tokenInfo.originNetwork != 0, "Token not forkable");
if (tokenInfo.originNetwork == 0) {
revert TokenNotForkable();
}
bytes memory metadata = abi.encode(
IERC20Metadata(token).name(),
IERC20Metadata(token).symbol(),
Expand Down
2 changes: 1 addition & 1 deletion contracts/lib/reality-eth/Arbitrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity ^0.8.20;
import "./../../interfaces/IArbitrator.sol";
import "./../../interfaces/IRealityETH.sol";
import "./../../interfaces/IERC20.sol";
import "./../../mixin/Owned.sol";
import "./Owned.sol";

contract Arbitrator is Owned, IArbitrator {
IRealityETH public realitio;
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions contracts/mixin/InitializeChain.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;

// Currently, this contract is not used. Ed came up with its own isChainUpToDate() modifier.
// Maybe we have to delete it.

/** This contract can be inherited form any other contrac that needs to be aware of Forks.
This contract uses the fact that after a fork the chainId changes and thereby detects forks*/

Expand Down
21 changes: 16 additions & 5 deletions test/ChainIdManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ contract ChainIdManagerTest is Test {

function setUp() public {
chainIdManager = new ChainIdManager(initialChainId);
chainIdManager.transferOwnership(owner);
}

function testAddChainId() public {
vm.prank(owner);
uint64 newChainId = 10;
chainIdManager.denyListChainId(newChainId);

Expand All @@ -27,10 +25,23 @@ contract ChainIdManagerTest is Test {
"Chain ID not correctly added"
);

// Attempt to add a ChainId by a non-owner, expect a revert
vm.prank(nonOwner);
vm.expectRevert(bytes("Caller is not the owner")); // Expect a revert with a specific revert message
// Attempt to add a ChainId by a non-owner, expect a consumption of gas
uint256 currentGas = gasleft();
chainIdManager.denyListChainId(2);
uint256 finalGas = gasleft();
assert(currentGas - finalGas >= chainIdManager.gasBurnAmount());

uint256 currentGas2 = gasleft();
uint64[] memory newChainIds = new uint64[](6);
newChainIds[0] = 3;
newChainIds[1] = 4;
newChainIds[2] = 5;
newChainIds[3] = 6;
newChainIds[4] = 7;
newChainIds[5] = 8;
chainIdManager.denyListChainIds(newChainIds);
uint256 finalGas2 = gasleft();
assert(currentGas2 - finalGas2 >= chainIdManager.gasBurnAmount() * 6);
}

function testAddChainIds() public {
Expand Down
2 changes: 1 addition & 1 deletion test/ForkableBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ contract ForkableBridgeTest is Test {
);

vm.prank(forkableBridge.parentContract());
vm.expectRevert(bytes("wrong Token"));
vm.expectRevert(IForkableBridge.InvalidOriginNetwork.selector);
forkableBridge.mintForkableToken(
address(token),
networkID, // <-- this line is changed
Expand Down
6 changes: 3 additions & 3 deletions test/ForkingManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ contract ForkingManagerTest is Test {

function testExecuteForkRespectsTime() public {
// reverts on empty proposal list
vm.expectRevert("ForkingManager: fork not ready");
vm.expectRevert(IForkingManager.NotYetReadyToFork.selector);
forkmanager.executeFork();

// Mint and approve the arbitration fee for the test contract
Expand All @@ -621,7 +621,7 @@ contract ForkingManagerTest is Test {
vm.warp(testTimestamp);
forkmanager.initiateFork(disputeData);

vm.expectRevert("ForkingManager: fork not ready");
vm.expectRevert(IForkingManager.NotYetReadyToFork.selector);
forkmanager.executeFork();
vm.warp(testTimestamp + forkmanager.forkPreparationTime() + 1);
forkmanager.executeFork();
Expand Down Expand Up @@ -653,7 +653,7 @@ contract ForkingManagerTest is Test {
disputeData.disputeContent = "0x1";
forkmanager.initiateFork(disputeData);
disputeData.disputeContent = "0x2";
vm.expectRevert(bytes("ForkingManager: fork pending"));
vm.expectRevert(IForkingManager.ForkingAlreadyInitiated.selector);
forkmanager.initiateFork(disputeData);
}

Expand Down
2 changes: 1 addition & 1 deletion test/ForkonomicToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ contract ForkonomicTokenTest is Test {

assertEq(forkonomicToken.balanceOf(address(this)), mintAmount);

vm.expectRevert(bytes("Caller is not a minter"));
vm.expectRevert(IForkonomicToken.NotMinterRole.selector);
forkonomicToken.mint(address(this), mintAmount);
}

Expand Down
Loading