Skip to content

Commit

Permalink
Fix mantle (#108)
Browse files Browse the repository at this point in the history
* fix mantle eth bug

* fix lint

* support mantle eth withdraw

* update mantle chain config
  • Loading branch information
zkbenny authored May 3, 2024
1 parent 16db883 commit be73bd8
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 66 deletions.
34 changes: 20 additions & 14 deletions contracts/ZkLink.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {AddressAliasHelper} from "./zksync/l1-contracts/vendor/AddressAliasHelper.sol";
import {IZkLink} from "./interfaces/IZkLink.sol";
import {IL2Gateway} from "./interfaces/IL2Gateway.sol";
Expand Down Expand Up @@ -35,6 +37,7 @@ contract ZkLink is
PausableUpgradeable
{
using UncheckedMath for uint256;
using SafeERC20 for IERC20;

/// @dev The forward request type hash
bytes32 public constant FORWARD_REQUEST_TYPE_HASH =
Expand All @@ -45,9 +48,6 @@ contract ZkLink is
/// @dev The length of withdraw message sent to secondary chain
uint256 private constant L2_WITHDRAW_MESSAGE_LENGTH = 108;

/// @dev Whether eth is the gas token
bool public immutable IS_ETH_GAS_TOKEN;

/// @notice The gateway is used for communicating with L1
IL2Gateway public gateway;
/// @notice List of permitted validators
Expand Down Expand Up @@ -148,8 +148,7 @@ contract ZkLink is
_;
}

constructor(bool _isEthGasToken) {
IS_ETH_GAS_TOKEN = _isEthGasToken;
constructor() {
_disableInitializers();
}

Expand Down Expand Up @@ -275,7 +274,7 @@ contract ZkLink is
address _refundRecipient
) external payable nonReentrant whenNotPaused returns (bytes32 canonicalTxHash) {
// Disable l2 value if eth is not the gas token
if (!IS_ETH_GAS_TOKEN) {
if (!gateway.isEthGasToken()) {
require(_l2Value == 0, "Not allow l2 value");
}
// Change the sender address if it is a smart contract to prevent address collision between L1 and L2.
Expand Down Expand Up @@ -365,7 +364,6 @@ contract ZkLink is
bytes calldata _message,
bytes32[] calldata _merkleProof
) external nonReentrant {
require(IS_ETH_GAS_TOKEN, "Not allow eth withdraw");
require(!isEthWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex], "jj");

L2Message memory l2ToL1Message = L2Message({
Expand Down Expand Up @@ -461,7 +459,9 @@ contract ZkLink is
bytes32 _l2LogsRootHash,
uint256 _forwardEthAmount
) external payable onlyGateway {
require(msg.value == _forwardEthAmount, "Invalid forward amount");
if (gateway.isEthGasToken()) {
require(msg.value == _forwardEthAmount, "Invalid forward amount");
}
// Allows repeated sending of the forward amount of the batch
if (_batchNumber > totalBatchesExecuted) {
totalBatchesExecuted = _batchNumber;
Expand All @@ -477,7 +477,9 @@ contract ZkLink is
uint256 _forwardEthAmount
) external payable onlyGateway {
require(_toBatchNumber >= _fromBatchNumber, "Invalid range");
require(msg.value == _forwardEthAmount, "Invalid forward amount");
if (gateway.isEthGasToken()) {
require(msg.value == _forwardEthAmount, "Invalid forward amount");
}
bytes32 range = keccak256(abi.encodePacked(_fromBatchNumber, _toBatchNumber));
rangeBatchRootHashes[range] = _rangeBatchRootHash;
emit SyncRangeBatchRoot(_fromBatchNumber, _toBatchNumber, _rangeBatchRootHash, _forwardEthAmount);
Expand Down Expand Up @@ -644,12 +646,16 @@ contract ZkLink is
/// @notice Transfer ether from the contract to the receiver
/// @dev Reverts only if the transfer call failed
function _withdrawFunds(address _to, uint256 _amount) internal {
bool callSuccess;
// Low-level assembly call, to avoid any memory copying (save gas)
assembly {
callSuccess := call(gas(), _to, _amount, 0, 0, 0, 0)
if (gateway.isEthGasToken()) {
bool callSuccess;
// Low-level assembly call, to avoid any memory copying (save gas)
assembly {
callSuccess := call(gas(), _to, _amount, 0, 0, 0, 0)
}
require(callSuccess, "pz");
} else {
SafeERC20.safeTransfer(gateway.ethToken(), _to, _amount);
}
require(callSuccess, "pz");
}

function hashForwardL2Request(ForwardL2Request memory _request) internal pure returns (bytes32) {
Expand Down
4 changes: 1 addition & 3 deletions contracts/dev-contracts/DummyZkLink.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IL2Gateway} from "../interfaces/IL2Gateway.sol";
import {IZkLink} from "../interfaces/IZkLink.sol";

contract DummyZkLink is IZkLink, OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuardUpgradeable {
bool public immutable IS_ETH_GAS_TOKEN;
IL2Gateway public gateway;

event ReceiveBatchRoot(uint256 batchNumber, bytes32 l2LogsRootHash, uint256 forwardEthAmount);
Expand All @@ -26,8 +25,7 @@ contract DummyZkLink is IZkLink, OwnableUpgradeable, UUPSUpgradeable, Reentrancy
_;
}

constructor(bool _isEthGasToken) {
IS_ETH_GAS_TOKEN = _isEthGasToken;
constructor() {
_disableInitializers();
}

Expand Down
9 changes: 9 additions & 0 deletions contracts/gateway/L2BaseGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.0;

import {IL2Gateway} from "../interfaces/IL2Gateway.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

abstract contract L2BaseGateway is IL2Gateway {
/// @notice The zkLink contract
Expand All @@ -23,4 +24,12 @@ abstract contract L2BaseGateway is IL2Gateway {
constructor(address _zkLink) {
ZKLINK = _zkLink;
}

function isEthGasToken() external pure virtual returns (bool) {
return true;
}

function ethToken() external pure virtual returns (IERC20) {
return IERC20(address(0));
}
}
38 changes: 38 additions & 0 deletions contracts/gateway/optimism/MantleL2Gateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.0;

import {OptimismL2Gateway} from "./OptimismL2Gateway.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract MantleL2Gateway is OptimismL2Gateway {
using SafeERC20 for IERC20;

/// @dev The ETH token deployed on Mantle
IERC20 private constant BVM_ETH = IERC20(0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111);

constructor(address _zkLink) OptimismL2Gateway(_zkLink) {
_disableInitializers();
}

function isEthGasToken() external pure override returns (bool) {
return false;
}

function ethToken() external pure override returns (IERC20) {
return BVM_ETH;
}

function claimMessageCallback(
uint256 _ethValue,
bytes calldata _callData
) external payable override onlyMessageService onlyRemoteGateway {
if (_ethValue > 0) {
// Mantle L2CrossDomainMessenger will approve l2 gateway before the callback in `relayMessage`
SafeERC20.safeTransferFrom(BVM_ETH, address(MESSAGE_SERVICE), address(ZKLINK), _ethValue);
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = ZKLINK.call{value: 0}(_callData);
require(success, "Call zkLink failed");
}
}
2 changes: 1 addition & 1 deletion contracts/gateway/optimism/OptimismL2Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract OptimismL2Gateway is L2BaseGateway, OptimismGateway {
function claimMessageCallback(
uint256 _value,
bytes calldata _callData
) external payable onlyMessageService onlyRemoteGateway {
) external payable virtual onlyMessageService onlyRemoteGateway {
require(msg.value == _value, "Invalid value");

// solhint-disable-next-line avoid-low-level-calls
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IL2Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.0;

import {IGateway} from "./IGateway.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IL2Gateway is IGateway {
/// @notice Emit when sending a message
Expand All @@ -11,4 +12,8 @@ interface IL2Gateway is IGateway {
/// @param _value The msg value
/// @param _callData The call data
function sendMessage(uint256 _value, bytes calldata _callData) external payable;

function isEthGasToken() external view returns (bool);

function ethToken() external view returns (IERC20);
}
30 changes: 2 additions & 28 deletions script/ChainConfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
{
"ETHEREUM": {
"eth": true
},
"ZKSYNC": {
"eth": true,
"l2Gateway": {
"contractName": "ZkSyncL2Gateway",
"constructParams": [],
Expand All @@ -17,7 +15,6 @@
}
},
"SCROLL": {
"eth": true,
"l2Gateway": {
"contractName": "ScrollL2Gateway",
"constructParams": ["0x781e90f1c8Fc4611c9b7497C3B47F99Ef6969CbC"],
Expand All @@ -31,7 +28,6 @@
}
},
"LINEA": {
"eth": true,
"l2Gateway": {
"contractName": "LineaL2Gateway",
"constructParams": ["0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec"],
Expand All @@ -45,7 +41,6 @@
}
},
"ZKPOLYGON": {
"eth": true,
"l2Gateway": {
"contractName": "ZkPolygonL2Gateway",
"constructParams": ["0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe"],
Expand All @@ -59,7 +54,6 @@
}
},
"ARBITRUM": {
"eth": true,
"l2Gateway": {
"contractName": "ArbitrumL2Gateway",
"constructParams": [],
Expand All @@ -73,7 +67,6 @@
}
},
"OPTIMISM": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -87,7 +80,6 @@
}
},
"MANTA": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -101,9 +93,8 @@
}
},
"MANTLE": {
"eth": false,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"contractName": "MantleL2Gateway",
"constructParams": [],
"initializeParams": []
},
Expand All @@ -115,7 +106,6 @@
}
},
"BLAST": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -129,7 +119,6 @@
}
},
"BASE": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -143,7 +132,6 @@
}
},
"METIS": {
"eth": false,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -156,14 +144,9 @@
"initializeParams": []
}
},
"GOERLI": {
"eth": true
},
"SEPOLIA": {
"eth": true
},
"ZKSYNCTEST": {
"eth": true,
"l2Gateway": {
"contractName": "ZkSyncL2Gateway",
"constructParams": [],
Expand All @@ -177,7 +160,6 @@
}
},
"SCROLLTEST": {
"eth": true,
"l2Gateway": {
"contractName": "ScrollL2Gateway",
"constructParams": ["0xBa50f5340FB9F3Bd074bD638c9BE13eCB36E603d"],
Expand All @@ -191,7 +173,6 @@
}
},
"LINEATEST": {
"eth": true,
"l2Gateway": {
"contractName": "LineaL2Gateway",
"constructParams": ["0x971e727e956690b9957be6d51Ec16E73AcAC83A7"],
Expand All @@ -205,7 +186,6 @@
}
},
"ZKPOLYGONTEST": {
"eth": true,
"l2Gateway": {
"contractName": "ZkPolygonL2Gateway",
"constructParams": ["0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7"],
Expand All @@ -219,7 +199,6 @@
}
},
"ARBITRUMTEST": {
"eth": true,
"l2Gateway": {
"contractName": "ArbitrumL2Gateway",
"constructParams": [],
Expand All @@ -233,7 +212,6 @@
}
},
"OPTIMISMTEST": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -247,7 +225,6 @@
}
},
"MANTATEST": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -261,9 +238,8 @@
}
},
"MANTLETEST": {
"eth": false,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"contractName": "MantleL2Gateway",
"constructParams": [],
"initializeParams": []
},
Expand All @@ -275,7 +251,6 @@
}
},
"BLASTTEST": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand All @@ -289,7 +264,6 @@
}
},
"BASETEST": {
"eth": true,
"l2Gateway": {
"contractName": "OptimismL2Gateway",
"constructParams": [],
Expand Down
Loading

0 comments on commit be73bd8

Please sign in to comment.