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

Add PolygonZkEvm contracts #112

Open
wants to merge 2 commits into
base: v1
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
11 changes: 11 additions & 0 deletions config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export const CHAIN_IDS: any = {
},
SCROLL: {
SCROLL_TESTNET: BigNumber.from('534353')
},
POLYGONZKEVM: {
POLYGONZKEVM_TESTNET: BigNumber.from('1442')
}
}

Expand Down Expand Up @@ -85,6 +88,9 @@ export const CHAIN_IDS_TO_ACTIVATE: any = {
},
SCROLL: {
SCROLL_TESTNET: BigNumber.from('534353')
},
POLYGONZKEVM: {
POLYGONZKEVM_TESTNET: BigNumber.from('1442')
}
}
}
Expand Down Expand Up @@ -288,6 +294,10 @@ export const L2_CANONICAL_TOKEN_ADDRESSES: any = {
},
SCROLL_TESTNET: {
ETH: '0x5300000000000000000000000000000000000004' // Canonical deployment
},
POLYGONZKEVM_TESTNET: {
// TODO: find address
ETH: '0x0000000000000000000000000000000000000000' // Canonical deployment
}
}

Expand All @@ -300,5 +310,6 @@ export const HOP_DAO_ADDRESS = '0xeeA8422a08258e73c139Fc32a25e10410c14bd7a'
export const CONSENSYS_ZK_EVM_MESSAGE_FEE = '10000000000000000'
export const ZKSYNC_MESSAGE_FEE = 'TODO' // TODO: zksync
export const SCROLL_ZK_EVM_MESSAGE_FEE = '10000000000000000' // TODO
export const POLYGONZKEVM_MESSAGE_FEE = '0'

