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

Execute forks separately #96

Merged
merged 8 commits into from
Nov 29, 2023
Merged
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
42 changes: 23 additions & 19 deletions contracts/ForkableBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ contract ForkableBridge is
address to
) external onlyAfterForking {
require(_hardAssetManager == msg.sender, "Not authorized");
require(to == children[0] || to == children[1], "Invalid to address");
require(to == children[0] || to == children[1], "Invalid to");
edmundedgar marked this conversation as resolved.
Show resolved Hide resolved
IERC20(token).transfer(to, amount);
}

Expand All @@ -79,9 +79,8 @@ contract ForkableBridge is
if (parentContract != address(0)) {
// Also check the parent contract for claims if it is set
return ForkableBridge(parentContract).isClaimed(index);
} else {
return false;
}
return false;
}

/**
Expand Down Expand Up @@ -116,7 +115,7 @@ contract ForkableBridge is
bytes calldata metadata,
address destinationAddress
) external onlyParent {
require(originNetwork != networkID, "Token is from this network");
require(originNetwork != networkID, "wrong Token");
_issueBridgedTokens(
originNetwork,
token,
Expand All @@ -127,16 +126,18 @@ contract ForkableBridge is
}

// @inheritdoc IForkableBridge
function splitTokenIntoChildTokens(
function splitTokenIntoChildToken(
address token,
uint256 amount
) external onlyAfterForking {
BridgeAssetOperations.splitTokenIntoChildTokens(
uint256 amount,
bool mintSecondChildAsWell
) public onlyAfterForking {
BridgeAssetOperations.splitTokenIntoChildToken(
token,
amount,
wrappedTokenToTokenInfo[token],
children[0],
children[1]
// If the second token should not be minted - to safe gas or since its broken - we pass address(0)
mintSecondChildAsWell ? children[1] : address(0),
wrappedTokenToTokenInfo[token]
);
}

Expand Down Expand Up @@ -171,17 +172,20 @@ contract ForkableBridge is
* @dev Allows the forkmanager to take out the forkonomic tokens
* and send them to the children-bridge contracts
* Notice that forkonomic tokens are special, as they their main contract
* is on L1, but they are still forkable tokens as all the tokens from L2.
* is on L1, but they are still forkable tokens as all the tokens from
* @param useFirstChild boolean indicating for which child the operation should be run
*/
function sendForkonomicTokensToChildren()
public
onlyForkManger
onlyAfterForking
{
BridgeAssetOperations.sendForkonomicTokensToChildren(
function sendForkonomicTokensToChild(
uint256 amount,
bool useFirstChild,
bool useChildTokenAllowance
) public onlyForkManger onlyAfterForking {
BridgeAssetOperations.sendForkonomicTokensToChild(
gasTokenAddress,
children[0],
children[1]
amount,
useFirstChild ? children[0] : children[1],
useFirstChild,
useChildTokenAllowance
);
}

Expand Down
173 changes: 114 additions & 59 deletions contracts/ForkingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,38 +102,32 @@ contract ForkingManager is IForkingManager, ForkableStructure {
/**
* @dev function that executes a fork proposal
*/
function executeFork() external onlyBeforeForking {
function executeFork1() external onlyBeforeForking {
edmundedgar marked this conversation as resolved.
Show resolved Hide resolved
require(
executionTimeForProposal != 0 &&
// solhint-disable-next-line not-rely-on-time
executionTimeForProposal <= block.timestamp,
"ForkingManager: fork not ready"
);

NewImplementations memory newImplementations = proposedImplementations;

// Create the children of each contract
NewInstances memory newInstances;
(
newInstances.forkingManager.one,
newInstances.forkingManager.two
) = _createChildren(newImplementations.forkingManagerImplementation);
(newInstances.bridge.one, newInstances.bridge.two) = IForkableBridge(
bridge
).createChildren(newImplementations.bridgeImplementation);
(newInstances.zkEVM.one, newInstances.zkEVM.two) = IForkableZkEVM(zkEVM)
.createChildren(newImplementations.zkEVMImplementation);
(
newInstances.forkonomicToken.one,
newInstances.forkonomicToken.two
) = IForkonomicToken(forkonomicToken).createChildren(
newImplementations.forkonomicTokenImplementation
(newInstances.forkingManager.one, ) = _createChildren(
newImplementations.forkingManagerImplementation
);
(
newInstances.globalExitRoot.one,
newInstances.globalExitRoot.two
) = IForkableGlobalExitRoot(globalExitRoot).createChildren(
newImplementations.globalExitRootImplementation
(newInstances.bridge.one, ) = IForkableBridge(bridge).createChildren(
newImplementations.bridgeImplementation
);
(newInstances.zkEVM.one, ) = IForkableZkEVM(zkEVM).createChildren(
newImplementations.zkEVMImplementation
);
(newInstances.forkonomicToken.one, ) = IForkonomicToken(forkonomicToken)
.createChildren(newImplementations.forkonomicTokenImplementation);
(newInstances.globalExitRoot.one, ) = IForkableGlobalExitRoot(
globalExitRoot
).createChildren(newImplementations.globalExitRootImplementation);

// Initialize the zkEVM contracts
IPolygonZkEVM.InitializePackedParameters
Expand Down Expand Up @@ -175,11 +169,106 @@ contract ForkingManager is IForkingManager, ForkableStructure {
IForkableZkEVM(zkEVM).rollupVerifier(),
IPolygonZkEVMBridge(newInstances.bridge.one)
);
initializePackedParameters.chainID = ChainIdManager(chainIdManager)
.getNextUsableChainId();
initializePackedParameters.forkID = newImplementations.forkID > 0
? newImplementations.forkID
: IPolygonZkEVM(zkEVM).forkID();
}

// Initialize the tokens
IForkonomicToken(newInstances.forkonomicToken.one).initialize(
newInstances.forkingManager.one,
forkonomicToken,
address(this),
string.concat(IERC20Metadata(forkonomicToken).name(), "0"),
IERC20Metadata(forkonomicToken).symbol()
);

bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
memory depositBranch = IForkableBridge(bridge).getBranch();

//Initialize the bridge contracts
IForkableBridge(newInstances.bridge.one).initialize(
newInstances.forkingManager.one,
bridge,
0, // network identifiers will always be 0 on mainnet and 1 on L2
IBasePolygonZkEVMGlobalExitRoot(newInstances.globalExitRoot.one),
address(newInstances.zkEVM.one),
address(newInstances.forkonomicToken.one),
false,
IForkableBridge(bridge).getHardAssetManager(),
IForkableBridge(bridge).getLastUpdatedDepositCount(),
depositBranch
);

//Initialize the forking manager contracts
IForkingManager(newInstances.forkingManager.one).initialize(
newInstances.zkEVM.one,
newInstances.bridge.one,
newInstances.forkonomicToken.one,
address(this),
newInstances.globalExitRoot.one,
arbitrationFee,
chainIdManager
);

//Initialize the global exit root contracts
IForkableGlobalExitRoot(newInstances.globalExitRoot.one).initialize(
newInstances.forkingManager.one,
globalExitRoot,
newInstances.zkEVM.one,
newInstances.bridge.one
);
}

/**
* @dev function that creates the second fork for the fork proposal
*/
function executeFork2() external onlyBeforeCreatingChild2 {
require(
executionTimeForProposal != 0 &&
// solhint-disable-next-line not-rely-on-time
executionTimeForProposal <= block.timestamp,
"ForkingManager: fork not ready"
);
NewImplementations memory newImplementations = proposedImplementations;

// Create the children of each contract
NewInstances memory newInstances;
(, newInstances.forkingManager.two) = getChildren();
(, newInstances.bridge.two) = IForkableBridge(bridge).getChildren();
(, newInstances.zkEVM.two) = IForkableZkEVM(zkEVM).getChildren();
(, newInstances.forkonomicToken.two) = IForkonomicToken(forkonomicToken)
.getChildren();
(, newInstances.globalExitRoot.two) = IForkableGlobalExitRoot(
globalExitRoot
).getChildren();

// Initialize the zkEVM contracts
IPolygonZkEVM.InitializePackedParameters
memory initializePackedParameters;

{
// retrieve some information from the zkEVM contract
bytes32 genesisRoot = IPolygonZkEVM(zkEVM).batchNumToStateRoot(
IPolygonZkEVM(zkEVM).lastVerifiedBatch()
);
// the following variables could be used to save gas, but it requires via-ir in the compiler settings
string memory trustedSequencerURL = IPolygonZkEVM(zkEVM)
.trustedSequencerURL();
string memory networkName = IPolygonZkEVM(zkEVM).networkName();
// string memory version = "0.1.0"; // Todo: get version from zkEVM, currently only emitted as event
initializePackedParameters = IPolygonZkEVM
.InitializePackedParameters({
admin: IPolygonZkEVM(zkEVM).admin(),
trustedSequencer: IPolygonZkEVM(zkEVM).trustedSequencer(),
pendingStateTimeout: IPolygonZkEVM(zkEVM)
.pendingStateTimeout(),
trustedAggregator: IPolygonZkEVM(zkEVM).trustedAggregator(),
trustedAggregatorTimeout: IPolygonZkEVM(zkEVM)
.trustedAggregatorTimeout(),
chainID: ChainIdManager(chainIdManager)
.getNextUsableChainId(),
forkID: newImplementations.forkID > 0
? newImplementations.forkID
: IPolygonZkEVM(zkEVM).forkID()
});
IForkableZkEVM(newInstances.zkEVM.two).initialize(
newInstances.forkingManager.two,
zkEVM,
Expand All @@ -196,13 +285,6 @@ contract ForkingManager is IForkingManager, ForkableStructure {
}

// Initialize the tokens
IForkonomicToken(newInstances.forkonomicToken.one).initialize(
newInstances.forkingManager.one,
forkonomicToken,
address(this),
string.concat(IERC20Metadata(forkonomicToken).name(), "0"),
IERC20Metadata(forkonomicToken).symbol()
);
IForkonomicToken(newInstances.forkonomicToken.two).initialize(
newInstances.forkingManager.two,
forkonomicToken,
Expand All @@ -215,18 +297,6 @@ contract ForkingManager is IForkingManager, ForkableStructure {
memory depositBranch = IForkableBridge(bridge).getBranch();

//Initialize the bridge contracts
IForkableBridge(newInstances.bridge.one).initialize(
newInstances.forkingManager.one,
bridge,
0, // network identifiers will always be 0 on mainnet and 1 on L2
IBasePolygonZkEVMGlobalExitRoot(newInstances.globalExitRoot.one),
address(newInstances.zkEVM.one),
address(newInstances.forkonomicToken.one),
false,
IForkableBridge(bridge).getHardAssetManager(),
IForkableBridge(bridge).getLastUpdatedDepositCount(),
depositBranch
);
IForkableBridge(newInstances.bridge.two).initialize(
newInstances.forkingManager.two,
bridge,
Expand All @@ -241,15 +311,6 @@ contract ForkingManager is IForkingManager, ForkableStructure {
);

//Initialize the forking manager contracts
IForkingManager(newInstances.forkingManager.one).initialize(
newInstances.zkEVM.one,
newInstances.bridge.one,
newInstances.forkonomicToken.one,
address(this),
newInstances.globalExitRoot.one,
arbitrationFee,
chainIdManager
);
IForkingManager(newInstances.forkingManager.two).initialize(
newInstances.zkEVM.two,
newInstances.bridge.two,
Expand All @@ -261,12 +322,6 @@ contract ForkingManager is IForkingManager, ForkableStructure {
);

//Initialize the global exit root contracts
IForkableGlobalExitRoot(newInstances.globalExitRoot.one).initialize(
newInstances.forkingManager.one,
globalExitRoot,
newInstances.zkEVM.one,
newInstances.bridge.one
);
IForkableGlobalExitRoot(newInstances.globalExitRoot.two).initialize(
newInstances.forkingManager.two,
globalExitRoot,
Expand Down
44 changes: 40 additions & 4 deletions contracts/ForkonomicToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ contract ForkonomicToken is
/// @dev The role that allows minting new tokens
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

/// @dev Mapping that stores burned amounts
/// address The address of the token owner
/// bool indicating whether the first or second child was burnt
/// uint256 The amount of burned tokens
mapping(address => mapping(bool => uint256)) public childTokenAllowances;

/// @inheritdoc IForkonomicToken
function initialize(
address _forkmanager,
Expand Down Expand Up @@ -46,12 +52,42 @@ contract ForkonomicToken is
return _createChildren(implementation);
}

function splitTokenAndMintOneChild(
uint256 amount,
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"
);
childTokenAllowances[msg.sender][firstChild] -= amount;
} else {
_burn(msg.sender, amount);
childTokenAllowances[msg.sender][!firstChild] += amount;
}
IForkonomicToken(firstChild ? children[0] : children[1]).mint(
msg.sender,
amount
);
}

/// @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");
_burn(msg.sender, amount);
childTokenAllowances[msg.sender][false] += amount;
childTokenAllowances[msg.sender][true] += amount;
}

/// @dev Allows anyone to split the tokens from the parent contract into the tokens of the children
/// @param amount The amount of tokens to split
function splitTokensIntoChildTokens(uint256 amount) external {
require(children[0] != address(0), "Children not created yet");
_burn(msg.sender, amount);
IForkonomicToken(children[0]).mint(msg.sender, amount);
IForkonomicToken(children[1]).mint(msg.sender, amount);
splitTokenAndMintOneChild(amount, true, false);
splitTokenAndMintOneChild(amount, false, true);
}
}
9 changes: 7 additions & 2 deletions contracts/interfaces/IForkableBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pragma solidity ^0.8.20;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IPolygonZkEVMBridge} from "@RealityETH/zkevm-contracts/contracts/interfaces/IPolygonZkEVMBridge.sol";
import {IBasePolygonZkEVMGlobalExitRoot} from "@RealityETH/zkevm-contracts/contracts/interfaces/IBasePolygonZkEVMGlobalExitRoot.sol";
import {IForkableStructure} from "./IForkableStructure.sol";

interface IForkableBridge is IPolygonZkEVMBridge {
interface IForkableBridge is IForkableStructure, IPolygonZkEVMBridge {
/**
* @dev Function to initialize the contract
* @param _forkmanager: address of the forkmanager contract
Expand Down Expand Up @@ -49,7 +50,11 @@ interface IForkableBridge is IPolygonZkEVMBridge {
* @param token token that should be split
* @param amount amount of tokens to be split
*/
function splitTokenIntoChildTokens(address token, uint256 amount) external;
function splitTokenIntoChildToken(
address token,
uint256 amount,
bool mintSecondChild
) external;

/**
* @dev Function to mint the forkable token by the parent contract
Expand Down
Loading
Loading