Skip to content

Commit

Permalink
added l2 and sc custom errors
Browse files Browse the repository at this point in the history
  • Loading branch information
koloz193 committed May 15, 2024
1 parent 1515917 commit 2dfb996
Show file tree
Hide file tree
Showing 32 changed files with 697 additions and 408 deletions.
1 change: 1 addition & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ l2-contracts/node_modules
system-contracts/contracts/openzeppelin
system-contracts/contracts/Constants.sol
system-contracts/contracts/test-contracts
system-contracts/contracts-preprocessed
1 change: 1 addition & 0 deletions l1-contracts/contracts/dev-contracts/SingletonFactory.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/**
Expand Down
34 changes: 17 additions & 17 deletions l1-contracts/test/test_config/constant/hardhat.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,96 +3,96 @@
"name": "DAI",
"symbol": "DAI",
"decimals": 18,
"address": "0xfCdA09988fC2433BFE27BBe9e95E0C007ee272Fd"
"address": "0x3202935CA01eADd2F0B4e7aA23EFA52315121172"
},
{
"name": "wBTC",
"symbol": "wBTC",
"decimals": 8,
"address": "0x3b78cDD294f0b34755c8a9bA8f124Cb6c217b60a"
"address": "0xe73a1c05498e492f182f9B3E3cd65b2F9f52eE94"
},
{
"name": "BAT",
"symbol": "BAT",
"decimals": 18,
"address": "0xd4a9D970EF600289dC96b67505027D17604FBfe1"
"address": "0x7aAE2ee8317b384aDE246664933A147411b60045"
},
{
"name": "GNT",
"symbol": "GNT",
"decimals": 18,
"address": "0x4fE0EE70D78132fBb5C68C1d5e0020f3c05542f2"
"address": "0x02a344d1e31e92e39c2681937645F1d668C37d4e"
},
{
"name": "MLTT",
"symbol": "MLTT",
"decimals": 18,
"address": "0x3202935CA01eADd2F0B4e7aA23EFA52315121172"
"address": "0x28033f8EdB2F43747E55401C4a3E3b4b2cF5146C"
},
{
"name": "DAIK",
"symbol": "DAIK",
"decimals": 18,
"address": "0xe73a1c05498e492f182f9B3E3cd65b2F9f52eE94"
"address": "0x147dCc3a8E99794C2Ec79EaF1a142324D6778255"
},
{
"name": "wBTCK",
"symbol": "wBTCK",
"decimals": 8,
"address": "0x7aAE2ee8317b384aDE246664933A147411b60045"
"address": "0x74cA8715E29196Bfbcd7444B09203d22dDaF7d1a"
},
{
"name": "BATK",
"symbol": "BATS",
"decimals": 18,
"address": "0x02a344d1e31e92e39c2681937645F1d668C37d4e"
"address": "0x2eAf3eac597d23db3A8427329482aE47935141d9"
},
{
"name": "GNTK",
"symbol": "GNTS",
"decimals": 18,
"address": "0x28033f8EdB2F43747E55401C4a3E3b4b2cF5146C"
"address": "0x2B1b32d23f2be391280bFbD2B51daB8Ad2a69B9e"
},
{
"name": "MLTTK",
"symbol": "MLTTS",
"decimals": 18,
"address": "0x147dCc3a8E99794C2Ec79EaF1a142324D6778255"
"address": "0xc2Ca10940Ad80Cd98512B767457bd44713232B5a"
},
{
"name": "DAIL",
"symbol": "DAIL",
"decimals": 18,
"address": "0x74cA8715E29196Bfbcd7444B09203d22dDaF7d1a"
"address": "0xd6b4CDa9F0Ef6d9F6b35Ab5424df0dD95E6a6D1b"
},
{
"name": "wBTCL",
"symbol": "wBTCP",
"decimals": 8,
"address": "0x2eAf3eac597d23db3A8427329482aE47935141d9"
"address": "0x15CD4a1C10AE2D3727Dad680a1966947931588C9"
},
{
"name": "BATL",
"symbol": "BATW",
"decimals": 18,
"address": "0x2B1b32d23f2be391280bFbD2B51daB8Ad2a69B9e"
"address": "0x45f430CFD5Bf38eCE39f1B9A2930B3fD494619e8"
},
{
"name": "GNTL",
"symbol": "GNTW",
"decimals": 18,
"address": "0xc2Ca10940Ad80Cd98512B767457bd44713232B5a"
"address": "0x801Ab08819573537C0B256d139473eF13482B3Dd"
},
{
"name": "MLTTL",
"symbol": "MLTTW",
"decimals": 18,
"address": "0xd6b4CDa9F0Ef6d9F6b35Ab5424df0dD95E6a6D1b"
"address": "0xf55F3af54B9a507Bd0260e5844C1648921214745"
},
{
"name": "Wrapped Ether",
"symbol": "WETH",
"decimals": 18,
"address": "0x15CD4a1C10AE2D3727Dad680a1966947931588C9"
"address": "0xed01DF970925Cc0BB427f9E8014449C8a529D303"
}
]
]
20 changes: 20 additions & 0 deletions l2-contracts/contracts/L2ContractErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

error InvalidCaller(address);
error InvalidInput();
error InsufficientAllowance(uint256 providedAllowance, uint256 requiredAmount);
error FailedToTransferTokens(address tokenContract, address to, uint256 amount);
error UnsupportedPaymasterFlow();
error EmptyAddress();
error EmptyBytes32();
error AddressMismatch(address expected, address supplied);
error AmountMustBeGreaterThanZero();
error DeployFailed();
error Unauthorized();
error NonSequentialVersion();
error Unimplemented();
error UnimplementedMessage(string);
error WithdrawFailed();

string constant BRIDGE_MINT_NOT_IMPLEMENTED = "bridgeMint is not implemented! Use deposit/depositTo methods instead.";
22 changes: 16 additions & 6 deletions l2-contracts/contracts/TestnetPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "./interfaces/IPaymaster.sol";
import {IPaymasterFlow} from "./interfaces/IPaymasterFlow.sol";
import {Transaction, BOOTLOADER_ADDRESS} from "./L2ContractHelper.sol";
import {InvalidCaller, InvalidInput, InsufficientAllowance, FailedToTransferTokens, UnsupportedPaymasterFlow} from "./L2ContractErrors.sol";

// This is a dummy paymaster. It expects the paymasterInput to contain its "signature" as well as the needed exchange rate.
// It supports only approval-based paymaster flow.
Expand All @@ -19,8 +20,13 @@ contract TestnetPaymaster is IPaymaster {
// By default we consider the transaction as accepted.
magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC;

require(msg.sender == BOOTLOADER_ADDRESS, "Only bootloader can call this contract");
require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long");
if (msg.sender != BOOTLOADER_ADDRESS) {
revert InvalidCaller(msg.sender);
}

if (_transaction.paymasterInput.length < 4) {
revert InvalidInput();
}

bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]);
if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) {
Expand All @@ -33,7 +39,9 @@ contract TestnetPaymaster is IPaymaster {
address thisAddress = address(this);

uint256 providedAllowance = IERC20(token).allowance(userAddress, thisAddress);
require(providedAllowance >= amount, "The user did not provide enough allowance");
if (providedAllowance < amount) {
revert InsufficientAllowance(providedAllowance, amount);
}

// The testnet paymaster exchanges X wei of the token to the X wei of ETH.
uint256 requiredETH = _transaction.gasLimit * _transaction.maxFeePerGas;
Expand All @@ -51,7 +59,7 @@ contract TestnetPaymaster is IPaymaster {
// If the revert reason is empty or represented by just a function selector,
// we replace the error with a more user-friendly message
if (revertReason.length <= 4) {
revert("Failed to transferFrom from users' account");
revert FailedToTransferTokens(token, thisAddress, amount);
} else {
assembly {
revert(add(0x20, revertReason), mload(revertReason))
Expand All @@ -61,9 +69,11 @@ contract TestnetPaymaster is IPaymaster {

// The bootloader never returns any data, so it can safely be ignored here.
(bool success, ) = payable(BOOTLOADER_ADDRESS).call{value: requiredETH}("");
require(success, "Failed to transfer funds to the bootloader");
if (!success) {
revert FailedToTransferTokens(address(0), BOOTLOADER_ADDRESS, requiredETH);
}
} else {
revert("Unsupported paymaster flow");
revert UnsupportedPaymasterFlow();
}
}

Expand Down
56 changes: 40 additions & 16 deletions l2-contracts/contracts/bridge/L2SharedBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol";
import {L2ContractHelper, DEPLOYER_SYSTEM_CONTRACT, IContractDeployer} from "../L2ContractHelper.sol";
import {SystemContractsCaller} from "../SystemContractsCaller.sol";

import {EmptyAddress, EmptyBytes32, InvalidCaller, AddressMismatch, AmountMustBeGreaterThanZero, DeployFailed} from "../L2ContractErrors.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice The "default" bridge implementation for the ERC20 tokens. Note, that it does not
Expand All @@ -35,10 +37,10 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {

address private l1LegacyBridge;

uint256 internal immutable ERA_CHAIN_ID;

/// @dev Contract is expected to be used as proxy implementation.
/// @dev Disable the initialization to prevent Parity hack.
uint256 immutable ERA_CHAIN_ID;

constructor(uint256 _eraChainId) {
ERA_CHAIN_ID = _eraChainId;
_disableInitializers();
Expand All @@ -54,9 +56,17 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {
bytes32 _l2TokenProxyBytecodeHash,
address _aliasedOwner
) external reinitializer(2) {
require(_l1Bridge != address(0), "bf");
require(_l2TokenProxyBytecodeHash != bytes32(0), "df");
require(_aliasedOwner != address(0), "sf");
if (_l1Bridge == address(0)) {
revert EmptyAddress();
}

if (_l2TokenProxyBytecodeHash == bytes32(0)) {
revert EmptyBytes32();
}

if (_aliasedOwner == address(0)) {
revert EmptyAddress();
}

l1Bridge = _l1Bridge;

Expand All @@ -66,7 +76,9 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {
l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash;
l2TokenBeacon.transferOwnership(_aliasedOwner);
} else {
require(_l1LegacyBridge != address(0), "bf2");
if (_l1LegacyBridge == address(0)) {
revert EmptyAddress();
}
l1LegacyBridge = _l1LegacyBridge;
// l2StandardToken and l2TokenBeacon are already deployed on ERA, and stored in the proxy
}
Expand All @@ -86,20 +98,26 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {
bytes calldata _data
) external override {
// Only the L1 bridge counterpart can initiate and finalize the deposit.
require(
AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1Bridge ||
AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1LegacyBridge,
"mq"
);
if (
AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1Bridge &&
AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1LegacyBridge
) {
revert InvalidCaller(msg.sender);
}

address expectedL2Token = l2TokenAddress(_l1Token);
address currentL1Token = l1TokenAddress[expectedL2Token];
if (currentL1Token == address(0)) {
address deployedToken = _deployL2Token(_l1Token, _data);
require(deployedToken == expectedL2Token, "mt");
if (deployedToken != expectedL2Token) {
revert AddressMismatch(expectedL2Token, deployedToken);
}

l1TokenAddress[expectedL2Token] = _l1Token;
} else {
require(currentL1Token == _l1Token, "gg"); // Double check that the expected value equal to real one
if (currentL1Token != _l1Token) {
revert AddressMismatch(_l1Token, currentL1Token);
}
}

IL2StandardToken(expectedL2Token).bridgeMint(_l2Receiver, _amount);
Expand All @@ -122,12 +140,16 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {
/// @param _l2Token The L2 token address which is withdrawn
/// @param _amount The total amount of tokens to be withdrawn
function withdraw(address _l1Receiver, address _l2Token, uint256 _amount) external override {
require(_amount > 0, "Amount cannot be zero");
if (_amount == 0) {
revert AmountMustBeGreaterThanZero();
}

IL2StandardToken(_l2Token).bridgeBurn(msg.sender, _amount);

address l1Token = l1TokenAddress[_l2Token];
require(l1Token != address(0), "yh");
if (l1Token == address(0)) {
revert EmptyAddress();
}

bytes memory message = _getL1WithdrawMessage(_l1Receiver, l1Token, _amount);
L2ContractHelper.sendMessageToL1(message);
Expand Down Expand Up @@ -174,7 +196,9 @@ contract L2SharedBridge is IL2SharedBridge, Initializable {
);

// The deployment should be successful and return the address of the proxy
require(success, "mk");
if (!success) {
revert DeployFailed();
}
proxy = BeaconProxy(abi.decode(returndata, (address)));
}
}
Loading

0 comments on commit 2dfb996

Please sign in to comment.