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

fix: [M-01] zkSync limits #328

Merged
merged 2 commits into from
Jul 28, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 67 additions & 4 deletions contracts/chain-adapters/ZkSync_Adapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,63 @@
) external payable returns (bytes32 txHash);
}

// Note: this contract just forwards the calls from the HubPool to ZkSync to avoid limits.
// A modified ZKSync_Adapter should be deployed with this address swapped in for all zkSync addresses.
contract LimitBypassProxy is ZkSyncInterface, ZkBridgeLike {
using SafeERC20 for IERC20;
ZkSyncInterface public constant zkSync = ZkSyncInterface(0x32400084C286CF3E17e7B677ea9583e60a000324);

Check warning on line 60 in contracts/chain-adapters/ZkSync_Adapter.sol

View workflow job for this annotation

GitHub Actions / Solhint (16)

Constant name must be in capitalized SNAKE_CASE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solhint is indicating that this should be in uppercase snake case ZKSYNC. Should we modify the solhint?

Copy link
Contributor Author

@mrice32 mrice32 Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@james-a-morris @pxrl Since we generally don't snake case contract interfaces, I removed the solhint warning for now to appease the linter and kept this consistent. If we decide to change in the future, we can revert this config change. But for the audit, I wanted to avoid making any changes outside of the scope.

ZkBridgeLike public constant zkErc20Bridge = ZkBridgeLike(0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063);

Check warning on line 61 in contracts/chain-adapters/ZkSync_Adapter.sol

View workflow job for this annotation

GitHub Actions / Solhint (16)

Constant name must be in capitalized SNAKE_CASE

function l2TransactionBaseCost(
uint256 _l1GasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256) {
return zkSync.l2TransactionBaseCost(_l1GasPrice, _l2GasLimit, _l2GasPerPubdataByteLimit);
}

function requestL2Transaction(
address _contractL2,
uint256 _l2Value,
bytes calldata _calldata,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit,
bytes[] calldata _factoryDeps,
address _refundRecipient
) external payable returns (bytes32 canonicalTxHash) {
return
zkSync.requestL2Transaction{ value: msg.value }(
_contractL2,
_l2Value,
_calldata,
_l2GasLimit,
_l2GasPerPubdataByteLimit,
_factoryDeps,
_refundRecipient
);
}

function deposit(
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte,
address _refundRecipient
) external payable returns (bytes32 txHash) {
IERC20(_l1Token).safeIncreaseAllowance(address(zkErc20Bridge), _amount);
return
zkErc20Bridge.deposit{ value: msg.value }(
_l2Receiver,
_l1Token,
_amount,
_l2TxGasLimit,
_l2TxGasPerPubdataByte,
_refundRecipient
);
}
}

/**
* @notice Contract containing logic to send messages from L1 to ZkSync.
* @dev Public functions calling external contracts do not guard against reentrancy because they are expected to be
Expand Down Expand Up @@ -82,13 +139,18 @@
// This address receives any remaining fee after an L1 to L2 transaction completes.
// If refund recipient = address(0) then L2 msg.sender is used, unless msg.sender is a contract then its address
// gets aliased.
address public constant l2RefundAddress = 0x428AB2BA90Eba0a4Be7aF34C9Ac451ab061AC010;

Check warning on line 142 in contracts/chain-adapters/ZkSync_Adapter.sol

View workflow job for this annotation

GitHub Actions / Solhint (16)

Constant name must be in capitalized SNAKE_CASE

// Hardcode the following ZkSync system contract addresses to save gas on construction. This adapter can be
// redeployed in the event that the following addresses change.

// Main contract used to send L1 --> L2 messages. Fetchable via `zks_getMainContract` method on JSON RPC.
ZkSyncInterface public constant zkSync = ZkSyncInterface(0x32400084C286CF3E17e7B677ea9583e60a000324);
ZkSyncInterface public constant zkSyncMessageBridge = ZkSyncInterface(0x32400084C286CF3E17e7B677ea9583e60a000324);

Check warning on line 148 in contracts/chain-adapters/ZkSync_Adapter.sol

View workflow job for this annotation

GitHub Actions / Solhint (16)

Constant name must be in capitalized SNAKE_CASE

// Contract used to send ETH to L2. Note: this is the same address as the main contract, but separated to allow
// only this contract to be swapped (leaving the main zkSync contract to be used for messaging).
ZkSyncInterface public constant zkSyncEthBridge = ZkSyncInterface(0x32400084C286CF3E17e7B677ea9583e60a000324);

// Bridges to send ERC20 and ETH to L2. Fetchable via `zks_getBridgeContracts` method on JSON RPC.
ZkBridgeLike public constant zkErc20Bridge = ZkBridgeLike(0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063);

Expand Down Expand Up @@ -117,7 +179,7 @@
uint256 txBaseCost = _contractHasSufficientEthBalance();

// Returns the hash of the requested L2 transaction. This hash can be used to follow the transaction status.
bytes32 canonicalTxHash = zkSync.requestL2Transaction{ value: txBaseCost }(
bytes32 canonicalTxHash = zkSyncMessageBridge.requestL2Transaction{ value: txBaseCost }(
target,
// We pass no ETH with the call, otherwise we'd need to add to the txBaseCost this value.
0,
Expand Down Expand Up @@ -164,7 +226,7 @@
if (l1Token == address(l1Weth)) {
l1Weth.withdraw(amount);
// We cannot call the standard ERC20 bridge because it disallows ETH deposits.
txHash = zkSync.requestL2Transaction{ value: txBaseCost + amount }(
txHash = zkSyncEthBridge.requestL2Transaction{ value: txBaseCost + amount }(
to,
amount,
"",
Expand Down Expand Up @@ -199,7 +261,8 @@
// https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/ethereum/contracts/zksync/facets/Mailbox.sol#L273
// - priority_fee_per_gas = min(transaction.max_priority_fee_per_gas, transaction.max_fee_per_gas - block.base_fee_per_gas)
// - effective_gas_price = priority_fee_per_gas + block.base_fee_per_gas
return zkSync.l2TransactionBaseCost(tx.gasprice, L2_GAS_LIMIT, L1_GAS_TO_L2_GAS_PER_PUB_DATA_LIMIT);
return
zkSyncMessageBridge.l2TransactionBaseCost(tx.gasprice, L2_GAS_LIMIT, L1_GAS_TO_L2_GAS_PER_PUB_DATA_LIMIT);
}

function _contractHasSufficientEthBalance() internal view returns (uint256 requiredL1CallValue) {
Expand Down