export const DefaultChallengePeriod: string = '86400'
16 changes: 16 additions & 0 deletions config/networks/goerli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,21 @@ export const networkData: NetworkData = {
...DEFAULT_NETWORK_DATA.ETH
}
}
},
polygonzkevm: {
l2NetworkName: 'polygonzkevm',
l1ChainId,
l2ChainId: CHAIN_IDS.POLYGONZKEVM.POLYGONZKEVM_TESTNET.toString(),
l1MessengerAddress: '0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7',
l2TokenBridgeAddress: '0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7',
l2MessengerAddress: '0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7',
tokens: {
ETH: {
l1CanonicalTokenAddress: L1_CANONICAL_TOKEN_ADDRESSES.GOERLI.ETH,
l2CanonicalTokenAddress:
L2_CANONICAL_TOKEN_ADDRESSES.POLYGONZKEVM_TESTNET.ETH,
...DEFAULT_NETWORK_DATA.ETH
}
}
}
}
24 changes: 17 additions & 7 deletions config/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ export const getMessengerWrapperDefaults = (
const gasLimit: number = 1000000
const ambAddress: string = getXDaiAmbAddresses(l1ChainId)

data.push(
...defaults,
gasLimit,
ambAddress
)
data.push(...defaults, gasLimit, ambAddress)
} else if (isChainIdPolygon(l2ChainId)) {
const checkpointManager: string = getPolygonCheckpointManagerAddress(
l1ChainId
Expand All @@ -73,6 +69,8 @@ export const getMessengerWrapperDefaults = (
data.push(...defaults)
} else if (isChainIdScroll(l2ChainId)) {
data.push(...defaults)
} else if (isChainIdPolygonZkEvm(l2ChainId)) {
data.push(...defaults)
}

return data
Expand Down Expand Up @@ -109,6 +107,8 @@ export const getL2BridgeDefaults = (
// no additional data
} else if (isChainIdScroll(chainId)) {
// no additional data
} else if (isChainIdPolygonZkEvm(chainId)) {
// no additional data
}

defaults.push(
Expand Down Expand Up @@ -208,6 +208,14 @@ export const isChainIdScroll = (chainId: BigNumber): boolean => {
return false
}

export const isChainIdPolygonZkEvm = (chainId: BigNumber): boolean => {
if (chainId.eq(CHAIN_IDS.POLYGONZKEVM.POLYGONZKEVM_TESTNET)) {
return true
}

return false
}

export const isChainIdMainnet = (chainId: BigNumber): boolean => {
if (chainId.eq(CHAIN_IDS.ETHEREUM.MAINNET)) {
return true
Expand Down Expand Up @@ -241,7 +249,8 @@ export const isChainIdTestnet = (chainId: BigNumber): boolean => {
chainId.eq(CHAIN_IDS.CONSENSYS.CONSENSYS_TESTNET) ||
chainId.eq(CHAIN_IDS.ZKSYNC.ZKSYNC_TESTNET) ||
chainId.eq(CHAIN_IDS.SCROLL.SCROLL_TESTNET) ||
chainId.eq(CHAIN_IDS.BASE.BASE_TESTNET)
chainId.eq(CHAIN_IDS.BASE.BASE_TESTNET) ||
chainId.eq(CHAIN_IDS.POLYGONZKEVM.POLYGONZKEVM_TESTNET)
) {
return true
}
Expand Down Expand Up @@ -329,7 +338,8 @@ export const getTxOverridesPerChain = (l2ChainId: BigNumber): Overrides => {
isChainIdConsensys(l2ChainId) ||
isChainIdZkSync(l2ChainId) ||
isChainIdBase(l2ChainId) ||
isChainIdScroll(l2ChainId)
isChainIdScroll(l2ChainId) ||
isChainIdPolygonZkEvm(l2ChainId)
) {
return {}
} else if (isChainIdXDai(l2ChainId)) {
Expand Down
53 changes: 53 additions & 0 deletions contracts/bridges/L2_PolygonZkEvmBridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "../interfaces/polygonzkevm/messengers/I_L2_PolygonZkEvmMessengerProxy.sol";
import "./L2_Bridge.sol";

/**
* @dev A MessengerWrapper for the Polygon zkEVM - https://polygon.technology/polygon-zkevm
*/

contract L2_PolygonZkEvmBridge is L2_Bridge {
I_L2_PolygonZkEvmMessengerProxy public messengerProxy;

constructor (
I_L2_PolygonZkEvmMessengerProxy _messengerProxy,
address l1Governance,
HopBridgeToken hToken,
address l1BridgeAddress,
uint256[] memory activeChainIds,
address[] memory bonders
)
public
L2_Bridge(
l1Governance,
hToken,
l1BridgeAddress,
activeChainIds,
bonders
)
{
messengerProxy = _messengerProxy;
}

function _sendCrossDomainMessage(bytes memory message) internal override {
messengerProxy.sendCrossDomainMessage(message);
}

function _verifySender(address expectedSender) internal override {
require(msg.sender == address(messengerProxy), "L2_PLGNZK_BRG: Caller is not the expected sender");
// Verify that cross-domain sender is expectedSender
require(messengerProxy.xDomainMessageSender() == expectedSender, "L2_PLGNZK_BRG: Invalid cross-domain sender");
}

/**
* @dev Allows the L1 Bridge to set the messengerProxy proxy
* @param _messengerProxy The new messengerProxy address
*/
function setMessengerProxy(I_L2_PolygonZkEvmMessengerProxy _messengerProxy) external onlyGovernance {
messengerProxy = _messengerProxy;
}
}
80 changes: 80 additions & 0 deletions contracts/bridges/L2_PolygonZkEvmMessengerProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
// @unsupported: ovm

pragma solidity 0.8.9;
pragma experimental ABIEncoderV2;

import "../polygon/ReentrancyGuard.sol";
import "../interfaces/polygonzkevm/messengers/IL2PolygonZkEvmMessenger.sol";
import "../interfaces/polygonzkevm/bridges/IBridgeMessageReceiver.sol";

contract L2Bridge {
function commitTransfers(uint256 destinationChainId) external {}
}

contract L2_PolygonZkEvmMessengerProxy is IBridgeMessageReceiver, ReentrancyGuard {
address public l2Bridge;
address public l1Bridge;
address public xDomainMessageSender;
address public polygonZkEvmMessenger;
bool private canCommit = false;

address constant public DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;

modifier onlyL2Bridge {
require(msg.sender == l2Bridge, "L2_PLGNZK_MSG: Sender must be the L2 Bridge");
_;
}

modifier validateSender(address sender) {
require(sender == msg.sender, "L2_PLGNZK_MSG: Invalid sender");
_;
}

constructor(address _l1Bridge, address _polygonZkEvmMessenger) public {
l1Bridge = _l1Bridge;
polygonZkEvmMessenger = _polygonZkEvmMessenger;
xDomainMessageSender = DEAD_ADDRESS;
}

function setL2Bridge(address _l2Bridge) external {
require(l2Bridge == address(0), "L2_PLGNZK_MSG: L2 Bridge already set");
l2Bridge = _l2Bridge;
}

function commitTransfers(uint256 destinationChainId) external {
require(msg.sender == tx.origin, "L2_PLGNZK_MSG: Sender must be origin");
canCommit = true;
L2Bridge(l2Bridge).commitTransfers(destinationChainId);
canCommit = false;
}

function sendCrossDomainMessage(bytes memory message) external onlyL2Bridge {
require(canCommit, "L2_PLGNZK_MSG: Unable to commit");
uint32 destinationNetwork = 0;
bool forceUpdateGlobalExitRoot = true;
IL2PolygonZkEvmMessenger(polygonZkEvmMessenger).bridgeMessage{value: 0}(
destinationNetwork,
l1Bridge,
forceUpdateGlobalExitRoot,
message
);
}

function onMessageReceived(
address originAddress,
uint32, /* originNetwork */
bytes memory data
)
external
override
payable
validateSender(originAddress)
nonReentrant
{
xDomainMessageSender = originAddress;
(bool success,) = l2Bridge.call(data);
require(success, "L2_PLGNZK_MSG: Failed to proxy message");
xDomainMessageSender = DEAD_ADDRESS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

/**
* @dev Define interface for PolygonZkEVM Bridge message receiver
* https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/interfaces/IBridgeMessageReceiver.sol
*/
interface IBridgeMessageReceiver {
function onMessageReceived(
address originAddress,
uint32 originNetwork,
bytes memory data
) external payable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

/// @title The bridge interface implemented on both chains
interface IL2PolygonZkEvmMessenger {
function bridgeMessage(
uint32 destinationNetwork,
address destinationAddress,
bool forceUpdateGlobalExitRoot,
bytes calldata metadata
) external payable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

interface I_L2_PolygonZkEvmMessengerProxy {
function sendCrossDomainMessage(bytes memory message) external;
function xDomainMessageSender() external view returns (address);
function onMessageReceived(
address originAddress,
uint32 originNetwork,
bytes memory data
) external;
}
28 changes: 28 additions & 0 deletions contracts/test/Mock_L2_PolygonZkEvmBridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "../bridges/L2_PolygonZkEvmBridge.sol";
import "../interfaces/polygonzkevm/messengers/I_L2_PolygonZkEvmMessengerProxy.sol";

contract Mock_L2_PolygonZkEvmBridge is L2_PolygonZkEvmBridge {
constructor (
I_L2_PolygonZkEvmMessengerProxy messenger,
address l1Governance,
HopBridgeToken hToken,
address l1BridgeAddress,
uint256[] memory activeChainIds,
address[] memory bonders
)
public
L2_PolygonZkEvmBridge(
messenger,
l1Governance,
hToken,
l1BridgeAddress,
activeChainIds,
bonders
)
{}
}
56 changes: 56 additions & 0 deletions contracts/test/polygonzkevm/mockPolygonZkEvm_L1Bridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

contract mockPolygonZkEvm_L1Bridge {
/**********
* Events *
**********/

/// @notice Emitted when a cross domain message is sent.
/// @param sender The address of the sender who initiates the message.
/// @param target The address of target contract to call.
/// @param value The amount of value passed to the target contract.
/// @param messageNonce The nonce of the message.
/// @param gasLimit The optional gas limit passed to L1 or L2.
/// @param message The calldata passed to the target contract.
event SentMessage(
address indexed sender,
address indexed target,
uint256 value,
uint256 messageNonce,
uint256 gasLimit,
bytes message
);

/// @notice Emitted when a cross domain message is relayed successfully.
/// @param messageHash The hash of the message.
event RelayedMessage(bytes32 indexed messageHash);

/// @notice Emitted when a cross domain message is failed to relay.
/// @param messageHash The hash of the message.
event FailedRelayedMessage(bytes32 indexed messageHash);

/*************************
* Public View Functions *
*************************/

/// @notice Return the sender of a cross domain message.
function xDomainMessageSender() external view returns (address) {}

/****************************
* Public Mutated Functions *
****************************/

/// @notice Send cross chain message from L1 to L2 or L2 to L1.
/// @param target The address of account who recieve the message.
/// @param value The amount of ether passed when call target contract.
/// @param message The content of the message.
/// @param gasLimit Gas limit required to complete the message relay on corresponding chain.
function sendMessage(
address target,
uint256 value,
bytes calldata message,
uint256 gasLimit
) external payable {}
}
6 changes: 6 additions & 0 deletions contracts/test/polygonzkevm/mockPolygonZkEvm_L2Bridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

contract mockPolygonZkEvm_L2Bridge {
}
Loading