├── .github └── workflows │ └── secrets_scanner.yaml ├── .gitignore ├── README.md ├── hardhat.config.js ├── l1 └── contracts │ ├── bridge │ ├── L1ERC20Bridge.sol │ └── interfaces │ │ ├── IL1Bridge.sol │ │ ├── IL1BridgeLegacy.sol │ │ └── IL2Bridge.sol │ ├── common │ ├── AllowList.sol │ ├── AllowListed.sol │ ├── Dependencies.sol │ ├── L2ContractAddresses.sol │ ├── ReentrancyGuard.sol │ ├── interfaces │ │ ├── IAllowList.sol │ │ └── IL2ContractDeployer.sol │ └── libraries │ │ ├── L2ContractHelper.sol │ │ ├── UncheckedMath.sol │ │ └── UnsafeBytes.sol │ ├── vendor │ └── AddressAliasHelper.sol │ └── zksync │ ├── Config.sol │ ├── DiamondInit.sol │ ├── DiamondProxy.sol │ ├── Plonk4VerifierWithAccessToDNext.sol │ ├── Storage.sol │ ├── Verifier.sol │ ├── facets │ ├── Base.sol │ ├── DiamondCut.sol │ ├── Executor.sol │ ├── Getters.sol │ ├── Governance.sol │ └── Mailbox.sol │ ├── interfaces │ ├── IDiamondCut.sol │ ├── IExecutor.sol │ ├── IGetters.sol │ ├── IGovernance.sol │ ├── IMailbox.sol │ └── IZkSync.sol │ ├── libraries │ ├── Diamond.sol │ ├── Merkle.sol │ ├── PairingsBn254.sol │ ├── PriorityQueue.sol │ └── TranscriptLib.sol │ └── upgrade-initializers │ ├── DIamondUpgradeInit2.sol │ ├── DiamondUpgradeInit1.sol │ ├── DiamondUpgradeInit3.sol │ └── DiamondUpgradeInit4.sol ├── l2 ├── contracts │ ├── Dependencies.sol │ ├── ExternalDecoder.sol │ ├── L2ContractHelper.sol │ ├── TestnetPaymaster.sol │ ├── bridge │ │ ├── L2ERC20Bridge.sol │ │ ├── L2StandardERC20.sol │ │ ├── L2WETH.sol │ │ └── interfaces │ │ │ ├── IL1Bridge.sol │ │ │ ├── IL2Bridge.sol │ │ │ ├── IL2StandardToken.sol │ │ │ └── IL2WETH.sol │ ├── interfaces │ │ ├── IPaymaster.sol │ │ └── IPaymasterFlow.sol │ └── vendor │ │ └── AddressAliasHelper.sol └── system-contracts │ ├── AccountCodeStorage.sol │ ├── BootloaderUtilities.sol │ ├── BytecodeCompressor.sol │ ├── Constants.sol │ ├── ContractDeployer.sol │ ├── DefaultAccount.sol │ ├── EmptyContract.sol │ ├── EventWriter.yul │ ├── ImmutableSimulator.sol │ ├── KnownCodesStorage.sol │ ├── L1Messenger.sol │ ├── L2EthToken.sol │ ├── MsgValueSimulator.sol │ ├── NonceHolder.sol │ ├── SystemContext.sol │ ├── interfaces │ ├── IAccount.sol │ ├── IAccountCodeStorage.sol │ ├── IBootloaderUtilities.sol │ ├── IBytecodeCompressor.sol │ ├── IContractDeployer.sol │ ├── IEthToken.sol │ ├── IImmutableSimulator.sol │ ├── IKnownCodesStorage.sol │ ├── IL1Messenger.sol │ ├── IL2StandardToken.sol │ ├── IMailbox.sol │ ├── INonceHolder.sol │ ├── IPaymaster.sol │ ├── IPaymasterFlow.sol │ └── ISystemContext.sol │ ├── libraries │ ├── EfficientCall.sol │ ├── RLPEncoder.sol │ ├── SystemContractHelper.sol │ ├── SystemContractsCaller.sol │ ├── TransactionHelper.sol │ ├── UnsafeBytesCalldata.sol │ └── Utils.sol │ ├── openzeppelin │ ├── token │ │ └── ERC20 │ │ │ ├── IERC20.sol │ │ │ ├── extensions │ │ │ └── IERC20Permit.sol │ │ │ └── utils │ │ │ └── SafeERC20.sol │ └── utils │ │ └── Address.sol │ ├── precompiles │ ├── Ecrecover.yul │ ├── Keccak256.yul │ └── SHA256.yul │ ├── test-contracts │ ├── TestSystemContract.sol │ └── TestSystemContractHelper.sol │ └── tests │ ├── Counter.sol │ └── TransactionHelperTest.sol ├── package.json └── yarn.lock /.github/workflows/secrets_scanner.yaml: -------------------------------------------------------------------------------- 1 | name: Leaked Secrets Scan 2 | on: [pull_request] 3 | jobs: 4 | TruffleHog: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout code 8 | uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 9 | with: 10 | fetch-depth: 0 11 | - name: TruffleHog OSS 12 | uses: trufflesecurity/trufflehog@0c66d30c1f4075cee1aada2e1ab46dabb1b0071a 13 | with: 14 | path: ./ 15 | base: ${{ github.event.repository.default_branch }} 16 | head: HEAD 17 | extra_args: --debug --only-verified 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | cache 3 | artifacts 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zkSync Smart Contracts 2 | 3 | zkSync smart contracts. More detailed description to be added soon. 4 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | solidity: { 3 | version: "0.8.19", 4 | settings: { 5 | optimizer: { 6 | enabled: true, 7 | runs: 1000, 8 | } 9 | } 10 | }, 11 | paths: { 12 | sources: "./l1", 13 | cache: "./cache", 14 | artifacts: "./artifacts" 15 | }, 16 | mocha: { 17 | timeout: 40000 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /l1/contracts/bridge/interfaces/IL1Bridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /// @author Matter Labs 6 | interface IL1Bridge { 7 | event DepositInitiated( 8 | bytes32 indexed l2DepositTxHash, 9 | address indexed from, 10 | address indexed to, 11 | address l1Token, 12 | uint256 amount 13 | ); 14 | 15 | event WithdrawalFinalized(address indexed to, address indexed l1Token, uint256 amount); 16 | 17 | event ClaimedFailedDeposit(address indexed to, address indexed l1Token, uint256 amount); 18 | 19 | function isWithdrawalFinalized(uint256 _l2BlockNumber, uint256 _l2MessageIndex) external view returns (bool); 20 | 21 | function deposit( 22 | address _l2Receiver, 23 | address _l1Token, 24 | uint256 _amount, 25 | uint256 _l2TxGasLimit, 26 | uint256 _l2TxGasPerPubdataByte, 27 | address _refundRecipient 28 | ) external payable returns (bytes32 txHash); 29 | 30 | function claimFailedDeposit( 31 | address _depositSender, 32 | address _l1Token, 33 | bytes32 _l2TxHash, 34 | uint256 _l2BlockNumber, 35 | uint256 _l2MessageIndex, 36 | uint16 _l2TxNumberInBlock, 37 | bytes32[] calldata _merkleProof 38 | ) external; 39 | 40 | function finalizeWithdrawal( 41 | uint256 _l2BlockNumber, 42 | uint256 _l2MessageIndex, 43 | uint16 _l2TxNumberInBlock, 44 | bytes calldata _message, 45 | bytes32[] calldata _merkleProof 46 | ) external; 47 | 48 | function l2TokenAddress(address _l1Token) external view returns (address); 49 | } 50 | -------------------------------------------------------------------------------- /l1/contracts/bridge/interfaces/IL1BridgeLegacy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /// @author Matter Labs 6 | interface IL1BridgeLegacy { 7 | function deposit( 8 | address _l2Receiver, 9 | address _l1Token, 10 | uint256 _amount, 11 | uint256 _l2TxGasLimit, 12 | uint256 _l2TxGasPerPubdataByte 13 | ) external payable returns (bytes32 txHash); 14 | } 15 | -------------------------------------------------------------------------------- /l1/contracts/bridge/interfaces/IL2Bridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /// @author Matter Labs 6 | interface IL2Bridge { 7 | function initialize( 8 | address _l1Bridge, 9 | bytes32 _l2TokenProxyBytecodeHash, 10 | address _governor 11 | ) external; 12 | 13 | function finalizeDeposit( 14 | address _l1Sender, 15 | address _l2Receiver, 16 | address _l1Token, 17 | uint256 _amount, 18 | bytes calldata _data 19 | ) external; 20 | 21 | function withdraw( 22 | address _l1Receiver, 23 | address _l2Token, 24 | uint256 _amount 25 | ) external; 26 | 27 | function l1TokenAddress(address _l2Token) external view returns (address); 28 | 29 | function l2TokenAddress(address _l1Token) external view returns (address); 30 | 31 | function l1Bridge() external view returns (address); 32 | } 33 | -------------------------------------------------------------------------------- /l1/contracts/common/AllowList.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "@openzeppelin/contracts/access/Ownable2Step.sol"; 6 | 7 | import "./interfaces/IAllowList.sol"; 8 | import "./libraries/UncheckedMath.sol"; 9 | 10 | /// @author Matter Labs 11 | /// @notice The smart contract that stores the permissions to call the function on different contracts. 12 | /// @dev The contract is fully controlled by the owner, that can grant and revoke any permissions at any time. 13 | /// @dev The permission list has three different modes: 14 | /// - Closed. The contract can NOT be called by anyone. 15 | /// - SpecialAccessOnly. Only some contract functions can be called by specifically granted addresses. 16 | /// - Public. Access list to call any function from the target contract by any caller 17 | contract AllowList is IAllowList, Ownable2Step { 18 | using UncheckedMath for uint256; 19 | 20 | /// @notice The Access mode by which it is decided whether the caller has access 21 | mapping(address => AccessMode) public getAccessMode; 22 | 23 | /// @notice The mapping that stores permissions to call the function on the target address by the caller 24 | /// @dev caller => target => function signature => permission to call target function for the given caller address 25 | mapping(address => mapping(address => mapping(bytes4 => bool))) public hasSpecialAccessToCall; 26 | 27 | /// @dev The mapping L1 token address => struct Deposit 28 | mapping(address => Deposit) public tokenDeposit; 29 | 30 | constructor(address _initialOwner) { 31 | _transferOwnership(_initialOwner); 32 | } 33 | 34 | /// @return Whether the caller can call the specific function on the target contract 35 | /// @param _caller The caller address, who is granted access 36 | /// @param _target The address of the smart contract which is called 37 | /// @param _functionSig The function signature (selector), access to which need to check 38 | function canCall( 39 | address _caller, 40 | address _target, 41 | bytes4 _functionSig 42 | ) external view returns (bool) { 43 | AccessMode accessMode = getAccessMode[_target]; 44 | return 45 | accessMode == AccessMode.Public || 46 | (accessMode == AccessMode.SpecialAccessOnly && hasSpecialAccessToCall[_caller][_target][_functionSig]); 47 | } 48 | 49 | /// @notice Set the permission mode to call the target contract 50 | /// @param _target The address of the smart contract, of which access to the call is to be changed 51 | /// @param _accessMode Whether no one, any or only some addresses can call the target contract 52 | function setAccessMode(address _target, AccessMode _accessMode) external onlyOwner { 53 | _setAccessMode(_target, _accessMode); 54 | } 55 | 56 | /// @notice Set many permission modes to call the target contracts 57 | /// @dev Analogous to function `setAccessMode` but performs a batch of changes 58 | /// @param _targets The array of smart contract addresses, of which access to the call is to be changed 59 | /// @param _accessModes The array of new permission modes, whether no one, any or only some addresses can call the target contract 60 | function setBatchAccessMode(address[] calldata _targets, AccessMode[] calldata _accessModes) external onlyOwner { 61 | uint256 targetsLength = _targets.length; 62 | require(targetsLength == _accessModes.length, "yg"); // The size of arrays should be equal 63 | 64 | for (uint256 i = 0; i < targetsLength; i = i.uncheckedInc()) { 65 | _setAccessMode(_targets[i], _accessModes[i]); 66 | } 67 | } 68 | 69 | /// @dev Changes access mode and emit the event if the access was changed 70 | function _setAccessMode(address _target, AccessMode _accessMode) internal { 71 | AccessMode accessMode = getAccessMode[_target]; 72 | 73 | if (accessMode != _accessMode) { 74 | getAccessMode[_target] = _accessMode; 75 | emit UpdateAccessMode(_target, accessMode, _accessMode); 76 | } 77 | } 78 | 79 | /// @notice Set many permissions to call the function on the contract to the specified caller address 80 | /// @param _callers The array of caller addresses, who are granted access 81 | /// @param _targets The array of smart contract addresses, of which access to the call are to be changed 82 | /// @param _functionSigs The array of function signatures (selectors), access to which need to be changed 83 | /// @param _enables The array of boolean flags, whether enable or disable the function access to the corresponding target address 84 | function setBatchPermissionToCall( 85 | address[] calldata _callers, 86 | address[] calldata _targets, 87 | bytes4[] calldata _functionSigs, 88 | bool[] calldata _enables 89 | ) external onlyOwner { 90 | uint256 callersLength = _callers.length; 91 | 92 | // The size of arrays should be equal 93 | require(callersLength == _targets.length, "yw"); 94 | require(callersLength == _functionSigs.length, "yx"); 95 | require(callersLength == _enables.length, "yy"); 96 | 97 | for (uint256 i = 0; i < callersLength; i = i.uncheckedInc()) { 98 | _setPermissionToCall(_callers[i], _targets[i], _functionSigs[i], _enables[i]); 99 | } 100 | } 101 | 102 | /// @notice Set the permission to call the function on the contract to the specified caller address 103 | /// @param _caller The caller address, who is granted access 104 | /// @param _target The address of the smart contract, of which access to the call is to be changed 105 | /// @param _functionSig The function signature (selector), access to which need to be changed 106 | /// @param _enable Whether enable or disable the permission 107 | function setPermissionToCall( 108 | address _caller, 109 | address _target, 110 | bytes4 _functionSig, 111 | bool _enable 112 | ) external onlyOwner { 113 | _setPermissionToCall(_caller, _target, _functionSig, _enable); 114 | } 115 | 116 | /// @dev Changes permission to call and emits the event if the permission was changed 117 | function _setPermissionToCall( 118 | address _caller, 119 | address _target, 120 | bytes4 _functionSig, 121 | bool _enable 122 | ) internal { 123 | bool currentPermission = hasSpecialAccessToCall[_caller][_target][_functionSig]; 124 | 125 | if (currentPermission != _enable) { 126 | hasSpecialAccessToCall[_caller][_target][_functionSig] = _enable; 127 | emit UpdateCallPermission(_caller, _target, _functionSig, _enable); 128 | } 129 | } 130 | 131 | /// @dev Set deposit limit data for a token 132 | /// @param _l1Token The address of L1 token 133 | /// @param _depositLimitation deposit limitation is active or not 134 | /// @param _depositCap The maximum amount that can be deposited. 135 | function setDepositLimit( 136 | address _l1Token, 137 | bool _depositLimitation, 138 | uint256 _depositCap 139 | ) external onlyOwner { 140 | tokenDeposit[_l1Token].depositLimitation = _depositLimitation; 141 | tokenDeposit[_l1Token].depositCap = _depositCap; 142 | } 143 | 144 | /// @dev Get deposit limit data of a token 145 | /// @param _l1Token The address of L1 token 146 | function getTokenDepositLimitData(address _l1Token) external view returns (Deposit memory) { 147 | return tokenDeposit[_l1Token]; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /l1/contracts/common/AllowListed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "./interfaces/IAllowList.sol"; 6 | 7 | /// @author Matter Labs 8 | abstract contract AllowListed { 9 | modifier senderCanCallFunction(IAllowList _allowList) { 10 | // Preventing the stack too deep error 11 | { 12 | require(_allowList.canCall(msg.sender, address(this), msg.sig), "nr"); 13 | } 14 | _; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /l1/contracts/common/Dependencies.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 6 | -------------------------------------------------------------------------------- /l1/contracts/common/L2ContractAddresses.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /// @dev The address of the L2 deployer system contract. 6 | address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(0x8006); 7 | 8 | /// @dev The special reserved L2 address. It is located in the system contracts space but doesn't have deployed bytecode. 9 | /// @dev The L2 deployer system contract allows changing bytecodes on any address if the `msg.sender` is this address. 10 | /// @dev So, whenever the governor wants to redeploy system contracts, it just initiates the L1 upgrade call deployer system contract 11 | /// via the L1 -> L2 transaction with `sender == L2_FORCE_DEPLOYER_ADDR`. For more details see the `diamond-initializers` contracts. 12 | address constant L2_FORCE_DEPLOYER_ADDR = address(0x8007); 13 | 14 | /// @dev The address of the special smart contract that can send arbitrary length message as an L2 log 15 | address constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR = address(0x8008); 16 | 17 | /// @dev The formal address of the initial program of the system: the bootloader 18 | address constant L2_BOOTLOADER_ADDRESS = address(0x8001); 19 | 20 | /// @dev The address of the eth token system contract 21 | address constant L2_ETH_TOKEN_SYSTEM_CONTRACT_ADDR = address(0x800a); 22 | 23 | /// @dev The address of the known code storage system contract 24 | address constant L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR = address(0x8004); 25 | 26 | /// @dev The address of the context system contract 27 | address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(0x800b); 28 | -------------------------------------------------------------------------------- /l1/contracts/common/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /** 6 | * @dev Contract module that helps prevent reentrant calls to a function. 7 | * 8 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 9 | * available, which can be applied to functions to make sure there are no nested 10 | * (reentrant) calls to them. 11 | * 12 | * Note that because there is a single `nonReentrant` guard, functions marked as 13 | * `nonReentrant` may not call one another. This can be worked around by making 14 | * those functions `private`, and then adding `external` `nonReentrant` entry 15 | * points to them. 16 | * 17 | * TIP: If you would like to learn more about reentrancy and alternative ways 18 | * to protect against it, check out our blog post 19 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 20 | * 21 | * _Since v2.5.0:_ this module is now much more gas efficient, given net gas 22 | * metering changes introduced in the Istanbul hardfork. 23 | */ 24 | abstract contract ReentrancyGuard { 25 | /// @dev Address of lock flag variable. 26 | /// @dev Flag is placed at random memory location to not interfere with Storage contract. 27 | uint256 private constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4; // keccak256("ReentrancyGuard") - 1; 28 | 29 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/security/ReentrancyGuard.sol 30 | // The values being non-zero value makes deployment a bit more expensive, 31 | // but in exchange the refund on every call to nonReentrant will be lower in 32 | // amount. Since refunds are capped to a percentage of the total 33 | // transaction's gas, it is best to keep them low in cases like this one, to 34 | // increase the likelihood of the full refund coming into effect. 35 | uint256 private constant _NOT_ENTERED = 1; 36 | uint256 private constant _ENTERED = 2; 37 | 38 | modifier reentrancyGuardInitializer() { 39 | _initializeReentrancyGuard(); 40 | _; 41 | } 42 | 43 | function _initializeReentrancyGuard() private { 44 | uint256 lockSlotOldValue; 45 | 46 | // Storing an initial non-zero value makes deployment a bit more 47 | // expensive but in exchange every call to nonReentrant 48 | // will be cheaper. 49 | assembly { 50 | lockSlotOldValue := sload(LOCK_FLAG_ADDRESS) 51 | sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED) 52 | } 53 | 54 | // Check that storage slot for reentrancy guard is empty to rule out possibility of slot conflict 55 | require(lockSlotOldValue == 0, "1B"); 56 | } 57 | 58 | /** 59 | * @dev Prevents a contract from calling itself, directly or indirectly. 60 | * Calling a `nonReentrant` function from another `nonReentrant` 61 | * function is not supported. It is possible to prevent this from happening 62 | * by making the `nonReentrant` function external, and make it call a 63 | * `private` function that does the actual work. 64 | */ 65 | modifier nonReentrant() { 66 | uint256 _status; 67 | assembly { 68 | _status := sload(LOCK_FLAG_ADDRESS) 69 | } 70 | 71 | // On the first call to nonReentrant, _notEntered will be true 72 | require(_status == _NOT_ENTERED, "r1"); 73 | 74 | // Any calls to nonReentrant after this point will fail 75 | assembly { 76 | sstore(LOCK_FLAG_ADDRESS, _ENTERED) 77 | } 78 | 79 | _; 80 | 81 | // By storing the original value once again, a refund is triggered (see 82 | // https://eips.ethereum.org/EIPS/eip-2200) 83 | assembly { 84 | sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /l1/contracts/common/interfaces/IAllowList.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | interface IAllowList { 6 | /*////////////////////////////////////////////////////////////// 7 | EVENTS 8 | //////////////////////////////////////////////////////////////*/ 9 | 10 | /// @notice Access mode of target contract is changed 11 | event UpdateAccessMode(address indexed target, AccessMode previousMode, AccessMode newMode); 12 | 13 | /// @notice Permission to call is changed 14 | event UpdateCallPermission(address indexed caller, address indexed target, bytes4 indexed functionSig, bool status); 15 | 16 | /// @notice Type of access to a specific contract includes three different modes 17 | /// @param Closed No one has access to the contract 18 | /// @param SpecialAccessOnly Any address with granted special access can interact with a contract (see `hasSpecialAccessToCall`) 19 | /// @param Public Everyone can interact with a contract 20 | enum AccessMode { 21 | Closed, 22 | SpecialAccessOnly, 23 | Public 24 | } 25 | 26 | /// @dev A struct that contains deposit limit data of a token 27 | /// @param depositLimitation Whether any deposit limitation is placed or not 28 | /// @param depositCap The maximum amount that can be deposited. 29 | struct Deposit { 30 | bool depositLimitation; 31 | uint256 depositCap; 32 | } 33 | 34 | /*////////////////////////////////////////////////////////////// 35 | GETTERS 36 | //////////////////////////////////////////////////////////////*/ 37 | 38 | function getAccessMode(address _target) external view returns (AccessMode); 39 | 40 | function hasSpecialAccessToCall( 41 | address _caller, 42 | address _target, 43 | bytes4 _functionSig 44 | ) external view returns (bool); 45 | 46 | function canCall( 47 | address _caller, 48 | address _target, 49 | bytes4 _functionSig 50 | ) external view returns (bool); 51 | 52 | function getTokenDepositLimitData(address _l1Token) external view returns (Deposit memory); 53 | 54 | /*////////////////////////////////////////////////////////////// 55 | ALLOW LIST LOGIC 56 | //////////////////////////////////////////////////////////////*/ 57 | 58 | function setBatchAccessMode(address[] calldata _targets, AccessMode[] calldata _accessMode) external; 59 | 60 | function setAccessMode(address _target, AccessMode _accessMode) external; 61 | 62 | function setBatchPermissionToCall( 63 | address[] calldata _callers, 64 | address[] calldata _targets, 65 | bytes4[] calldata _functionSigs, 66 | bool[] calldata _enables 67 | ) external; 68 | 69 | function setPermissionToCall( 70 | address _caller, 71 | address _target, 72 | bytes4 _functionSig, 73 | bool _enable 74 | ) external; 75 | 76 | /*////////////////////////////////////////////////////////////// 77 | DEPOSIT LIMIT LOGIC 78 | //////////////////////////////////////////////////////////////*/ 79 | 80 | function setDepositLimit( 81 | address _l1Token, 82 | bool _depositLimitation, 83 | uint256 _depositCap 84 | ) external; 85 | } 86 | -------------------------------------------------------------------------------- /l1/contracts/common/interfaces/IL2ContractDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @notice System smart contract that is responsible for deploying other smart contracts on zkSync. 8 | */ 9 | interface IL2ContractDeployer { 10 | /// @notice A struct that describes a forced deployment on an address. 11 | /// @param bytecodeHash The bytecode hash to put on an address. 12 | /// @param newAddress The address on which to deploy the bytecodehash to. 13 | /// @param callConstructor Whether to run the constructor on the force deployment. 14 | /// @param value The `msg.value` with which to initialize a contract. 15 | /// @param input The constructor calldata. 16 | struct ForceDeployment { 17 | bytes32 bytecodeHash; 18 | address newAddress; 19 | bool callConstructor; 20 | uint256 value; 21 | bytes input; 22 | } 23 | 24 | /// @notice This method is to be used only during an upgrade to set bytecodes on specific addresses. 25 | function forceDeployOnAddresses(ForceDeployment[] calldata _deployParams) external; 26 | 27 | /// @notice Deploys a contract with similar address derivation rules to the EVM's `CREATE2` opcode. 28 | /// @param _salt The create2 salt. 29 | /// @param _bytecodeHash The correctly formatted hash of the bytecode. 30 | /// @param _input The constructor calldata. 31 | function create2( 32 | bytes32 _salt, 33 | bytes32 _bytecodeHash, 34 | bytes calldata _input 35 | ) external; 36 | } 37 | -------------------------------------------------------------------------------- /l1/contracts/common/libraries/L2ContractHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @notice Helper library for working with L2 contracts on L1. 8 | */ 9 | library L2ContractHelper { 10 | /// @dev The prefix used to create CREATE2 addresses. 11 | bytes32 constant CREATE2_PREFIX = keccak256("zksyncCreate2"); 12 | 13 | /// @notice Validate the bytecode format and calculate its hash. 14 | /// @param _bytecode The bytecode to hash. 15 | /// @return hashedBytecode The 32-byte hash of the bytecode. 16 | /// Note: The function reverts the execution if the bytecode has non expected format: 17 | /// - Bytecode bytes length is not a multiple of 32 18 | /// - Bytecode bytes length is not less than 2^21 bytes (2^16 words) 19 | /// - Bytecode words length is not odd 20 | function hashL2Bytecode(bytes memory _bytecode) internal pure returns (bytes32 hashedBytecode) { 21 | // Note that the length of the bytecode must be provided in 32-byte words. 22 | require(_bytecode.length % 32 == 0, "po"); 23 | 24 | uint256 bytecodeLenInWords = _bytecode.length / 32; 25 | require(bytecodeLenInWords < 2**16, "pp"); // bytecode length must be less than 2^16 words 26 | require(bytecodeLenInWords % 2 == 1, "pr"); // bytecode length in words must be odd 27 | hashedBytecode = sha256(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 28 | // Setting the version of the hash 29 | hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); 30 | // Setting the length 31 | hashedBytecode = hashedBytecode | bytes32(bytecodeLenInWords << 224); 32 | } 33 | 34 | /// @notice Validates the format of the given bytecode hash. 35 | /// @dev Due to the specification of the L2 bytecode hash, not every 32 bytes could be a legit bytecode hash. 36 | /// @dev The function reverts on invalid bytecode hash formam. 37 | /// @param _bytecodeHash The hash of the bytecode to validate. 38 | function validateBytecodeHash(bytes32 _bytecodeHash) internal pure { 39 | uint8 version = uint8(_bytecodeHash[0]); 40 | require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf"); // Incorrectly formatted bytecodeHash 41 | 42 | require(_bytecodeLen(_bytecodeHash) % 2 == 1, "uy"); // Code length in words must be odd 43 | } 44 | 45 | /// @notice Returns the length of the bytecode associated with the given hash. 46 | /// @param _bytecodeHash The hash of the bytecode. 47 | /// @return codeLengthInWords The length of the bytecode in words. 48 | function _bytecodeLen(bytes32 _bytecodeHash) private pure returns (uint256 codeLengthInWords) { 49 | codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3])); 50 | } 51 | 52 | /// @notice Computes the create2 address for a Layer 2 contract. 53 | /// @param _sender The address of the sender. 54 | /// @param _salt The salt value to use in the create2 address computation. 55 | /// @param _bytecodeHash The contract bytecode hash. 56 | /// @param _constructorInputHash The hash of the constructor input data. 57 | /// @return The create2 address of the contract. 58 | /// NOTE: L2 create2 derivation is different from L1 derivation! 59 | function computeCreate2Address( 60 | address _sender, 61 | bytes32 _salt, 62 | bytes32 _bytecodeHash, 63 | bytes32 _constructorInputHash 64 | ) internal pure returns (address) { 65 | bytes32 senderBytes = bytes32(uint256(uint160(_sender))); 66 | bytes32 data = keccak256( 67 | bytes.concat(CREATE2_PREFIX, senderBytes, _salt, _bytecodeHash, _constructorInputHash) 68 | ); 69 | 70 | return address(uint160(uint256(data))); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /l1/contracts/common/libraries/UncheckedMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | library UncheckedMath { 6 | function uncheckedInc(uint256 _number) internal pure returns (uint256) { 7 | unchecked { 8 | return _number + 1; 9 | } 10 | } 11 | 12 | function uncheckedAdd(uint256 _lhs, uint256 _rhs) internal pure returns (uint256) { 13 | unchecked { 14 | return _lhs + _rhs; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /l1/contracts/common/libraries/UnsafeBytes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @dev The library provides a set of functions that help read data from an "abi.encodePacked" byte array. 8 | * @dev Each of the functions accepts the `bytes memory` and the offset where data should be read and returns a value of a certain type. 9 | * 10 | * @dev WARNING! 11 | * 1) Functions don't check the length of the bytes array, so it can go out of bounds. 12 | * The user of the library must check for bytes length before using any functions from the library! 13 | * 14 | * 2) Read variables are not cleaned up - https://docs.soliditylang.org/en/v0.8.16/internals/variable_cleanup.html. 15 | * Using data in inline assembly can lead to unexpected behavior! 16 | */ 17 | library UnsafeBytes { 18 | function readUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32 result, uint256 offset) { 19 | assembly { 20 | offset := add(_start, 4) 21 | result := mload(add(_bytes, offset)) 22 | } 23 | } 24 | 25 | function readAddress(bytes memory _bytes, uint256 _start) internal pure returns (address result, uint256 offset) { 26 | assembly { 27 | offset := add(_start, 20) 28 | result := mload(add(_bytes, offset)) 29 | } 30 | } 31 | 32 | function readUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256 result, uint256 offset) { 33 | assembly { 34 | offset := add(_start, 32) 35 | result := mload(add(_bytes, offset)) 36 | } 37 | } 38 | 39 | function readBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32 result, uint256 offset) { 40 | assembly { 41 | offset := add(_start, 32) 42 | result := mload(add(_bytes, offset)) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /l1/contracts/vendor/AddressAliasHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | /* 4 | * Copyright 2019-2021, Offchain Labs, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | pragma solidity ^0.8.0; 20 | 21 | library AddressAliasHelper { 22 | uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); 23 | 24 | /// @notice Utility function converts the address that submitted a tx 25 | /// to the inbox on L1 to the msg.sender viewed on L2 26 | /// @param l1Address the address in the L1 that triggered the tx to L2 27 | /// @return l2Address L2 address as viewed in msg.sender 28 | function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { 29 | unchecked { 30 | l2Address = address(uint160(l1Address) + offset); 31 | } 32 | } 33 | 34 | /// @notice Utility function that converts the msg.sender viewed on L2 to the 35 | /// address that submitted a tx to the inbox on L1 36 | /// @param l2Address L2 address as viewed in msg.sender 37 | /// @return l1Address the address in the L1 that triggered the tx to L2 38 | function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { 39 | unchecked { 40 | l1Address = address(uint160(l2Address) - offset); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /l1/contracts/zksync/Config.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.13; 2 | 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | 7 | /// @dev `keccak256("")` 8 | bytes32 constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; 9 | 10 | /// @dev Bytes in raw L2 log 11 | /// @dev Equal to the bytes size of the tuple - (uint8 ShardId, bool isService, uint16 txNumberInBlock, address sender, bytes32 key, bytes32 value) 12 | uint256 constant L2_TO_L1_LOG_SERIALIZE_SIZE = 88; 13 | 14 | /// @dev The maximum length of the bytes array with L2 -> L1 logs 15 | uint256 constant MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES = 4 + L2_TO_L1_LOG_SERIALIZE_SIZE * 512; 16 | 17 | /// @dev L2 -> L1 logs Merkle tree height 18 | uint256 constant L2_TO_L1_LOG_MERKLE_TREE_HEIGHT = 9; 19 | 20 | /// @dev The value of default leaf hash for L2 -> L1 logs Merkle tree 21 | /// @dev An incomplete fixed-size tree is filled with this value to be a full binary tree 22 | /// @dev Actually equal to the `keccak256(new bytes(L2_TO_L1_LOG_SERIALIZE_SIZE))` 23 | bytes32 constant L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH = 0x72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba; 24 | 25 | /// @dev Number of bytes in a one initial storage change 26 | /// @dev Equal to the bytes size of the tuple - (bytes32 key, bytes32 value) 27 | uint256 constant INITIAL_STORAGE_CHANGE_SERIALIZE_SIZE = 64; 28 | 29 | /// @dev The maximum length of the bytes array with initial storage changes 30 | uint256 constant MAX_INITIAL_STORAGE_CHANGES_COMMITMENT_BYTES = 4 + INITIAL_STORAGE_CHANGE_SERIALIZE_SIZE * 4765; 31 | 32 | /// @dev Number of bytes in a one repeated storage change 33 | /// @dev Equal to the bytes size of the tuple - (bytes8 key, bytes32 value) 34 | uint256 constant REPEATED_STORAGE_CHANGE_SERIALIZE_SIZE = 40; 35 | 36 | /// @dev The maximum length of the bytes array with repeated storage changes 37 | uint256 constant MAX_REPEATED_STORAGE_CHANGES_COMMITMENT_BYTES = 4 + REPEATED_STORAGE_CHANGE_SERIALIZE_SIZE * 7564; 38 | 39 | // TODO: change constant to the real root hash of empty Merkle tree (SMA-184) 40 | bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0); 41 | 42 | /// @dev Denotes the first byte of the zkSync transaction that came from L1. 43 | uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255; 44 | 45 | /// @dev The amount of time in seconds the validator has to process the priority transaction 46 | /// NOTE: The constant is set to zero for the Alpha release period 47 | uint256 constant PRIORITY_EXPIRATION = 0 days; 48 | 49 | /// @dev Notice period before activation preparation status of upgrade mode (in seconds) 50 | /// @dev NOTE: we must reserve for users enough time to send full exit operation, wait maximum time for processing this operation and withdraw funds from it. 51 | uint256 constant UPGRADE_NOTICE_PERIOD = 0; 52 | 53 | /// @dev Timestamp - seconds since unix epoch 54 | uint256 constant COMMIT_TIMESTAMP_NOT_OLDER = 365 days; 55 | 56 | /// @dev Maximum available error between real commit block timestamp and analog used in the verifier (in seconds) 57 | /// @dev Must be used cause miner's `block.timestamp` value can differ on some small value (as we know - 15 seconds) 58 | uint256 constant COMMIT_TIMESTAMP_APPROXIMATION_DELTA = 365 days; 59 | 60 | /// @dev Bit mask to apply for verifier public input before verifying. 61 | uint256 constant INPUT_MASK = 452312848583266388373324160190187140051835877600158453279131187530910662655; 62 | 63 | /// @dev The maximum number of L2 gas that a user can request for an L2 transaction 64 | uint256 constant L2_TX_MAX_GAS_LIMIT = 80000000; 65 | 66 | /// @dev The maximum number of the pubdata an L2 operation should be allowed to use. 67 | uint256 constant MAX_PUBDATA_PER_BLOCK = 110000; 68 | 69 | /// @dev The maximum number of the pubdata an priority operation should be allowed to use. 70 | /// For now, it is somewhat lower than the maximum number of pubdata allowed for an L2 transaction, 71 | /// to ensure that the transaction is definitely processable on L2 despite any potential overhead. 72 | uint256 constant PRIORITY_TX_MAX_PUBDATA = 99000; 73 | 74 | /// @dev The default price per L2 gas to be used for L1->L2 transactions 75 | uint256 constant FAIR_L2_GAS_PRICE = 500000000; 76 | 77 | /// @dev Even though the price for 1 byte of pubdata is 16 L1 gas, we have a slightly increased 78 | /// value. 79 | uint256 constant L1_GAS_PER_PUBDATA_BYTE = 17; 80 | 81 | /// @dev The computational overhead of processing an L2 block. 82 | uint256 constant BLOCK_OVERHEAD_L2_GAS = 1200000; 83 | 84 | /// @dev The overhead in L1 gas of interacting with the L1 85 | uint256 constant BLOCK_OVERHEAD_L1_GAS = 1000000; 86 | 87 | /// @dev The equivalent in L1 pubdata of L1 gas used for working with L1 88 | uint256 constant BLOCK_OVERHEAD_PUBDATA = BLOCK_OVERHEAD_L1_GAS / L1_GAS_PER_PUBDATA_BYTE; 89 | 90 | /// @dev The maximum number of transactions in L2 block: 91 | uint256 constant MAX_TRANSACTIONS_IN_BLOCK = 1024; 92 | 93 | /// @dev The size of the bootloader memory dedicated to the encodings of transactions 94 | uint256 constant BOOTLOADER_TX_ENCODING_SPACE = 485225; 95 | 96 | /// @dev The intrinsic cost of the L1->l2 transaction in computational L2 gas 97 | uint256 constant L1_TX_INTRINSIC_L2_GAS = 167157; 98 | 99 | /// @dev The intrinsic cost of the L1->l2 transaction in pubdata 100 | uint256 constant L1_TX_INTRINSIC_PUBDATA = 88; 101 | 102 | /// @dev The minimal base price for L1 transaction 103 | uint256 constant L1_TX_MIN_L2_GAS_BASE = 173484; 104 | 105 | /// @dev The number of L2 gas the transaction starts costing more with each 544 bytes of encoding 106 | uint256 constant L1_TX_DELTA_544_ENCODING_BYTES = 1656; 107 | 108 | /// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency 109 | uint256 constant L1_TX_DELTA_FACTORY_DEPS_L2_GAS = 2473; 110 | 111 | /// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency 112 | uint256 constant L1_TX_DELTA_FACTORY_DEPS_PUBDATA = 64; 113 | 114 | /// @dev The number of pubdata an L1->L2 transaction requires with each new factory dependency 115 | uint256 constant MAX_NEW_FACTORY_DEPS = 32; 116 | 117 | /// @dev The L2 gasPricePerPubdata required to be used in bridges. 118 | uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = 800; 119 | -------------------------------------------------------------------------------- /l1/contracts/zksync/DiamondInit.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.13; 2 | 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | 7 | import "../common/interfaces/IAllowList.sol"; 8 | import "./interfaces/IExecutor.sol"; 9 | import "./libraries/Diamond.sol"; 10 | import "./facets/Base.sol"; 11 | import "./Config.sol"; 12 | 13 | /// @author Matter Labs 14 | /// @dev The contract is used only once to initialize the diamond proxy. 15 | /// @dev The deployment process takes care of this contract's initialization. 16 | contract DiamondInit is Base { 17 | /// @dev Initialize the implementation to prevent any possibility of a Parity hack. 18 | constructor() reentrancyGuardInitializer {} 19 | 20 | /// @notice zkSync contract initialization 21 | /// @param _verifier address of Verifier contract 22 | /// @param _governor address who can manage the contract 23 | /// @param _validator address who can make blocks 24 | /// @param _genesisBlockHash Block hash of the genesis (initial) block 25 | /// @param _genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for genesis block 26 | /// @param _genesisBlockCommitment The zk-proof commitment for the genesis block 27 | /// @param _allowList The address of the allow list smart contract 28 | /// @param _verifierParams Verifier config parameters that describes the circuit to be verified 29 | /// @param _zkPorterIsAvailable The availability of zk porter shard 30 | /// @param _l2BootloaderBytecodeHash The hash of bootloader L2 bytecode 31 | /// @param _l2DefaultAccountBytecodeHash The hash of default account L2 bytecode 32 | /// @param _priorityTxMaxGasLimit maximum number of the L2 gas that a user can request for L1 -> L2 transactions 33 | /// @return Magic 32 bytes, which indicates that the contract logic is expected to be used as a diamond proxy initializer 34 | function initialize( 35 | Verifier _verifier, 36 | address _governor, 37 | address _validator, 38 | bytes32 _genesisBlockHash, 39 | uint64 _genesisIndexRepeatedStorageChanges, 40 | bytes32 _genesisBlockCommitment, 41 | IAllowList _allowList, 42 | VerifierParams calldata _verifierParams, 43 | bool _zkPorterIsAvailable, 44 | bytes32 _l2BootloaderBytecodeHash, 45 | bytes32 _l2DefaultAccountBytecodeHash, 46 | uint256 _priorityTxMaxGasLimit 47 | ) external reentrancyGuardInitializer returns (bytes32) { 48 | require(address(_verifier) != address(0), "vt"); 49 | require(_governor != address(0), "vy"); 50 | 51 | s.verifier = _verifier; 52 | s.governor = _governor; 53 | s.validators[_validator] = true; 54 | 55 | // We need to initialize the state hash because it is used in the commitment of the next block 56 | IExecutor.StoredBlockInfo memory storedBlockZero = IExecutor.StoredBlockInfo( 57 | 0, 58 | _genesisBlockHash, 59 | _genesisIndexRepeatedStorageChanges, 60 | 0, 61 | EMPTY_STRING_KECCAK, 62 | DEFAULT_L2_LOGS_TREE_ROOT_HASH, 63 | 0, 64 | _genesisBlockCommitment 65 | ); 66 | 67 | s.storedBlockHashes[0] = keccak256(abi.encode(storedBlockZero)); 68 | s.allowList = _allowList; 69 | s.verifierParams = _verifierParams; 70 | s.zkPorterIsAvailable = _zkPorterIsAvailable; 71 | s.l2BootloaderBytecodeHash = _l2BootloaderBytecodeHash; 72 | s.l2DefaultAccountBytecodeHash = _l2DefaultAccountBytecodeHash; 73 | s.priorityTxMaxGasLimit = _priorityTxMaxGasLimit; 74 | 75 | return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /l1/contracts/zksync/DiamondProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.13; 2 | 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | 7 | import "./libraries/Diamond.sol"; 8 | 9 | /// @title Diamond Proxy Contract (EIP-2535) 10 | /// @author Matter Labs 11 | contract DiamondProxy { 12 | constructor(uint256 _chainId, Diamond.DiamondCutData memory _diamondCut) { 13 | // Check that the contract is deployed on the expected chain. 14 | // Thus, the contract deployed by the same Create2 factory on the different chain will have different addresses! 15 | require(_chainId == block.chainid, "pr"); 16 | Diamond.diamondCut(_diamondCut); 17 | } 18 | 19 | /// @dev 1. Find the facet for the function that is called. 20 | /// @dev 2. Delegate the execution to the found facet via `delegatecall`. 21 | fallback() external payable { 22 | Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage(); 23 | // Check whether the data contains a "full" selector or it is empty. 24 | // Required because Diamond proxy finds a facet by function signature, 25 | // which is not defined for data length in range [1, 3]. 26 | require(msg.data.length >= 4 || msg.data.length == 0, "Ut"); 27 | // Get facet from function selector 28 | Diamond.SelectorToFacet memory facet = diamondStorage.selectorToFacet[msg.sig]; 29 | address facetAddress = facet.facetAddress; 30 | 31 | require(facetAddress != address(0), "F"); // Proxy has no facet for this selector 32 | require(!diamondStorage.isFrozen || !facet.isFreezable, "q1"); // Facet is frozen 33 | 34 | assembly { 35 | // The pointer to the free memory slot 36 | let ptr := mload(0x40) 37 | // Copy function signature and arguments from calldata at zero position into memory at pointer position 38 | calldatacopy(ptr, 0, calldatasize()) 39 | // Delegatecall method of the implementation contract returns 0 on error 40 | let result := delegatecall(gas(), facetAddress, ptr, calldatasize(), 0, 0) 41 | // Get the size of the last return data 42 | let size := returndatasize() 43 | // Copy the size length of bytes from return data at zero position to pointer position 44 | returndatacopy(ptr, 0, size) 45 | // Depending on the result value 46 | switch result 47 | case 0 { 48 | // End execution and revert state changes 49 | revert(ptr, size) 50 | } 51 | default { 52 | // Return data with length of size at pointers position 53 | return(ptr, size) 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /l1/contracts/zksync/Storage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "./Verifier.sol"; 6 | import "../common/interfaces/IAllowList.sol"; 7 | import "./libraries/PriorityQueue.sol"; 8 | 9 | /// @notice Indicates whether an upgrade is initiated and if yes what type 10 | /// @param None Upgrade is NOT initiated 11 | /// @param Transparent Fully transparent upgrade is initiated, upgrade data is publicly known 12 | /// @param Shadow Shadow upgrade is initiated, upgrade data is hidden 13 | enum UpgradeState { 14 | None, 15 | Transparent, 16 | Shadow 17 | } 18 | 19 | /// @dev Logically separated part of the storage structure, which is responsible for everything related to proxy upgrades and diamond cuts 20 | /// @param proposedUpgradeHash The hash of the current upgrade proposal, zero if there is no active proposal 21 | /// @param state Indicates whether an upgrade is initiated and if yes what type 22 | /// @param securityCouncil Address which has the permission to approve instant upgrades (expected to be a Gnosis multisig) 23 | /// @param approvedBySecurityCouncil Indicates whether the security council has approved the upgrade 24 | /// @param proposedUpgradeTimestamp The timestamp when the upgrade was proposed, zero if there are no active proposals 25 | /// @param currentProposalId The serial number of proposed upgrades, increments when proposing a new one 26 | struct UpgradeStorage { 27 | bytes32 proposedUpgradeHash; 28 | UpgradeState state; 29 | address securityCouncil; 30 | bool approvedBySecurityCouncil; 31 | uint40 proposedUpgradeTimestamp; 32 | uint40 currentProposalId; 33 | } 34 | 35 | /// @dev The log passed from L2 36 | /// @param l2ShardId The shard identifier, 0 - rollup, 1 - porter. All other values are not used but are reserved for the future 37 | /// @param isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address. 38 | /// This field is required formally but does not have any special meaning. 39 | /// @param txNumberInBlock The L2 transaction number in a block, in which the log was sent 40 | /// @param sender The L2 address which sent the log 41 | /// @param key The 32 bytes of information that was sent in the log 42 | /// @param value The 32 bytes of information that was sent in the log 43 | // Both `key` and `value` are arbitrary 32-bytes selected by the log sender 44 | struct L2Log { 45 | uint8 l2ShardId; 46 | bool isService; 47 | uint16 txNumberInBlock; 48 | address sender; 49 | bytes32 key; 50 | bytes32 value; 51 | } 52 | 53 | /// @dev An arbitrary length message passed from L2 54 | /// @notice Under the hood it is `L2Log` sent from the special system L2 contract 55 | /// @param txNumberInBlock The L2 transaction number in a block, in which the message was sent 56 | /// @param sender The address of the L2 account from which the message was passed 57 | /// @param data An arbitrary length message 58 | struct L2Message { 59 | uint16 txNumberInBlock; 60 | address sender; 61 | bytes data; 62 | } 63 | 64 | /// @notice Part of the configuration parameters of ZKP circuits 65 | struct VerifierParams { 66 | bytes32 recursionNodeLevelVkHash; 67 | bytes32 recursionLeafLevelVkHash; 68 | bytes32 recursionCircuitsSetVksHash; 69 | } 70 | 71 | /// @dev storing all storage variables for zkSync facets 72 | /// NOTE: It is used in a proxy, so it is possible to add new variables to the end 73 | /// NOTE: but NOT to modify already existing variables or change their order 74 | /// NOTE: DiamondCutStorage is unused, but it must remain a member of AppStorage to not have storage collision 75 | /// NOTE: instead UpgradeStorage is used that is appended to the end of the AppStorage struct 76 | struct AppStorage { 77 | /// @dev Storage of variables needed for deprecated diamond cut facet 78 | uint256[7] __DEPRECATED_diamondCutStorage; 79 | /// @notice Address which will exercise governance over the network i.e. change validator set, conduct upgrades 80 | address governor; 81 | /// @notice Address that the governor proposed as one that will replace it 82 | address pendingGovernor; 83 | /// @notice List of permitted validators 84 | mapping(address => bool) validators; 85 | /// @dev Verifier contract. Used to verify aggregated proof for blocks 86 | Verifier verifier; 87 | /// @notice Total number of executed blocks i.e. blocks[totalBlocksExecuted] points at the latest executed block (block 0 is genesis) 88 | uint256 totalBlocksExecuted; 89 | /// @notice Total number of proved blocks i.e. blocks[totalBlocksProved] points at the latest proved block 90 | uint256 totalBlocksVerified; 91 | /// @notice Total number of committed blocks i.e. blocks[totalBlocksCommitted] points at the latest committed block 92 | uint256 totalBlocksCommitted; 93 | /// @dev Stored hashed StoredBlock for block number 94 | mapping(uint256 => bytes32) storedBlockHashes; 95 | /// @dev Stored root hashes of L2 -> L1 logs 96 | mapping(uint256 => bytes32) l2LogsRootHashes; 97 | /// @dev Container that stores transactions requested from L1 98 | PriorityQueue.Queue priorityQueue; 99 | /// @dev The smart contract that manages the list with permission to call contract functions 100 | IAllowList allowList; 101 | /// @notice Part of the configuration parameters of ZKP circuits. Used as an input for the verifier smart contract 102 | VerifierParams verifierParams; 103 | /// @notice Bytecode hash of bootloader program. 104 | /// @dev Used as an input to zkp-circuit. 105 | bytes32 l2BootloaderBytecodeHash; 106 | /// @notice Bytecode hash of default account (bytecode for EOA). 107 | /// @dev Used as an input to zkp-circuit. 108 | bytes32 l2DefaultAccountBytecodeHash; 109 | /// @dev Indicates that the porter may be touched on L2 transactions. 110 | /// @dev Used as an input to zkp-circuit. 111 | bool zkPorterIsAvailable; 112 | /// @dev The maximum number of the L2 gas that a user can request for L1 -> L2 transactions 113 | /// @dev This is the maximum number of L2 gas that is available for the "body" of the transaction, i.e. 114 | /// without overhead for proving the block. 115 | uint256 priorityTxMaxGasLimit; 116 | /// @dev Storage of variables needed for upgrade facet 117 | UpgradeStorage upgrades; 118 | /// @dev A mapping L2 block number => message number => flag. 119 | /// @dev The L2 -> L1 log is sent for every withdrawal, so this mapping is serving as 120 | /// a flag to indicate that the message was already processed. 121 | /// @dev Used to indicate that eth withdrawal was already processed 122 | mapping(uint256 => mapping(uint256 => bool)) isEthWithdrawalFinalized; 123 | /// @dev The most recent withdrawal time and amount reset 124 | uint256 __DEPRECATED_lastWithdrawalLimitReset; 125 | /// @dev The accumulated withdrawn amount during the withdrawal limit window 126 | uint256 __DEPRECATED_withdrawnAmountInWindow; 127 | /// @dev A mapping user address => the total deposited amount by the user 128 | mapping(address => uint256) totalDepositedAmountPerUser; 129 | } 130 | -------------------------------------------------------------------------------- /l1/contracts/zksync/facets/Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../Storage.sol"; 6 | import "../../common/ReentrancyGuard.sol"; 7 | import "../../common/AllowListed.sol"; 8 | 9 | /// @title Base contract containing functions accessible to the other facets. 10 | /// @author Matter Labs 11 | contract Base is ReentrancyGuard, AllowListed { 12 | AppStorage internal s; 13 | 14 | /// @notice Checks that the message sender is an active governor 15 | modifier onlyGovernor() { 16 | require(msg.sender == s.governor, "1g"); // only by governor 17 | _; 18 | } 19 | 20 | /// @notice Checks if validator is active 21 | modifier onlyValidator() { 22 | require(s.validators[msg.sender], "1h"); // validator is not active 23 | _; 24 | } 25 | 26 | modifier onlySecurityCouncil() { 27 | require(msg.sender == s.upgrades.securityCouncil, "a9"); // not a security council 28 | _; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /l1/contracts/zksync/facets/Governance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../interfaces/IGovernance.sol"; 6 | import "../../common/libraries/L2ContractHelper.sol"; 7 | import "./Base.sol"; 8 | 9 | /// @title Governance Contract controls access rights for contract management. 10 | /// @author Matter Labs 11 | contract GovernanceFacet is Base, IGovernance { 12 | /// @notice Starts the transfer of governor rights. Only the current governor can propose a new pending one. 13 | /// @notice New governor can accept governor rights by calling `acceptGovernor` function. 14 | /// @param _newPendingGovernor Address of the new governor 15 | function setPendingGovernor(address _newPendingGovernor) external onlyGovernor { 16 | // Save previous value into the stack to put it into the event later 17 | address oldPendingGovernor = s.pendingGovernor; 18 | 19 | if (oldPendingGovernor != _newPendingGovernor) { 20 | // Change pending governor 21 | s.pendingGovernor = _newPendingGovernor; 22 | 23 | emit NewPendingGovernor(oldPendingGovernor, _newPendingGovernor); 24 | } 25 | } 26 | 27 | /// @notice Accepts transfer of admin rights. Only pending governor can accept the role. 28 | function acceptGovernor() external { 29 | address pendingGovernor = s.pendingGovernor; 30 | require(msg.sender == pendingGovernor, "n4"); // Only proposed by current governor address can claim the governor rights 31 | 32 | if (pendingGovernor != s.governor) { 33 | address previousGovernor = s.governor; 34 | s.governor = pendingGovernor; 35 | delete s.pendingGovernor; 36 | 37 | emit NewPendingGovernor(pendingGovernor, address(0)); 38 | emit NewGovernor(previousGovernor, pendingGovernor); 39 | } 40 | } 41 | 42 | /// @notice Change validator status (active or not active) 43 | /// @param _validator Validator address 44 | /// @param _active Active flag 45 | function setValidator(address _validator, bool _active) external onlyGovernor { 46 | if (s.validators[_validator] != _active) { 47 | s.validators[_validator] = _active; 48 | emit ValidatorStatusUpdate(_validator, _active); 49 | } 50 | } 51 | 52 | /// @notice Change bootloader bytecode hash, that is used on L2 53 | /// @param _l2BootloaderBytecodeHash The hash of bootloader L2 bytecode 54 | function setL2BootloaderBytecodeHash(bytes32 _l2BootloaderBytecodeHash) external onlyGovernor { 55 | L2ContractHelper.validateBytecodeHash(_l2BootloaderBytecodeHash); 56 | 57 | // Save previous value into the stack to put it into the event later 58 | bytes32 previousBootloaderBytecodeHash = s.l2BootloaderBytecodeHash; 59 | 60 | if (previousBootloaderBytecodeHash != _l2BootloaderBytecodeHash) { 61 | // Change the bootloader bytecode hash 62 | s.l2BootloaderBytecodeHash = _l2BootloaderBytecodeHash; 63 | emit NewL2BootloaderBytecodeHash(previousBootloaderBytecodeHash, _l2BootloaderBytecodeHash); 64 | } 65 | } 66 | 67 | /// @notice Change default account bytecode hash, that is used on L2 68 | /// @param _l2DefaultAccountBytecodeHash The hash of default account L2 bytecode 69 | function setL2DefaultAccountBytecodeHash(bytes32 _l2DefaultAccountBytecodeHash) external onlyGovernor { 70 | L2ContractHelper.validateBytecodeHash(_l2DefaultAccountBytecodeHash); 71 | 72 | // Save previous value into the stack to put it into the event later 73 | bytes32 previousDefaultAccountBytecodeHash = s.l2DefaultAccountBytecodeHash; 74 | 75 | if (previousDefaultAccountBytecodeHash != _l2DefaultAccountBytecodeHash) { 76 | // Change the default account bytecode hash 77 | s.l2DefaultAccountBytecodeHash = _l2DefaultAccountBytecodeHash; 78 | emit NewL2DefaultAccountBytecodeHash(previousDefaultAccountBytecodeHash, _l2DefaultAccountBytecodeHash); 79 | } 80 | } 81 | 82 | /// @notice Change zk porter availability 83 | /// @param _zkPorterIsAvailable The availability of zk porter shard 84 | function setPorterAvailability(bool _zkPorterIsAvailable) external onlyGovernor { 85 | if (s.zkPorterIsAvailable != _zkPorterIsAvailable) { 86 | // Change the porter availability 87 | s.zkPorterIsAvailable = _zkPorterIsAvailable; 88 | emit IsPorterAvailableStatusUpdate(_zkPorterIsAvailable); 89 | } 90 | } 91 | 92 | /// @notice Change the address of the verifier smart contract 93 | /// @param _newVerifier Verifier smart contract address 94 | function setVerifier(Verifier _newVerifier) external onlyGovernor { 95 | Verifier oldVerifier = s.verifier; 96 | if (oldVerifier != _newVerifier) { 97 | s.verifier = _newVerifier; 98 | emit NewVerifier(address(oldVerifier), address(_newVerifier)); 99 | } 100 | } 101 | 102 | /// @notice Change the verifier parameters 103 | /// @param _newVerifierParams New parameters for the verifier 104 | function setVerifierParams(VerifierParams calldata _newVerifierParams) external onlyGovernor { 105 | VerifierParams memory oldVerifierParams = s.verifierParams; 106 | 107 | s.verifierParams = _newVerifierParams; 108 | emit NewVerifierParams(oldVerifierParams, _newVerifierParams); 109 | } 110 | 111 | /// @notice Change the address of the allow list smart contract 112 | /// @param _newAllowList Allow list smart contract address 113 | function setAllowList(IAllowList _newAllowList) external onlyGovernor { 114 | IAllowList oldAllowList = s.allowList; 115 | if (oldAllowList != _newAllowList) { 116 | s.allowList = _newAllowList; 117 | emit NewAllowList(address(oldAllowList), address(_newAllowList)); 118 | } 119 | } 120 | 121 | /// @notice Change the max L2 gas limit for L1 -> L2 transactions 122 | /// @param _newPriorityTxMaxGasLimit The maximum number of L2 gas that a user can request for L1 -> L2 transactions 123 | function setPriorityTxMaxGasLimit(uint256 _newPriorityTxMaxGasLimit) external onlyGovernor { 124 | uint256 oldPriorityTxMaxGasLimit = s.priorityTxMaxGasLimit; 125 | if (oldPriorityTxMaxGasLimit != _newPriorityTxMaxGasLimit) { 126 | s.priorityTxMaxGasLimit = _newPriorityTxMaxGasLimit; 127 | emit NewPriorityTxMaxGasLimit(oldPriorityTxMaxGasLimit, _newPriorityTxMaxGasLimit); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /l1/contracts/zksync/interfaces/IDiamondCut.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | import "../libraries/Diamond.sol"; 5 | 6 | interface IDiamondCut { 7 | function proposeTransparentUpgrade(Diamond.DiamondCutData calldata _diamondCut, uint40 _proposalId) external; 8 | 9 | function proposeShadowUpgrade(bytes32 _proposalHash, uint40 _proposalId) external; 10 | 11 | function cancelUpgradeProposal(bytes32 _proposedUpgradeHash) external; 12 | 13 | function securityCouncilUpgradeApprove(bytes32 _upgradeProposalHash) external; 14 | 15 | function executeUpgrade(Diamond.DiamondCutData calldata _diamondCut, bytes32 _proposalSalt) external; 16 | 17 | function freezeDiamond() external; 18 | 19 | function unfreezeDiamond() external; 20 | 21 | function upgradeProposalHash( 22 | Diamond.DiamondCutData calldata _diamondCut, 23 | uint256 _proposalId, 24 | bytes32 _salt 25 | ) external pure returns (bytes32); 26 | 27 | event ProposeTransparentUpgrade( 28 | Diamond.DiamondCutData diamondCut, 29 | uint256 indexed proposalId, 30 | bytes32 proposalSalt 31 | ); 32 | 33 | event ProposeShadowUpgrade(uint256 indexed proposalId, bytes32 indexed proposalHash); 34 | 35 | event CancelUpgradeProposal(uint256 indexed proposalId, bytes32 indexed proposalHash); 36 | 37 | event SecurityCouncilUpgradeApprove(uint256 indexed proposalId, bytes32 indexed proposalHash); 38 | 39 | event ExecuteUpgrade(uint256 indexed proposalId, bytes32 indexed proposalHash, bytes32 proposalSalt); 40 | 41 | event Freeze(); 42 | 43 | event Unfreeze(); 44 | } 45 | -------------------------------------------------------------------------------- /l1/contracts/zksync/interfaces/IExecutor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | interface IExecutor { 6 | /// @notice Rollup block stored data 7 | /// @param blockNumber Rollup block number 8 | /// @param blockHash Hash of L2 block 9 | /// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more 10 | /// @param numberOfLayer1Txs Number of priority operations to be processed 11 | /// @param priorityOperationsHash Hash of all priority operations from this block 12 | /// @param l2LogsTreeRoot Root hash of tree that contains L2 -> L1 messages from this block 13 | /// @param timestamp Rollup block timestamp, have the same format as Ethereum block constant 14 | /// @param commitment Verified input for the zkSync circuit 15 | struct StoredBlockInfo { 16 | uint64 blockNumber; 17 | bytes32 blockHash; 18 | uint64 indexRepeatedStorageChanges; 19 | uint256 numberOfLayer1Txs; 20 | bytes32 priorityOperationsHash; 21 | bytes32 l2LogsTreeRoot; 22 | uint256 timestamp; 23 | bytes32 commitment; 24 | } 25 | 26 | /// @notice Data needed to commit new block 27 | /// @param blockNumber Number of the committed block 28 | /// @param timestamp Unix timestamp denoting the start of the block execution 29 | /// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more 30 | /// @param newStateRoot The state root of the full state tree 31 | /// @param numberOfLayer1Txs Number of priority operations to be processed 32 | /// @param l2LogsTreeRoot The root hash of the tree that contains all L2 -> L1 logs in the block 33 | /// @param priorityOperationsHash Hash of all priority operations from this block 34 | /// @param initialStorageChanges Storage write access as a concatenation key-value 35 | /// @param repeatedStorageChanges Storage write access as a concatenation index-value 36 | /// @param l2Logs concatenation of all L2 -> L1 logs in the block 37 | /// @param l2ArbitraryLengthMessages array of hash preimages that were sent as value of L2 logs by special system L2 contract 38 | /// @param factoryDeps array of l2 bytecodes that were marked as known on L2 39 | struct CommitBlockInfo { 40 | uint64 blockNumber; 41 | uint64 timestamp; 42 | uint64 indexRepeatedStorageChanges; 43 | bytes32 newStateRoot; 44 | uint256 numberOfLayer1Txs; 45 | bytes32 l2LogsTreeRoot; 46 | bytes32 priorityOperationsHash; 47 | bytes initialStorageChanges; 48 | bytes repeatedStorageChanges; 49 | bytes l2Logs; 50 | bytes[] l2ArbitraryLengthMessages; 51 | bytes[] factoryDeps; 52 | } 53 | 54 | /// @notice Recursive proof input data (individual commitments are constructed onchain) 55 | struct ProofInput { 56 | uint256[] recursiveAggregationInput; 57 | uint256[] serializedProof; 58 | } 59 | 60 | function commitBlocks(StoredBlockInfo calldata _lastCommittedBlockData, CommitBlockInfo[] calldata _newBlocksData) 61 | external; 62 | 63 | function proveBlocks( 64 | StoredBlockInfo calldata _prevBlock, 65 | StoredBlockInfo[] calldata _committedBlocks, 66 | ProofInput calldata _proof 67 | ) external; 68 | 69 | function executeBlocks(StoredBlockInfo[] calldata _blocksData) external; 70 | 71 | function revertBlocks(uint256 _newLastBlock) external; 72 | 73 | /// @notice Event emitted when a block is committed 74 | event BlockCommit(uint256 indexed blockNumber, bytes32 indexed blockHash, bytes32 indexed commitment); 75 | 76 | /// @notice Event emitted when blocks are verified 77 | event BlocksVerification(uint256 indexed previousLastVerifiedBlock, uint256 indexed currentLastVerifiedBlock); 78 | 79 | /// @notice Event emitted when a block is executed 80 | event BlockExecution(uint256 indexed blockNumber, bytes32 indexed blockHash, bytes32 indexed commitment); 81 | 82 | /// @notice Event emitted when blocks are reverted 83 | event BlocksRevert(uint256 totalBlocksCommitted, uint256 totalBlocksVerified, uint256 totalBlocksExecuted); 84 | } 85 | -------------------------------------------------------------------------------- /l1/contracts/zksync/interfaces/IGetters.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../Storage.sol"; 6 | import "../libraries/PriorityQueue.sol"; 7 | import {VerifierParams} from "../Storage.sol"; 8 | 9 | interface IGetters { 10 | /*////////////////////////////////////////////////////////////// 11 | CUSTOM GETTERS 12 | //////////////////////////////////////////////////////////////*/ 13 | 14 | function getVerifier() external view returns (address); 15 | 16 | function getGovernor() external view returns (address); 17 | 18 | function getPendingGovernor() external view returns (address); 19 | 20 | function getTotalBlocksCommitted() external view returns (uint256); 21 | 22 | function getTotalBlocksVerified() external view returns (uint256); 23 | 24 | function getTotalBlocksExecuted() external view returns (uint256); 25 | 26 | function getTotalPriorityTxs() external view returns (uint256); 27 | 28 | function getFirstUnprocessedPriorityTx() external view returns (uint256); 29 | 30 | function getPriorityQueueSize() external view returns (uint256); 31 | 32 | function priorityQueueFrontOperation() external view returns (PriorityOperation memory); 33 | 34 | function isValidator(address _address) external view returns (bool); 35 | 36 | function l2LogsRootHash(uint256 _blockNumber) external view returns (bytes32 hash); 37 | 38 | function storedBlockHash(uint256 _blockNumber) external view returns (bytes32); 39 | 40 | function getL2BootloaderBytecodeHash() external view returns (bytes32); 41 | 42 | function getL2DefaultAccountBytecodeHash() external view returns (bytes32); 43 | 44 | function getVerifierParams() external view returns (VerifierParams memory); 45 | 46 | function isDiamondStorageFrozen() external view returns (bool); 47 | 48 | function getSecurityCouncil() external view returns (address); 49 | 50 | function getUpgradeProposalState() external view returns (UpgradeState); 51 | 52 | function getProposedUpgradeHash() external view returns (bytes32); 53 | 54 | function getProposedUpgradeTimestamp() external view returns (uint256); 55 | 56 | function getCurrentProposalId() external view returns (uint256); 57 | 58 | function isApprovedBySecurityCouncil() external view returns (bool); 59 | 60 | function getPriorityTxMaxGasLimit() external view returns (uint256); 61 | 62 | function getAllowList() external view returns (address); 63 | 64 | function isEthWithdrawalFinalized(uint256 _l2BlockNumber, uint256 _l2MessageIndex) external view returns (bool); 65 | 66 | /*////////////////////////////////////////////////////////////// 67 | DIAMOND LOUPE 68 | //////////////////////////////////////////////////////////////*/ 69 | 70 | /// @notice Faсet structure compatible with the EIP-2535 diamond loupe 71 | /// @param addr The address of the facet contract 72 | /// @param selectors The NON-sorted array with selectors associated with facet 73 | struct Facet { 74 | address addr; 75 | bytes4[] selectors; 76 | } 77 | 78 | function facets() external view returns (Facet[] memory); 79 | 80 | function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory); 81 | 82 | function facetAddresses() external view returns (address[] memory facets); 83 | 84 | function facetAddress(bytes4 _selector) external view returns (address facet); 85 | 86 | function isFunctionFreezable(bytes4 _selector) external view returns (bool); 87 | 88 | function isFacetFreezable(address _facet) external view returns (bool isFreezable); 89 | } 90 | -------------------------------------------------------------------------------- /l1/contracts/zksync/interfaces/IGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../../common/interfaces/IAllowList.sol"; 6 | import "../Verifier.sol"; 7 | import "../Storage.sol"; 8 | 9 | interface IGovernance { 10 | function setPendingGovernor(address _newPendingGovernor) external; 11 | 12 | function acceptGovernor() external; 13 | 14 | function setValidator(address _validator, bool _active) external; 15 | 16 | function setL2BootloaderBytecodeHash(bytes32 _l2BootloaderBytecodeHash) external; 17 | 18 | function setL2DefaultAccountBytecodeHash(bytes32 _l2DefaultAccountBytecodeHash) external; 19 | 20 | function setPorterAvailability(bool _zkPorterIsAvailable) external; 21 | 22 | function setVerifier(Verifier _newVerifier) external; 23 | 24 | function setVerifierParams(VerifierParams calldata _newVerifierParams) external; 25 | 26 | function setAllowList(IAllowList _newAllowList) external; 27 | 28 | function setPriorityTxMaxGasLimit(uint256 _newPriorityTxMaxGasLimit) external; 29 | 30 | /// @notice Сhanges to the bytecode that is used in L2 as a bootloader (start program) 31 | event NewL2BootloaderBytecodeHash(bytes32 indexed previousBytecodeHash, bytes32 indexed newBytecodeHash); 32 | 33 | /// @notice Сhanges to the bytecode that is used in L2 as a default account 34 | event NewL2DefaultAccountBytecodeHash(bytes32 indexed previousBytecodeHash, bytes32 indexed newBytecodeHash); 35 | 36 | /// @notice Porter availability status changes 37 | event IsPorterAvailableStatusUpdate(bool isPorterAvailable); 38 | 39 | /// @notice Validator's status changed 40 | event ValidatorStatusUpdate(address indexed validatorAddress, bool isActive); 41 | 42 | /// @notice pendingGovernor is changed 43 | /// @dev Also emitted when new governor is accepted and in this case, `newPendingGovernor` would be zero address 44 | event NewPendingGovernor(address indexed oldPendingGovernor, address indexed newPendingGovernor); 45 | 46 | /// @notice Governor changed 47 | event NewGovernor(address indexed oldGovernor, address indexed newGovernor); 48 | 49 | /// @notice Verifier address changed 50 | event NewVerifier(address indexed oldVerifier, address indexed newVerifier); 51 | 52 | /// @notice Verifier address changed 53 | event NewVerifierParams(VerifierParams oldVerifierParams, VerifierParams newVerifierParams); 54 | 55 | /// @notice Allow list address changed 56 | event NewAllowList(address indexed oldAllowList, address indexed newAllowList); 57 | 58 | /// @notice Priority transaction max L2 gas limit changed 59 | event NewPriorityTxMaxGasLimit(uint256 oldPriorityTxMaxGasLimit, uint256 newPriorityTxMaxGasLimit); 60 | } 61 | -------------------------------------------------------------------------------- /l1/contracts/zksync/interfaces/IZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "./IMailbox.sol"; 6 | import "./IGovernance.sol"; 7 | import "./IExecutor.sol"; 8 | import "./IDiamondCut.sol"; 9 | import "./IGetters.sol"; 10 | 11 | interface IZkSync is IMailbox, IGovernance, IExecutor, IDiamondCut, IGetters {} 12 | -------------------------------------------------------------------------------- /l1/contracts/zksync/libraries/Merkle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../../common/libraries/UncheckedMath.sol"; 6 | 7 | /// @author Matter Labs 8 | library Merkle { 9 | using UncheckedMath for uint256; 10 | 11 | /// @dev Calculate Merkle root by the provided Merkle proof. 12 | /// NOTE: When using this function, check that the _path length is equal to the tree height to prevent shorter/longer paths attack 13 | /// @param _path Merkle path from the leaf to the root 14 | /// @param _index Leaf index in the tree 15 | /// @param _itemHash Hash of leaf content 16 | /// @return The Merkle root 17 | function calculateRoot( 18 | bytes32[] calldata _path, 19 | uint256 _index, 20 | bytes32 _itemHash 21 | ) internal pure returns (bytes32) { 22 | uint256 pathLength = _path.length; 23 | require(pathLength > 0, "xc"); 24 | require(pathLength < 256, "bt"); 25 | require(_index < (1 << pathLength), "pz"); 26 | 27 | bytes32 currentHash = _itemHash; 28 | for (uint256 i; i < pathLength; i = i.uncheckedInc()) { 29 | currentHash = (_index % 2 == 0) 30 | ? _efficientHash(currentHash, _path[i]) 31 | : _efficientHash(_path[i], currentHash); 32 | _index /= 2; 33 | } 34 | 35 | return currentHash; 36 | } 37 | 38 | /// @dev Keccak hash of the concatenation of two 32-byte words 39 | function _efficientHash(bytes32 _lhs, bytes32 _rhs) private pure returns (bytes32 result) { 40 | assembly { 41 | mstore(0x00, _lhs) 42 | mstore(0x20, _rhs) 43 | result := keccak256(0x00, 0x40) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /l1/contracts/zksync/libraries/PriorityQueue.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | /// @notice The structure that contains meta information of the L2 transaction that was requested from L1 6 | /// @dev The weird size of fields was selected specifically to minimize the structure storage size 7 | /// @param canonicalTxHash Hashed L2 transaction data that is needed to process it 8 | /// @param expirationTimestamp Expiration timestamp for this request (must be satisfied before) 9 | /// @param layer2Tip Additional payment to the validator as an incentive to perform the operation 10 | struct PriorityOperation { 11 | bytes32 canonicalTxHash; 12 | uint64 expirationTimestamp; 13 | uint192 layer2Tip; 14 | } 15 | 16 | /// @author Matter Labs 17 | /// @dev The library provides the API to interact with the priority queue container 18 | /// @dev Order of processing operations from queue - FIFO (Fist in - first out) 19 | library PriorityQueue { 20 | using PriorityQueue for Queue; 21 | 22 | /// @notice Container that stores priority operations 23 | /// @param data The inner mapping that saves priority operation by its index 24 | /// @param head The pointer to the first unprocessed priority operation, equal to the tail if the queue is empty 25 | /// @param tail The pointer to the free slot 26 | struct Queue { 27 | mapping(uint256 => PriorityOperation) data; 28 | uint256 tail; 29 | uint256 head; 30 | } 31 | 32 | /// @notice Returns zero if and only if no operations were processed from the queue 33 | /// @return Index of the oldest priority operation that wasn't processed yet 34 | function getFirstUnprocessedPriorityTx(Queue storage _queue) internal view returns (uint256) { 35 | return _queue.head; 36 | } 37 | 38 | /// @return The total number of priority operations that were added to the priority queue, including all processed ones 39 | function getTotalPriorityTxs(Queue storage _queue) internal view returns (uint256) { 40 | return _queue.tail; 41 | } 42 | 43 | /// @return The total number of unprocessed priority operations in a priority queue 44 | function getSize(Queue storage _queue) internal view returns (uint256) { 45 | return uint256(_queue.tail - _queue.head); 46 | } 47 | 48 | /// @return Whether the priority queue contains no operations 49 | function isEmpty(Queue storage _queue) internal view returns (bool) { 50 | return _queue.tail == _queue.head; 51 | } 52 | 53 | /// @notice Add the priority operation to the end of the priority queue 54 | function pushBack(Queue storage _queue, PriorityOperation memory _operation) internal { 55 | // Save value into the stack to avoid double reading from the storage 56 | uint256 tail = _queue.tail; 57 | 58 | _queue.data[tail] = _operation; 59 | _queue.tail = tail + 1; 60 | } 61 | 62 | /// @return The first unprocessed priority operation from the queue 63 | function front(Queue storage _queue) internal view returns (PriorityOperation memory) { 64 | require(!_queue.isEmpty(), "D"); // priority queue is empty 65 | 66 | return _queue.data[_queue.head]; 67 | } 68 | 69 | /// @notice Remove the first unprocessed priority operation from the queue 70 | /// @return priorityOperation that was popped from the priority queue 71 | function popFront(Queue storage _queue) internal returns (PriorityOperation memory priorityOperation) { 72 | require(!_queue.isEmpty(), "s"); // priority queue is empty 73 | 74 | // Save value into the stack to avoid double reading from the storage 75 | uint256 head = _queue.head; 76 | 77 | priorityOperation = _queue.data[head]; 78 | delete _queue.data[head]; 79 | _queue.head = head + 1; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /l1/contracts/zksync/libraries/TranscriptLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "./PairingsBn254.sol"; 6 | 7 | library TranscriptLib { 8 | // flip 0xe000000000000000000000000000000000000000000000000000000000000000; 9 | uint256 constant FR_MASK = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; 10 | 11 | uint32 constant DST_0 = 0; 12 | uint32 constant DST_1 = 1; 13 | uint32 constant DST_CHALLENGE = 2; 14 | 15 | struct Transcript { 16 | bytes32 state_0; 17 | bytes32 state_1; 18 | uint32 challenge_counter; 19 | } 20 | 21 | function new_transcript() internal pure returns (Transcript memory t) { 22 | t.state_0 = bytes32(0); 23 | t.state_1 = bytes32(0); 24 | t.challenge_counter = 0; 25 | } 26 | 27 | function update_with_u256(Transcript memory self, uint256 value) internal pure { 28 | bytes32 old_state_0 = self.state_0; 29 | self.state_0 = keccak256(abi.encodePacked(DST_0, old_state_0, self.state_1, value)); 30 | self.state_1 = keccak256(abi.encodePacked(DST_1, old_state_0, self.state_1, value)); 31 | } 32 | 33 | function update_with_fr(Transcript memory self, PairingsBn254.Fr memory value) internal pure { 34 | update_with_u256(self, value.value); 35 | } 36 | 37 | function update_with_g1(Transcript memory self, PairingsBn254.G1Point memory p) internal pure { 38 | update_with_u256(self, p.X); 39 | update_with_u256(self, p.Y); 40 | } 41 | 42 | function get_challenge(Transcript memory self) internal pure returns (PairingsBn254.Fr memory challenge) { 43 | bytes32 query = keccak256(abi.encodePacked(DST_CHALLENGE, self.state_0, self.state_1, self.challenge_counter)); 44 | self.challenge_counter += 1; 45 | challenge = PairingsBn254.Fr({value: uint256(query) & FR_MASK}); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /l1/contracts/zksync/upgrade-initializers/DIamondUpgradeInit2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../Config.sol"; 6 | import "../facets/Mailbox.sol"; 7 | import "../libraries/Diamond.sol"; 8 | import "../../common/libraries/L2ContractHelper.sol"; 9 | import "../../common/L2ContractAddresses.sol"; 10 | 11 | interface IOldContractDeployer { 12 | function forceDeployOnAddress( 13 | bytes32 _bytecodeHash, 14 | address _newAddress, 15 | bytes calldata _input 16 | ) external payable returns (address); 17 | } 18 | 19 | /// @author Matter Labs 20 | contract DiamondUpgradeInit2 is MailboxFacet { 21 | function forceDeploy2( 22 | bytes calldata _upgradeDeployerCalldata, 23 | bytes calldata _upgradeSystemContractsCalldata, 24 | bytes[] calldata _factoryDeps 25 | ) external payable returns (bytes32) { 26 | // 1. Update bytecode for the deployer smart contract 27 | _requestL2Transaction( 28 | L2_FORCE_DEPLOYER_ADDR, 29 | L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, 30 | 0, 31 | _upgradeDeployerCalldata, 32 | 72000000, 33 | REQUIRED_L2_GAS_PRICE_PER_PUBDATA, 34 | _factoryDeps, 35 | true, 36 | address(0) 37 | ); 38 | 39 | // 2. Redeploy other contracts by one transaction 40 | _requestL2Transaction( 41 | L2_FORCE_DEPLOYER_ADDR, 42 | L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, 43 | 0, 44 | _upgradeSystemContractsCalldata, 45 | 72000000, 46 | REQUIRED_L2_GAS_PRICE_PER_PUBDATA, 47 | _factoryDeps, 48 | true, 49 | address(0) 50 | ); 51 | 52 | return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /l1/contracts/zksync/upgrade-initializers/DiamondUpgradeInit1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../facets/Mailbox.sol"; 6 | import "../libraries/Diamond.sol"; 7 | import "../../common/libraries/L2ContractHelper.sol"; 8 | import "../../common/L2ContractAddresses.sol"; 9 | import "../Config.sol"; 10 | 11 | /// @author Matter Labs 12 | contract DiamondUpgradeInit1 is MailboxFacet { 13 | /// @dev Request priority operation on behalf of force deployer address to the deployer system contract 14 | /// @return The message indicating the successful force deployment of contract on L2 15 | function forceDeployL2Contract( 16 | bytes calldata _forceDeployCalldata, 17 | bytes[] calldata _factoryDeps, 18 | uint256 _l2GasLimit 19 | ) external payable returns (bytes32) { 20 | _requestL2Transaction( 21 | L2_FORCE_DEPLOYER_ADDR, 22 | L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, 23 | 0, 24 | _forceDeployCalldata, 25 | _l2GasLimit, 26 | REQUIRED_L2_GAS_PRICE_PER_PUBDATA, 27 | _factoryDeps, 28 | true, 29 | address(0) 30 | ); 31 | 32 | return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /l1/contracts/zksync/upgrade-initializers/DiamondUpgradeInit3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../libraries/Diamond.sol"; 6 | import "../facets/Base.sol"; 7 | 8 | interface IOldDiamondCut { 9 | function proposeDiamondCut(Diamond.FacetCut[] calldata _facetCuts, address _initAddress) external; 10 | 11 | function cancelDiamondCutProposal() external; 12 | 13 | function executeDiamondCutProposal(Diamond.DiamondCutData calldata _diamondCut) external; 14 | 15 | function emergencyFreezeDiamond() external; 16 | 17 | function unfreezeDiamond() external; 18 | 19 | function approveEmergencyDiamondCutAsSecurityCouncilMember(bytes32 _diamondCutHash) external; 20 | 21 | // FIXME: token holders should have the ability to cancel the upgrade 22 | 23 | event DiamondCutProposal(Diamond.FacetCut[] _facetCuts, address _initAddress); 24 | 25 | event DiamondCutProposalCancelation(uint256 currentProposalId, bytes32 indexed proposedDiamondCutHash); 26 | 27 | event DiamondCutProposalExecution(Diamond.DiamondCutData _diamondCut); 28 | 29 | event EmergencyFreeze(); 30 | 31 | event Unfreeze(uint256 lastDiamondFreezeTimestamp); 32 | 33 | event EmergencyDiamondCutApproved( 34 | address indexed _address, 35 | uint256 currentProposalId, 36 | uint256 securityCouncilEmergencyApprovals, 37 | bytes32 indexed proposedDiamondCutHash 38 | ); 39 | } 40 | 41 | /// @author Matter Labs 42 | contract DiamondUpgradeInit3 is Base { 43 | function upgrade( 44 | uint256 _priorityTxMaxGasLimit, 45 | IAllowList _allowList, 46 | Verifier _verifier 47 | ) external payable returns (bytes32) { 48 | // Zero out the deprecated storage slots 49 | delete s.__DEPRECATED_diamondCutStorage; 50 | 51 | s.priorityTxMaxGasLimit = _priorityTxMaxGasLimit; 52 | s.allowList = _allowList; 53 | s.verifier = _verifier; 54 | 55 | return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /l1/contracts/zksync/upgrade-initializers/DiamondUpgradeInit4.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | import "../Config.sol"; 6 | import "../facets/Mailbox.sol"; 7 | import "../libraries/Diamond.sol"; 8 | import "../../common/libraries/L2ContractHelper.sol"; 9 | import "../../common/L2ContractAddresses.sol"; 10 | 11 | interface IOldContractDeployer { 12 | struct ForceDeployment { 13 | bytes32 bytecodeHash; 14 | address newAddress; 15 | uint256 value; 16 | bytes input; 17 | } 18 | 19 | function forceDeployOnAddresses(ForceDeployment[] calldata _deployParams) external; 20 | } 21 | 22 | /// @author Matter Labs 23 | contract DiamondUpgradeInit4 is MailboxFacet { 24 | function forceDeploy2( 25 | bytes calldata _upgradeDeployerCalldata, 26 | bytes calldata _upgradeSystemContractsCalldata, 27 | bytes[] calldata _factoryDeps 28 | ) external payable returns (bytes32) { 29 | // 1. Update bytecode for the deployer smart contract 30 | _requestL2Transaction( 31 | L2_FORCE_DEPLOYER_ADDR, 32 | L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, 33 | 0, 34 | _upgradeDeployerCalldata, 35 | 72000000, 36 | REQUIRED_L2_GAS_PRICE_PER_PUBDATA, 37 | _factoryDeps, 38 | true, 39 | address(0) 40 | ); 41 | 42 | // 2. Redeploy other contracts by one transaction 43 | _requestL2Transaction( 44 | L2_FORCE_DEPLOYER_ADDR, 45 | L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, 46 | 0, 47 | _upgradeSystemContractsCalldata, 48 | 72000000, 49 | REQUIRED_L2_GAS_PRICE_PER_PUBDATA, 50 | _factoryDeps, 51 | true, 52 | address(0) 53 | ); 54 | 55 | return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /l2/contracts/Dependencies.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 6 | -------------------------------------------------------------------------------- /l2/contracts/ExternalDecoder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /// @author Matter Labs 6 | /// @dev The library with which it is possible to use `abi.decode` with error handling. 7 | /// @dev All functions in this library are public and should be called in a try-catch block to handle errors. 8 | library ExternalDecoder { 9 | /// @dev External function to decode a string from bytes. 10 | function decodeString(bytes memory _input) external pure returns (string memory result) { 11 | (result) = abi.decode(_input, (string)); 12 | } 13 | 14 | /// @dev External function to decode a uint8 from bytes. 15 | function decodeUint8(bytes memory _input) external pure returns (uint8 result) { 16 | (result) = abi.decode(_input, (uint8)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /l2/contracts/L2ContractHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IL2Messenger { 6 | function sendToL1(bytes memory _message) external returns (bytes32); 7 | } 8 | 9 | interface IContractDeployer { 10 | function create2( 11 | bytes32 _salt, 12 | bytes32 _bytecodeHash, 13 | bytes calldata _input 14 | ) external; 15 | } 16 | 17 | uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15 18 | 19 | address constant BOOTLOADER_ADDRESS = address(SYSTEM_CONTRACTS_OFFSET + 0x01); 20 | 21 | IL2Messenger constant L2_MESSENGER = IL2Messenger(address(SYSTEM_CONTRACTS_OFFSET + 0x08)); 22 | 23 | library L2ContractHelper { 24 | bytes32 constant CREATE2_PREFIX = keccak256("zksyncCreate2"); 25 | 26 | function sendMessageToL1(bytes memory _message) internal returns (bytes32) { 27 | return L2_MESSENGER.sendToL1(_message); 28 | } 29 | 30 | function computeCreate2Address( 31 | address _sender, 32 | bytes32 _salt, 33 | bytes32 _bytecodeHash, 34 | bytes32 _constructorInputHash 35 | ) internal pure returns (address) { 36 | bytes32 senderBytes = bytes32(uint256(uint160(_sender))); 37 | bytes32 data = keccak256( 38 | bytes.concat(CREATE2_PREFIX, senderBytes, _salt, _bytecodeHash, _constructorInputHash) 39 | ); 40 | 41 | return address(uint160(uint256(data))); 42 | } 43 | } 44 | 45 | struct Transaction { 46 | uint256 txType; 47 | uint256 from; 48 | uint256 to; 49 | uint256 gasLimit; 50 | uint256 gasPerPubdataByteLimit; 51 | uint256 maxFeePerGas; 52 | uint256 maxPriorityFeePerGas; 53 | uint256 paymaster; 54 | uint256 nonce; 55 | uint256 value; 56 | // In the future, we might want to add some 57 | // new fields to the struct. The `txData` struct 58 | // is to be passed to account and any changes to its structure 59 | // would mean a breaking change to these accounts. In order to prevent this, 60 | // we should keep some fields as "reserved". 61 | // It is also recommneded that their length is fixed, since 62 | // it would allow easier proof integration (in case we will need 63 | // some special circuit for preprocessing transactions). 64 | uint256[4] reserved; 65 | bytes data; 66 | bytes signature; 67 | bytes32[] factoryDeps; 68 | bytes paymasterInput; 69 | // Reserved dynamic type for the future use-case. Using it should be avoided, 70 | // But it is still here, just in case we want to enable some additional functionality. 71 | bytes reservedDynamic; 72 | } 73 | -------------------------------------------------------------------------------- /l2/contracts/TestnetPaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import "./interfaces/IPaymaster.sol"; 8 | import "./interfaces/IPaymasterFlow.sol"; 9 | import "./L2ContractHelper.sol"; 10 | 11 | // This is a dummy paymaster. It expects the paymasterInput to contain its "signature" as well as the needed exchange rate. 12 | // It supports only approval-based paymaster flow. 13 | contract TestnetPaymaster is IPaymaster { 14 | function validateAndPayForPaymasterTransaction( 15 | bytes32, 16 | bytes32, 17 | Transaction calldata _transaction 18 | ) external payable returns (bytes4 magic, bytes memory context) { 19 | // By default we consider the transaction as accepted. 20 | magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; 21 | 22 | require(msg.sender == BOOTLOADER_ADDRESS, "Only bootloader can call this contract"); 23 | require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long"); 24 | 25 | bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); 26 | if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { 27 | // While the actual data consists of address, uint256 and bytes data, 28 | // the data is not needed for the testnet paymaster 29 | (address token, uint256 amount, ) = abi.decode(_transaction.paymasterInput[4:], (address, uint256, bytes)); 30 | 31 | // Firstly, we verify that the user has provided enough allowance 32 | address userAddress = address(uint160(_transaction.from)); 33 | address thisAddress = address(this); 34 | 35 | uint256 providedAllowance = IERC20(token).allowance(userAddress, thisAddress); 36 | require(providedAllowance >= amount, "The user did not provide enough allowance"); 37 | 38 | // The testnet paymaster exchanges X wei of the token to the X wei of ETH. 39 | uint256 requiredETH = _transaction.gasLimit * _transaction.maxFeePerGas; 40 | if (amount < requiredETH) { 41 | // Important note: while this clause definitely means that the user 42 | // has underpaid the paymaster and the transaction should not accepted, 43 | // we do not want the transaction to revert, because for fee estimation 44 | // we allow users to provide smaller amount of funds then necessary to preserve 45 | // the property that if using X gas the transaction success, then it will succeed with X+1 gas. 46 | magic = bytes4(0); 47 | } 48 | 49 | // Pulling all the tokens from the user 50 | try IERC20(token).transferFrom(userAddress, thisAddress, amount) {} catch (bytes memory revertReason) { 51 | // If the revert reason is empty or represented by just a function selector, 52 | // we replace the error with a more user-friendly message 53 | if (revertReason.length <= 4) { 54 | revert("Failed to transferFrom from users' account"); 55 | } else { 56 | assembly { 57 | revert(add(0x20, revertReason), mload(revertReason)) 58 | } 59 | } 60 | } 61 | 62 | // The bootloader never returns any data, so it can safely be ignored here. 63 | (bool success, ) = payable(BOOTLOADER_ADDRESS).call{value: requiredETH}(""); 64 | require(success, "Failed to transfer funds to the bootloader"); 65 | } else { 66 | revert("Unsupported paymaster flow"); 67 | } 68 | } 69 | 70 | function postTransaction( 71 | bytes calldata _context, 72 | Transaction calldata _transaction, 73 | bytes32, 74 | bytes32, 75 | ExecutionResult _txResult, 76 | uint256 _maxRefundedGas 77 | ) external payable override { 78 | // Refunds are not supported yet. 79 | } 80 | 81 | receive() external payable {} 82 | } 83 | -------------------------------------------------------------------------------- /l2/contracts/bridge/L2ERC20Bridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; 6 | import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; 7 | 8 | import "./interfaces/IL1Bridge.sol"; 9 | import "./interfaces/IL2Bridge.sol"; 10 | import "./interfaces/IL2StandardToken.sol"; 11 | 12 | import "./L2StandardERC20.sol"; 13 | import "../vendor/AddressAliasHelper.sol"; 14 | import {L2ContractHelper} from "../L2ContractHelper.sol"; 15 | 16 | /// @author Matter Labs 17 | /// @notice The "default" bridge implementation for the ERC20 tokens. 18 | contract L2ERC20Bridge is IL2Bridge, Initializable { 19 | /// @dev The address of the L1 bridge counterpart. 20 | address public override l1Bridge; 21 | 22 | /// @dev Contract that stores the implementation address for token. 23 | /// @dev For more details see https://docs.openzeppelin.com/contracts/3.x/api/proxy#UpgradeableBeacon. 24 | UpgradeableBeacon public l2TokenBeacon; 25 | 26 | /// @dev Bytecode hash of the proxy for tokens deployed by the bridge. 27 | bytes32 l2TokenProxyBytecodeHash; 28 | 29 | /// @dev A mapping l2 token address => l1 token address 30 | mapping(address => address) public override l1TokenAddress; 31 | 32 | /// @dev Contract is expected to be used as proxy implementation. 33 | /// @dev Disable the initialization to prevent Parity hack. 34 | constructor() { 35 | _disableInitializers(); 36 | } 37 | 38 | function initialize( 39 | address _l1Bridge, 40 | bytes32 _l2TokenProxyBytecodeHash, 41 | address _governor 42 | ) external initializer { 43 | require(_l1Bridge != address(0), "bf"); 44 | require(_l2TokenProxyBytecodeHash != bytes32(0), "df"); 45 | require(_governor != address(0), "sf"); 46 | 47 | l1Bridge = _l1Bridge; 48 | 49 | l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash; 50 | address l2StandardToken = address(new L2StandardERC20{salt: bytes32(0)}()); 51 | l2TokenBeacon = new UpgradeableBeacon{salt: bytes32(0)}(l2StandardToken); 52 | l2TokenBeacon.transferOwnership(_governor); 53 | } 54 | 55 | /// @notice Finalize the deposit and mint funds 56 | /// @param _l1Sender The account address that initiated the deposit on L1 57 | /// @param _l2Receiver The account address that would receive minted ether 58 | /// @param _l1Token The address of the token that was locked on the L1 59 | /// @param _amount Total amount of tokens deposited from L1 60 | /// @param _data The additional data that user can pass with the deposit 61 | function finalizeDeposit( 62 | address _l1Sender, 63 | address _l2Receiver, 64 | address _l1Token, 65 | uint256 _amount, 66 | bytes calldata _data 67 | ) external override { 68 | // Only the L1 bridge counterpart can initiate and finalize the deposit. 69 | require(AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1Bridge, "mq"); 70 | 71 | address expectedL2Token = l2TokenAddress(_l1Token); 72 | address currentL1Token = l1TokenAddress[expectedL2Token]; 73 | if (currentL1Token == address(0)) { 74 | address deployedToken = _deployL2Token(_l1Token, _data); 75 | require(deployedToken == expectedL2Token, "mt"); 76 | l1TokenAddress[expectedL2Token] = _l1Token; 77 | } else { 78 | require(currentL1Token == _l1Token, "gg"); // Double check that the expected value equal to real one 79 | } 80 | 81 | IL2StandardToken(expectedL2Token).bridgeMint(_l2Receiver, _amount); 82 | 83 | emit FinalizeDeposit(_l1Sender, _l2Receiver, expectedL2Token, _amount); 84 | } 85 | 86 | /// @dev Deploy and initialize the L2 token for the L1 counterpart 87 | function _deployL2Token(address _l1Token, bytes calldata _data) internal returns (address) { 88 | bytes32 salt = _getCreate2Salt(_l1Token); 89 | 90 | BeaconProxy l2Token = new BeaconProxy{salt: salt}(address(l2TokenBeacon), ""); 91 | L2StandardERC20(address(l2Token)).bridgeInitialize(_l1Token, _data); 92 | 93 | return address(l2Token); 94 | } 95 | 96 | /// @notice Initiates a withdrawal by burning funds on the contract and sending the message to L1 97 | /// where tokens would be unlocked 98 | /// @param _l1Receiver The account address that should receive funds on L1 99 | /// @param _l2Token The L2 token address which is withdrawn 100 | /// @param _amount The total amount of tokens to be withdrawn 101 | function withdraw( 102 | address _l1Receiver, 103 | address _l2Token, 104 | uint256 _amount 105 | ) external override { 106 | IL2StandardToken(_l2Token).bridgeBurn(msg.sender, _amount); 107 | 108 | address l1Token = l1TokenAddress[_l2Token]; 109 | require(l1Token != address(0), "yh"); 110 | 111 | bytes memory message = _getL1WithdrawMessage(_l1Receiver, l1Token, _amount); 112 | L2ContractHelper.sendMessageToL1(message); 113 | 114 | emit WithdrawalInitiated(msg.sender, _l1Receiver, _l2Token, _amount); 115 | } 116 | 117 | /// @dev Encode the message for l2ToL1log sent with withdraw initialization 118 | function _getL1WithdrawMessage( 119 | address _to, 120 | address _l1Token, 121 | uint256 _amount 122 | ) internal pure returns (bytes memory) { 123 | return abi.encodePacked(IL1Bridge.finalizeWithdrawal.selector, _to, _l1Token, _amount); 124 | } 125 | 126 | /// @return Address of an L2 token counterpart 127 | function l2TokenAddress(address _l1Token) public view override returns (address) { 128 | bytes32 constructorInputHash = keccak256(abi.encode(address(l2TokenBeacon), "")); 129 | bytes32 salt = _getCreate2Salt(_l1Token); 130 | 131 | return 132 | L2ContractHelper.computeCreate2Address(address(this), salt, l2TokenProxyBytecodeHash, constructorInputHash); 133 | } 134 | 135 | /// @dev Convert the L1 token address to the create2 salt of deployed L2 token 136 | function _getCreate2Salt(address _l1Token) internal pure returns (bytes32 salt) { 137 | salt = bytes32(uint256(uint160(_l1Token))); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /l2/contracts/bridge/L2StandardERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; 6 | import "./interfaces/IL2StandardToken.sol"; 7 | import "../ExternalDecoder.sol"; 8 | 9 | /// @author Matter Labs 10 | /// @notice The ERC20 token implementation, that is used in the "default" ERC20 bridge 11 | contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken { 12 | /// @dev Describes whether there is a specific getter in the token. 13 | /// @notice Used to explicitly separate which getters the token has and which it does not. 14 | /// @notice Different tokens in L1 can implement or not implement getter function as `name`/`symbol`/`decimals`, 15 | /// @notice Our goal is to store all the getters that L1 token implements, and for others, we keep it as an unimplemented method. 16 | struct ERC20Getters { 17 | bool ignoreName; 18 | bool ignoreSymbol; 19 | bool ignoreDecimals; 20 | } 21 | 22 | ERC20Getters availableGetters; 23 | 24 | /// @dev The decimals of the token, that are used as a value for `decimals` getter function. 25 | /// @notice A private variable is used only for decimals, but not for `name` and `symbol`, because standard 26 | /// @notice OpenZeppelin token represents `name` and `symbol` as storage variables and `decimals` as constant. 27 | uint8 private decimals_; 28 | 29 | /// @dev Address of the L2 bridge that is used as trustee who can mint/burn tokens 30 | address public override l2Bridge; 31 | 32 | /// @dev Address of the L1 token that can be deposited to mint this L2 token 33 | address public override l1Address; 34 | 35 | /// @dev Contract is expected to be used as proxy implementation. 36 | constructor() { 37 | // Disable initialization to prevent Parity hack. 38 | _disableInitializers(); 39 | } 40 | 41 | /// @notice Initializes a contract token for later use. Expected to be used in the proxy. 42 | /// @dev Stores the L1 address of the bridge and set `name`/`symbol`/`decimals` getters that L1 token has. 43 | /// @param _l1Address Address of the L1 token that can be deposited to mint this L2 token 44 | /// @param _data The additional data that the L1 bridge provide for initialization. 45 | /// In this case, it is packed `name`/`symbol`/`decimals` of the L1 token. 46 | function bridgeInitialize(address _l1Address, bytes memory _data) external initializer { 47 | require(_l1Address != address(0), "in6"); // Should be non-zero address 48 | l1Address = _l1Address; 49 | 50 | l2Bridge = msg.sender; 51 | 52 | // We parse the data exactly as they were created on the L1 bridge 53 | (bytes memory nameBytes, bytes memory symbolBytes, bytes memory decimalsBytes) = abi.decode( 54 | _data, 55 | (bytes, bytes, bytes) 56 | ); 57 | 58 | ERC20Getters memory getters; 59 | string memory decodedName; 60 | string memory decodedSymbol; 61 | 62 | // L1 bridge didn't check if the L1 token return values with proper types for `name`/`symbol`/`decimals` 63 | // That's why we need to try to decode them, and if it works out, set the values as getters. 64 | 65 | // NOTE: Solidity doesn't have a convenient way to try to decode a value: 66 | // - Decode them manually, i.e. write a function that will validate that data in the correct format 67 | // and return decoded value and a boolean value - whether it was possible to decode. 68 | // - Use the standard abi.decode method, but wrap it into an external call in which error can be handled. 69 | // We use the second option here. 70 | 71 | try ExternalDecoder.decodeString(nameBytes) returns (string memory nameString) { 72 | decodedName = nameString; 73 | } catch { 74 | getters.ignoreName = true; 75 | } 76 | 77 | try ExternalDecoder.decodeString(symbolBytes) returns (string memory symbolString) { 78 | decodedSymbol = symbolString; 79 | } catch { 80 | getters.ignoreSymbol = true; 81 | } 82 | 83 | // Set decoded values for name and symbol. 84 | __ERC20_init_unchained(decodedName, decodedSymbol); 85 | 86 | // Set the name for EIP-712 signature. 87 | __ERC20Permit_init(decodedName); 88 | 89 | try ExternalDecoder.decodeUint8(decimalsBytes) returns (uint8 decimalsUint8) { 90 | // Set decoded value for decimals. 91 | decimals_ = decimalsUint8; 92 | } catch { 93 | getters.ignoreDecimals = true; 94 | } 95 | 96 | availableGetters = getters; 97 | emit BridgeInitialize(_l1Address, decodedName, decodedSymbol, decimals_); 98 | } 99 | 100 | modifier onlyBridge() { 101 | require(msg.sender == l2Bridge, "xnt"); // Only L2 bridge can call this method 102 | _; 103 | } 104 | 105 | /// @dev Mint tokens to a given account. 106 | /// @param _to The account that will receive the created tokens. 107 | /// @param _amount The amount that will be created. 108 | /// @notice Should be called by bridge after depositing tokens from L1. 109 | function bridgeMint(address _to, uint256 _amount) external override onlyBridge { 110 | _mint(_to, _amount); 111 | emit BridgeMint(_to, _amount); 112 | } 113 | 114 | /// @dev Burn tokens from a given account. 115 | /// @param _from The account from which tokens will be burned. 116 | /// @param _amount The amount that will be burned. 117 | /// @notice Should be called by bridge before withdrawing tokens to L1. 118 | function bridgeBurn(address _from, uint256 _amount) external override onlyBridge { 119 | _burn(_from, _amount); 120 | emit BridgeBurn(_from, _amount); 121 | } 122 | 123 | function name() public view override returns (string memory) { 124 | // If method is not available, behave like a token that does not implement this method - revert on call. 125 | if (availableGetters.ignoreName) revert(); 126 | return super.name(); 127 | } 128 | 129 | function symbol() public view override returns (string memory) { 130 | // If method is not available, behave like a token that does not implement this method - revert on call. 131 | if (availableGetters.ignoreSymbol) revert(); 132 | return super.symbol(); 133 | } 134 | 135 | function decimals() public view override returns (uint8) { 136 | // If method is not available, behave like a token that does not implement this method - revert on call. 137 | if (availableGetters.ignoreDecimals) revert(); 138 | return decimals_; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /l2/contracts/bridge/L2WETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; 6 | import "./interfaces/IL2WETH.sol"; 7 | import "./interfaces/IL2StandardToken.sol"; 8 | 9 | /// @author Matter Labs 10 | /// @notice The canonical implementation of the WETH token. 11 | /// @dev The idea is to replace the legacy WETH9 (which has well-known issues) with something better. 12 | /// This implementation has the following differences from the WETH9: 13 | /// - It does not have a silent fallback method and will revert if it's called for a method it hasn't implemented. 14 | /// - It implements `receive` method to allow users to deposit ether directly. 15 | /// - It implements `permit` method to allow users to sign a message instead of calling `approve`. 16 | /// 17 | /// Note: This is an upgradeable contract. In the future, we will remove upgradeability to make it trustless. 18 | /// But for now, when the Rollup has instant upgradability, we leave the possibility of upgrading to improve the contract if needed. 19 | contract L2WETH is ERC20PermitUpgradeable, IL2WETH, IL2StandardToken { 20 | /// @dev Contract is expected to be used as proxy implementation. 21 | constructor() { 22 | // Disable initialization to prevent Parity hack. 23 | _disableInitializers(); 24 | } 25 | 26 | /// @notice Initializes a contract token for later use. Expected to be used in the proxy. 27 | /// @dev Stores the L1 address of the bridge and set `name`/`symbol`/`decimals` getters. 28 | /// @param name_ The name of the token. 29 | /// @param symbol_ The symbol of the token. 30 | /// Note: The decimals are hardcoded to 18, the same as on Ether. 31 | function initialize(string memory name_, string memory symbol_) external initializer { 32 | // Set decoded values for name and symbol. 33 | __ERC20_init_unchained(name_, symbol_); 34 | 35 | // Set the name for EIP-712 signature. 36 | __ERC20Permit_init(name_); 37 | 38 | emit Initialize(name_, symbol_, 18); 39 | } 40 | 41 | /// @notice Function for minting tokens on L2, is implemented †o be compatible with StandardToken interface. 42 | /// @dev Should be never called because the WETH should be collateralized with Ether. 43 | /// Note: Use `deposit`/`depositTo` methods instead. 44 | function bridgeMint( 45 | address, // _to 46 | uint256 // _amount 47 | ) external override { 48 | revert("bridgeMint is not implemented"); 49 | } 50 | 51 | /// @dev Burn tokens from a given account and send the same amount of Ether to the bridge. 52 | /// @param _from The account from which tokens will be burned. 53 | /// @param _amount The amount that will be burned. 54 | /// @notice Should be called by the bridge before withdrawing tokens to L1. 55 | function bridgeBurn(address _from, uint256 _amount) external override { 56 | revert("bridgeBurn is not implemented yet"); 57 | } 58 | 59 | function l2Bridge() external view returns (address) { 60 | revert("l2Bridge is not implemented yet"); 61 | } 62 | 63 | function l1Address() external view returns (address) { 64 | revert("l1Address is not implemented yet"); 65 | } 66 | 67 | /// @notice Deposit Ether to mint WETH. 68 | function deposit() external payable override { 69 | depositTo(msg.sender); 70 | } 71 | 72 | /// @notice Withdraw WETH to get Ether. 73 | function withdraw(uint256 _amount) external override { 74 | withdrawTo(msg.sender, _amount); 75 | } 76 | 77 | /// @notice Deposit Ether to mint WETH to a given account. 78 | function depositTo(address _to) public payable override { 79 | _mint(_to, msg.value); 80 | } 81 | 82 | /// @notice Withdraw WETH to get Ether to a given account. 83 | function withdrawTo(address _to, uint256 _amount) public override { 84 | _burn(msg.sender, _amount); 85 | 86 | (bool success, ) = _to.call{value: _amount}(""); 87 | require(success, "Failed withdrawal"); 88 | } 89 | 90 | /// @dev Fallback function to allow receiving Ether. 91 | receive() external payable { 92 | depositTo(msg.sender); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /l2/contracts/bridge/interfaces/IL1Bridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /// @author Matter Labs 6 | interface IL1Bridge { 7 | function finalizeWithdrawal( 8 | uint256 _l2BlockNumber, 9 | uint256 _l2MessageIndex, 10 | uint16 _l2TxNumberInBlock, 11 | bytes calldata _message, 12 | bytes32[] calldata _merkleProof 13 | ) external; 14 | } 15 | -------------------------------------------------------------------------------- /l2/contracts/bridge/interfaces/IL2Bridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /// @author Matter Labs 6 | interface IL2Bridge { 7 | event FinalizeDeposit( 8 | address indexed l1Sender, 9 | address indexed l2Receiver, 10 | address indexed l2Token, 11 | uint256 amount 12 | ); 13 | 14 | event WithdrawalInitiated( 15 | address indexed l2Sender, 16 | address indexed l1Receiver, 17 | address indexed l2Token, 18 | uint256 amount 19 | ); 20 | 21 | function finalizeDeposit( 22 | address _l1Sender, 23 | address _l2Receiver, 24 | address _l1Token, 25 | uint256 _amount, 26 | bytes calldata _data 27 | ) external; 28 | 29 | function withdraw( 30 | address _l1Receiver, 31 | address _l2Token, 32 | uint256 _amount 33 | ) external; 34 | 35 | function l1TokenAddress(address _l2Token) external view returns (address); 36 | 37 | function l2TokenAddress(address _l1Token) external view returns (address); 38 | 39 | function l1Bridge() external view returns (address); 40 | } 41 | -------------------------------------------------------------------------------- /l2/contracts/bridge/interfaces/IL2StandardToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IL2StandardToken { 6 | event BridgeInitialize(address indexed l1Token, string name, string symbol, uint8 decimals); 7 | 8 | event BridgeMint(address indexed _account, uint256 _amount); 9 | 10 | event BridgeBurn(address indexed _account, uint256 _amount); 11 | 12 | function bridgeMint(address _account, uint256 _amount) external; 13 | 14 | function bridgeBurn(address _account, uint256 _amount) external; 15 | 16 | function l1Address() external view returns (address); 17 | 18 | function l2Bridge() external view returns (address); 19 | } 20 | -------------------------------------------------------------------------------- /l2/contracts/bridge/interfaces/IL2WETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IL2WETH { 6 | event Initialize(string name, string symbol, uint8 decimals); 7 | 8 | function deposit() external payable; 9 | 10 | function withdraw(uint256 _amount) external; 11 | 12 | function depositTo(address _to) external payable; 13 | 14 | function withdrawTo(address _to, uint256 _amount) external; 15 | } 16 | -------------------------------------------------------------------------------- /l2/contracts/interfaces/IPaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../L2ContractHelper.sol"; 6 | 7 | enum ExecutionResult { 8 | Revert, 9 | Success 10 | } 11 | 12 | bytes4 constant PAYMASTER_VALIDATION_SUCCESS_MAGIC = IPaymaster.validateAndPayForPaymasterTransaction.selector; 13 | 14 | interface IPaymaster { 15 | /// @dev Called by the bootloader to verify that the paymaster agrees to pay for the 16 | /// fee for the transaction. This transaction should also send the necessary amount of funds onto the bootloader 17 | /// address. 18 | /// @param _txHash The hash of the transaction 19 | /// @param _suggestedSignedHash The hash of the transaction that is signed by an EOA 20 | /// @param _transaction The transaction itself. 21 | /// @return magic The value that should be equal to the signature of the validateAndPayForPaymasterTransaction 22 | /// if the paymaster agrees to pay for the transaction. 23 | /// @return context The "context" of the transaction: an array of bytes of length at most 1024 bytes, which will be 24 | /// passed to the `postTransaction` method of the account. 25 | /// @dev The developer should strive to preserve as many steps as possible both for valid 26 | /// and invalid transactions as this very method is also used during the gas fee estimation 27 | /// (without some of the necessary data, e.g. signature). 28 | function validateAndPayForPaymasterTransaction( 29 | bytes32 _txHash, 30 | bytes32 _suggestedSignedHash, 31 | Transaction calldata _transaction 32 | ) external payable returns (bytes4 magic, bytes memory context); 33 | 34 | /// @dev Called by the bootloader after the execution of the transaction. Please note that 35 | /// there is no guarantee that this method will be called at all. Unlike the original EIP4337, 36 | /// this method won't be called if the transaction execution results in out-of-gas. 37 | /// @param _context, the context of the execution, returned by the "validateAndPayForPaymasterTransaction" method. 38 | /// @param _transaction, the users' transaction. 39 | /// @param _txResult, the result of the transaction execution (success or failure). 40 | /// @param _maxRefundedGas, the upper bound on the amout of gas that could be refunded to the paymaster. 41 | /// @dev The exact amount refunded depends on the gas spent by the "postOp" itself and so the developers should 42 | /// take that into account. 43 | function postTransaction( 44 | bytes calldata _context, 45 | Transaction calldata _transaction, 46 | bytes32 _txHash, 47 | bytes32 _suggestedSignedHash, 48 | ExecutionResult _txResult, 49 | uint256 _maxRefundedGas 50 | ) external payable; 51 | } 52 | -------------------------------------------------------------------------------- /l2/contracts/interfaces/IPaymasterFlow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @dev The interface that is used for encoding/decoding of 8 | * different types of paymaster flows. 9 | * @notice This is NOT an interface to be implementated 10 | * by contracts. It is just used for encoding. 11 | */ 12 | interface IPaymasterFlow { 13 | function general(bytes calldata input) external; 14 | 15 | function approvalBased( 16 | address _token, 17 | uint256 _minAllowance, 18 | bytes calldata _innerInput 19 | ) external; 20 | } 21 | -------------------------------------------------------------------------------- /l2/contracts/vendor/AddressAliasHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | /* 4 | * Copyright 2019-2021, Offchain Labs, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | pragma solidity ^0.8.0; 20 | 21 | library AddressAliasHelper { 22 | uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); 23 | 24 | /// @notice Utility function converts the address that submitted a tx 25 | /// to the inbox on L1 to the msg.sender viewed on L2 26 | /// @param l1Address the address in the L1 that triggered the tx to L2 27 | /// @return l2Address L2 address as viewed in msg.sender 28 | function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { 29 | unchecked { 30 | l2Address = address(uint160(l1Address) + offset); 31 | } 32 | } 33 | 34 | /// @notice Utility function that converts the msg.sender viewed on L2 to the 35 | /// address that submitted a tx to the inbox on L1 36 | /// @param l2Address L2 address as viewed in msg.sender 37 | /// @return l1Address the address in the L1 that triggered the tx to L2 38 | function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { 39 | unchecked { 40 | l1Address = address(uint160(l2Address) - offset); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /l2/system-contracts/BytecodeCompressor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT OR Apache-2.0 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./interfaces/IBytecodeCompressor.sol"; 6 | import "./Constants.sol"; 7 | import "./libraries/Utils.sol"; 8 | import "./libraries/UnsafeBytesCalldata.sol"; 9 | 10 | /** 11 | * @author Matter Labs 12 | * @notice Simple implementation of the compression algorithm specialized for zkEVM bytecode. 13 | * @dev Every deployed bytecode in zkEVM should be publicly restorable from the L1 data availability. 14 | * For this reason, the user may request the sequencer to publish the original bytecode and mark it as known. 15 | * Or the user may compress the bytecode and publish it instead (fewer data onchain!). 16 | */ 17 | contract BytecodeCompressor is IBytecodeCompressor { 18 | using UnsafeBytesCalldata for bytes; 19 | 20 | modifier onlyBootloader() { 21 | require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Callable only by the bootloader"); 22 | _; 23 | } 24 | 25 | /// @notice Verify the compressed bytecode and publish it on the L1. 26 | /// @param _bytecode The original bytecode to be verified against. 27 | /// @param _rawCompressedData The compressed bytecode in a format of: 28 | /// - 2 bytes: the length of the dictionary 29 | /// - N bytes: the dictionary 30 | /// - M bytes: the encoded data 31 | /// @dev The dictionary is a sequence of 8-byte chunks, each of them has the associated index. 32 | /// @dev The encoded data is a sequence of 2-byte chunks, each of them is an index of the dictionary. 33 | /// @dev The compression algorithm works as follows: 34 | /// 1. The original bytecode is split into 8-byte chunks. 35 | /// Since the bytecode size is always a multiple of 32, this is always possible. 36 | /// 2. For each 8-byte chunk in the original bytecode: 37 | /// * If the chunk is not already in the dictionary, it is added to the dictionary array. 38 | /// * If the dictionary becomes overcrowded (2^16 + 1 elements), the compression process will fail. 39 | /// * The 2-byte index of the chunk in the dictionary is added to the encoded data. 40 | /// @dev Currently, the method may be called only from the bootloader because the server is not ready to publish bytecodes 41 | /// in internal transactions. However, in the future, we will allow everyone to publish compressed bytecodes. 42 | function publishCompressedBytecode( 43 | bytes calldata _bytecode, 44 | bytes calldata _rawCompressedData 45 | ) external payable onlyBootloader returns (bytes32 bytecodeHash) { 46 | unchecked { 47 | (bytes calldata dictionary, bytes calldata encodedData) = _decodeRawBytecode(_rawCompressedData); 48 | 49 | require(dictionary.length % 8 == 0, "Dictionary length should be a multiple of 8"); 50 | require(dictionary.length <= 2 ** 16 * 8, "Dictionary is too big"); 51 | require( 52 | encodedData.length * 4 == _bytecode.length, 53 | "Encoded data length should be 4 times shorter than the original bytecode" 54 | ); 55 | 56 | for (uint256 encodedDataPointer = 0; encodedDataPointer < encodedData.length; encodedDataPointer += 2) { 57 | uint256 indexOfEncodedChunk = uint256(encodedData.readUint16(encodedDataPointer)) * 8; 58 | require(indexOfEncodedChunk < dictionary.length, "Encoded chunk index is out of bounds"); 59 | 60 | uint64 encodedChunk = dictionary.readUint64(indexOfEncodedChunk); 61 | uint64 realChunk = _bytecode.readUint64(encodedDataPointer * 4); 62 | 63 | require(encodedChunk == realChunk, "Encoded chunk does not match the original bytecode"); 64 | } 65 | } 66 | 67 | bytecodeHash = Utils.hashL2Bytecode(_bytecode); 68 | 69 | bytes32 rawCompressedDataHash = L1_MESSENGER_CONTRACT.sendToL1(_rawCompressedData); 70 | KNOWN_CODE_STORAGE_CONTRACT.markBytecodeAsPublished( 71 | bytecodeHash, 72 | rawCompressedDataHash, 73 | _rawCompressedData.length 74 | ); 75 | } 76 | 77 | /// @notice Decode the raw compressed data into the dictionary and the encoded data. 78 | /// @param _rawCompressedData The compressed bytecode in a format of: 79 | /// - 2 bytes: the bytes length of the dictionary 80 | /// - N bytes: the dictionary 81 | /// - M bytes: the encoded data 82 | function _decodeRawBytecode( 83 | bytes calldata _rawCompressedData 84 | ) internal pure returns (bytes calldata dictionary, bytes calldata encodedData) { 85 | unchecked { 86 | // The dictionary length can't be more than 2^16, so it fits into 2 bytes. 87 | uint256 dictionaryLen = uint256(_rawCompressedData.readUint16(0)); 88 | dictionary = _rawCompressedData[2:2 + dictionaryLen * 8]; 89 | encodedData = _rawCompressedData[2 + dictionaryLen * 8:]; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /l2/system-contracts/Constants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./interfaces/IAccountCodeStorage.sol"; 6 | import "./interfaces/INonceHolder.sol"; 7 | import "./interfaces/IContractDeployer.sol"; 8 | import "./interfaces/IKnownCodesStorage.sol"; 9 | import "./interfaces/IImmutableSimulator.sol"; 10 | import "./interfaces/IEthToken.sol"; 11 | import "./interfaces/IL1Messenger.sol"; 12 | import "./interfaces/ISystemContext.sol"; 13 | import "./interfaces/IBytecodeCompressor.sol"; 14 | import "./BootloaderUtilities.sol"; 15 | 16 | /// @dev All the system contracts introduced by zkSync have their addresses 17 | /// started from 2^15 in order to avoid collision with Ethereum precompiles. 18 | uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15 19 | 20 | /// @dev All the system contracts must be located in the kernel space, 21 | /// i.e. their addresses must be below 2^16. 22 | uint160 constant MAX_SYSTEM_CONTRACT_ADDRESS = 0xffff; // 2^16 - 1 23 | 24 | address constant ECRECOVER_SYSTEM_CONTRACT = address(0x01); 25 | address constant SHA256_SYSTEM_CONTRACT = address(0x02); 26 | 27 | /// @dev The current maximum deployed precompile address. 28 | /// Note: currently only two precompiles are deployed: 29 | /// 0x01 - ecrecover 30 | /// 0x02 - sha256 31 | /// Important! So the constant should be updated if more precompiles are deployed. 32 | uint256 constant CURRENT_MAX_PRECOMPILE_ADDRESS = uint256(uint160(SHA256_SYSTEM_CONTRACT)); 33 | 34 | address payable constant BOOTLOADER_FORMAL_ADDRESS = payable(address(SYSTEM_CONTRACTS_OFFSET + 0x01)); 35 | IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( 36 | address(SYSTEM_CONTRACTS_OFFSET + 0x02) 37 | ); 38 | INonceHolder constant NONCE_HOLDER_SYSTEM_CONTRACT = INonceHolder(address(SYSTEM_CONTRACTS_OFFSET + 0x03)); 39 | IKnownCodesStorage constant KNOWN_CODE_STORAGE_CONTRACT = IKnownCodesStorage(address(SYSTEM_CONTRACTS_OFFSET + 0x04)); 40 | IImmutableSimulator constant IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT = IImmutableSimulator( 41 | address(SYSTEM_CONTRACTS_OFFSET + 0x05) 42 | ); 43 | IContractDeployer constant DEPLOYER_SYSTEM_CONTRACT = IContractDeployer(address(SYSTEM_CONTRACTS_OFFSET + 0x06)); 44 | 45 | // A contract that is allowed to deploy any codehash 46 | // on any address. To be used only during an upgrade. 47 | address constant FORCE_DEPLOYER = address(SYSTEM_CONTRACTS_OFFSET + 0x07); 48 | IL1Messenger constant L1_MESSENGER_CONTRACT = IL1Messenger(address(SYSTEM_CONTRACTS_OFFSET + 0x08)); 49 | address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09); 50 | 51 | IEthToken constant ETH_TOKEN_SYSTEM_CONTRACT = IEthToken(address(SYSTEM_CONTRACTS_OFFSET + 0x0a)); 52 | 53 | address constant KECCAK256_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x10); 54 | 55 | ISystemContext constant SYSTEM_CONTEXT_CONTRACT = ISystemContext(payable(address(SYSTEM_CONTRACTS_OFFSET + 0x0b))); 56 | 57 | BootloaderUtilities constant BOOTLOADER_UTILITIES = BootloaderUtilities(address(SYSTEM_CONTRACTS_OFFSET + 0x0c)); 58 | 59 | address constant EVENT_WRITER_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x0d); 60 | 61 | IBytecodeCompressor constant BYTECODE_COMPRESSOR_CONTRACT = IBytecodeCompressor( 62 | address(SYSTEM_CONTRACTS_OFFSET + 0x0e) 63 | ); 64 | 65 | /// @dev If the bitwise AND of the extraAbi[2] param when calling the MSG_VALUE_SIMULATOR 66 | /// is non-zero, the call will be assumed to be a system one. 67 | uint256 constant MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT = 1; 68 | 69 | /// @dev The maximal msg.value that context can have 70 | uint256 constant MAX_MSG_VALUE = 2 ** 128 - 1; 71 | 72 | /// @dev Prefix used during derivation of account addresses using CREATE2 73 | /// @dev keccak256("zksyncCreate2") 74 | bytes32 constant CREATE2_PREFIX = 0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494; 75 | /// @dev Prefix used during derivation of account addresses using CREATE 76 | /// @dev keccak256("zksyncCreate") 77 | bytes32 constant CREATE_PREFIX = 0x63bae3a9951d38e8a3fbb7b70909afc1200610fc5bc55ade242f815974674f23; 78 | -------------------------------------------------------------------------------- /l2/system-contracts/EmptyContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @notice The "empty" contract that is put into some system contracts by default. 8 | * @dev The bytecode of the contract is set by default for all addresses for which no other bytecodes are deployed. 9 | */ 10 | contract EmptyContract { 11 | fallback() external payable {} 12 | 13 | receive() external payable {} 14 | } 15 | -------------------------------------------------------------------------------- /l2/system-contracts/ImmutableSimulator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./interfaces/IImmutableSimulator.sol"; 6 | import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; 7 | 8 | /** 9 | * @author Matter Labs 10 | * @notice System smart contract that simulates the behavior of immutable variables in Solidity. 11 | * @dev The contract stores the immutable variables created during deployment by other contracts on his storage. 12 | * @dev This simulator is needed so that smart contracts with the same Solidity code but different 13 | * constructor parameters have the same bytecode. 14 | * @dev The users are not expected to call this contract directly, only indirectly via the compiler simulations 15 | * for the immutable variables in Solidity. 16 | */ 17 | contract ImmutableSimulator is IImmutableSimulator { 18 | /// @dev mapping (contract address) => (index of immutable variable) => value 19 | /// @notice that address uses `uint256` type to leave the option to introduce 32-byte address space in future. 20 | mapping(uint256 => mapping(uint256 => bytes32)) internal immutableDataStorage; 21 | 22 | /// @notice Method that returns the immutable with a certain index for a user. 23 | /// @param _dest The address which the immutable belongs to. 24 | /// @param _index The index of the immutable. 25 | /// @return The value of the immutables. 26 | function getImmutable(address _dest, uint256 _index) external view override returns (bytes32) { 27 | return immutableDataStorage[uint256(uint160(_dest))][_index]; 28 | } 29 | 30 | /// @notice Method used by the contract deployer to store the immutables for an account 31 | /// @param _dest The address which to store the immutables for. 32 | /// @param _immutables The list of the immutables. 33 | function setImmutables(address _dest, ImmutableData[] calldata _immutables) external override { 34 | require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), "Callable only by the deployer system contract"); 35 | unchecked { 36 | uint256 immutablesLength = _immutables.length; 37 | for (uint256 i = 0; i < immutablesLength; ++i) { 38 | uint256 index = _immutables[i].index; 39 | bytes32 value = _immutables[i].value; 40 | immutableDataStorage[uint256(uint160(_dest))][index] = value; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /l2/system-contracts/KnownCodesStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./interfaces/IKnownCodesStorage.sol"; 6 | import "./libraries/Utils.sol"; 7 | import "./libraries/SystemContractHelper.sol"; 8 | import {BOOTLOADER_FORMAL_ADDRESS, BYTECODE_COMPRESSOR_CONTRACT} from "./Constants.sol"; 9 | 10 | /** 11 | * @author Matter Labs 12 | * @notice The storage of this contract will basically serve as a mapping for the known code hashes. 13 | * @dev Code hash is not strictly a hash, it's a structure where the first byte denotes the version of the hash, 14 | * the second byte denotes whether the contract is constructed, and the next two bytes denote the length in 32-byte words. 15 | * words. And then the next 28 bytes is the truncated hash. 16 | */ 17 | contract KnownCodesStorage is IKnownCodesStorage { 18 | modifier onlyBootloader() { 19 | require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Callable only by the bootloader"); 20 | _; 21 | } 22 | 23 | modifier onlyBytecodeCompressor() { 24 | require(msg.sender == address(BYTECODE_COMPRESSOR_CONTRACT), "Callable only by the bytecode compressor"); 25 | _; 26 | } 27 | 28 | /// @notice The method that is used by the bootloader to mark several bytecode hashes as known. 29 | /// @param _shouldSendToL1 Whether the bytecode should be sent on L1. 30 | /// @param _hashes Hashes of the bytecodes to be marked as known. 31 | function markFactoryDeps(bool _shouldSendToL1, bytes32[] calldata _hashes) external onlyBootloader { 32 | unchecked { 33 | uint256 hashesLen = _hashes.length; 34 | for (uint256 i = 0; i < hashesLen; ++i) { 35 | uint256 codeLengthInBytes = Utils.bytecodeLenInBytes(_hashes[i]); 36 | _markBytecodeAsPublished(_hashes[i], 0, codeLengthInBytes, _shouldSendToL1); 37 | } 38 | } 39 | } 40 | 41 | /// @notice The method used to mark a single bytecode hash as known. 42 | /// @dev Only trusted contacts can call this method, currently only the bytecode compressor. 43 | /// @param _bytecodeHash The hash of the bytecode that is marked as known. 44 | /// @param _l1PreimageHash The hash of the preimage is be shown on L1 if zero - the full bytecode will be shown. 45 | /// @param _l1PreimageBytesLen The length of the preimage in bytes. 46 | function markBytecodeAsPublished( 47 | bytes32 _bytecodeHash, 48 | bytes32 _l1PreimageHash, 49 | uint256 _l1PreimageBytesLen 50 | ) external onlyBytecodeCompressor { 51 | _markBytecodeAsPublished(_bytecodeHash, _l1PreimageHash, _l1PreimageBytesLen, false); 52 | } 53 | 54 | /// @notice The method used to mark a single bytecode hash as known 55 | /// @param _bytecodeHash The hash of the bytecode that is marked as known 56 | /// @param _l1PreimageHash The hash of the preimage to be shown on L1 if zero - the full bytecode will be shown 57 | /// @param _l1PreimageBytesLen The length of the preimage in bytes 58 | /// @param _shouldSendToL1 Whether the bytecode should be sent on L1 59 | function _markBytecodeAsPublished( 60 | bytes32 _bytecodeHash, 61 | bytes32 _l1PreimageHash, 62 | uint256 _l1PreimageBytesLen, 63 | bool _shouldSendToL1 64 | ) internal { 65 | if (getMarker(_bytecodeHash) == 0) { 66 | _validateBytecode(_bytecodeHash); 67 | 68 | if (_shouldSendToL1) { 69 | _sendBytecodeToL1(_bytecodeHash, _l1PreimageHash, _l1PreimageBytesLen); 70 | } 71 | 72 | // Save as known, to not resend the log to L1 73 | assembly { 74 | sstore(_bytecodeHash, 1) 75 | } 76 | 77 | emit MarkedAsKnown(_bytecodeHash, _shouldSendToL1); 78 | } 79 | } 80 | 81 | /// @notice Method used for sending the bytecode (preimage for the bytecode hash) on L1. 82 | /// @dev While bytecode must be visible to L1 observers, it's not necessary to disclose the whole raw bytecode. 83 | /// To achieve this, it's possible to utilize compressed data using a known compression algorithm. Thus, the 84 | /// L1 preimage data may differ from the raw bytecode. 85 | /// @param _bytecodeHash The hash of the bytecode that is marked as known. 86 | /// @param _l1PreimageHash The hash of the preimage to be shown on L1 if zero - the full bytecode will be shown. 87 | /// @param _l1PreimageBytesLen The length of the preimage in bytes. 88 | /// @dev This method sends a single L2->L1 log with the bytecodeHash and l1PreimageHash. It is the responsibility of the L1 89 | /// smart contracts to make sure that the preimage for this bytecode hash has been shown. 90 | function _sendBytecodeToL1(bytes32 _bytecodeHash, bytes32 _l1PreimageHash, uint256 _l1PreimageBytesLen) internal { 91 | // Burn gas to cover the cost of publishing pubdata on L1 92 | 93 | // Get the cost of 1 pubdata byte in gas 94 | uint256 meta = SystemContractHelper.getZkSyncMetaBytes(); 95 | uint256 pricePerPubdataByteInGas = SystemContractHelper.getGasPerPubdataByteFromMeta(meta); 96 | 97 | // Calculate how many bytes of calldata will need to be transferred to L1. 98 | // We published the data as ABI-encoded `bytes`, so we pay for: 99 | // - bytecode length in bytes, rounded up to a multiple of 32 (it always is, because of the bytecode format) 100 | // - 32 bytes of encoded offset 101 | // - 32 bytes of encoded length 102 | 103 | uint256 gasToPay = (_l1PreimageBytesLen + 64) * pricePerPubdataByteInGas; 104 | _burnGas(Utils.safeCastToU32(gasToPay)); 105 | 106 | // Send a log to L1 that bytecode should be known. 107 | // L1 smart contract will check the availability of bytecodeHash preimage. 108 | SystemContractHelper.toL1(true, _bytecodeHash, _l1PreimageHash); 109 | } 110 | 111 | /// @notice Method used for burning a certain amount of gas 112 | /// @param _gasToPay The number of gas to burn. 113 | function _burnGas(uint32 _gasToPay) internal view { 114 | bool precompileCallSuccess = SystemContractHelper.precompileCall( 115 | 0, // The precompile parameters are formal ones. We only need the precompile call to burn gas. 116 | _gasToPay 117 | ); 118 | require(precompileCallSuccess, "Failed to charge gas"); 119 | } 120 | 121 | /// @notice Returns the marker stored for a bytecode hash. 1 means that the bytecode hash is known 122 | /// and can be used for deploying contracts. 0 otherwise. 123 | function getMarker(bytes32 _hash) public view override returns (uint256 marker) { 124 | assembly { 125 | marker := sload(_hash) 126 | } 127 | } 128 | 129 | /// @notice Validates the format of bytecodehash 130 | /// @dev zk-circuit accepts & handles only valid format of bytecode hash, other input has undefined behavior 131 | /// That's why we need to validate it 132 | function _validateBytecode(bytes32 _bytecodeHash) internal pure { 133 | uint8 version = uint8(_bytecodeHash[0]); 134 | require(version == 1 && _bytecodeHash[1] == bytes1(0), "Incorrectly formatted bytecodeHash"); 135 | 136 | require(Utils.bytecodeLenInWords(_bytecodeHash) % 2 == 1, "Code length in words must be odd"); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /l2/system-contracts/L1Messenger.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./interfaces/IL1Messenger.sol"; 6 | import "./libraries/SystemContractHelper.sol"; 7 | import "./libraries/EfficientCall.sol"; 8 | 9 | /** 10 | * @author Matter Labs 11 | * @notice Smart contract for sending arbitrary length messages to L1 12 | * @dev by default ZkSync can send fixed length messages on L1. 13 | * A fixed length message has 4 parameters `senderAddress` `isService`, `key`, `value`, 14 | * the first one is taken from the context, the other three are chosen by the sender. 15 | * @dev To send a variable length message we use this trick: 16 | * - This system contract accepts a arbitrary length message and sends a fixed length message with 17 | * parameters `senderAddress == this`, `marker == true`, `key == msg.sender`, `value == keccak256(message)`. 18 | * - The contract on L1 accepts all sent messages and if the message came from this system contract 19 | * it requires that the preimage of `value` be provided. 20 | */ 21 | contract L1Messenger is IL1Messenger { 22 | function sendToL1(bytes calldata _message) external override returns (bytes32 hash) { 23 | hash = EfficientCall.keccak(_message); 24 | 25 | // Get cost of one byte pubdata in gas from context. 26 | uint256 meta = SystemContractHelper.getZkSyncMetaBytes(); 27 | uint32 gasPerPubdataBytes = SystemContractHelper.getGasPerPubdataByteFromMeta(meta); 28 | 29 | // Calculate how many bytes of calldata will need to be transferred to L1. 30 | // We published the data as ABI-encoded `bytes`, so we pay for: 31 | // - message length in bytes, rounded up to a multiple of 32 32 | // - 32 bytes of encoded offset 33 | // - 32 bytes of encoded length 34 | 35 | uint256 pubdataLen; 36 | unchecked { 37 | pubdataLen = ((_message.length + 31) / 32) * 32 + 64; 38 | } 39 | uint256 gasToPay = pubdataLen * gasPerPubdataBytes; 40 | 41 | // Call precompile to burn gas to cover the cost of publishing pubdata to L1. 42 | uint256 precompileParams = SystemContractHelper.packPrecompileParams(0, 0, 0, 0, 0); 43 | bool precompileCallSuccess = SystemContractHelper.precompileCall( 44 | precompileParams, 45 | Utils.safeCastToU32(gasToPay) 46 | ); 47 | require(precompileCallSuccess); 48 | 49 | SystemContractHelper.toL1(true, bytes32(uint256(uint160(msg.sender))), hash); 50 | 51 | emit L1MessageSent(msg.sender, hash, _message); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /l2/system-contracts/L2EthToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import {IEthToken} from "./interfaces/IEthToken.sol"; 6 | import {MSG_VALUE_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS, L1_MESSENGER_CONTRACT} from "./Constants.sol"; 7 | import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; 8 | import {IMailbox} from "./interfaces/IMailbox.sol"; 9 | 10 | /** 11 | * @author Matter Labs 12 | * @notice Native ETH contract. 13 | * @dev It does NOT provide interfaces for personal interaction with tokens like `transfer`, `approve`, and `transferFrom`. 14 | * Instead, this contract is used by the bootloader and `MsgValueSimulator`/`ContractDeployer` system contracts 15 | * to perform the balance changes while simulating the `msg.value` Ethereum behavior. 16 | */ 17 | contract L2EthToken is IEthToken { 18 | /// @notice The balances of the users. 19 | mapping(address => uint256) balance; 20 | 21 | /// @notice The total amount of tokens that have been minted. 22 | uint256 public override totalSupply; 23 | 24 | modifier onlyBootloader() { 25 | require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Callable only by the bootloader"); 26 | _; 27 | } 28 | 29 | /// @notice Transfer tokens from one address to another. 30 | /// @param _from The address to transfer the ETH from. 31 | /// @param _to The address to transfer the ETH to. 32 | /// @param _amount The amount of ETH in wei being transferred. 33 | /// @dev This function can be called only by trusted system contracts. 34 | /// @dev This function also emits "Transfer" event, which might be removed 35 | /// later on. 36 | function transferFromTo(address _from, address _to, uint256 _amount) external override { 37 | require( 38 | msg.sender == MSG_VALUE_SYSTEM_CONTRACT || 39 | msg.sender == address(DEPLOYER_SYSTEM_CONTRACT) || 40 | msg.sender == BOOTLOADER_FORMAL_ADDRESS, 41 | "Only system contracts with special access can call this method" 42 | ); 43 | 44 | uint256 fromBalance = balance[_from]; 45 | require(fromBalance >= _amount, "Transfer amount exceeds balance"); 46 | unchecked { 47 | balance[_from] = fromBalance - _amount; 48 | // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by 49 | // decrementing then incrementing. 50 | balance[_to] += _amount; 51 | } 52 | 53 | emit Transfer(_from, _to, _amount); 54 | } 55 | 56 | /// @notice Returns ETH balance of an account 57 | /// @dev It takes `uint256` as an argument to be able to properly simulate the behaviour of the 58 | /// Ethereum's `BALANCE` opcode that accepts uint256 as an argument and truncates any upper bits 59 | /// @param _account The address of the account to return the balance of. 60 | function balanceOf(uint256 _account) external view override returns (uint256) { 61 | return balance[address(uint160(_account))]; 62 | } 63 | 64 | /// @notice Increase the total supply of tokens and balance of the receiver. 65 | /// @dev This method is only callable by the bootloader. 66 | /// @param _account The address which to mint the funds to. 67 | /// @param _amount The amount of ETH in wei to be minted. 68 | function mint(address _account, uint256 _amount) external override onlyBootloader { 69 | totalSupply += _amount; 70 | balance[_account] += _amount; 71 | emit Mint(_account, _amount); 72 | } 73 | 74 | /// @notice Initiate the ETH withdrawal, funds will be available to claim on L1 `finalizeEthWithdrawal` method. 75 | /// @param _l1Receiver The address on L1 to receive the funds. 76 | /// @dev The function accepts the `msg.value`. Since this contract holds the mapping of all ether 77 | /// balances of the system, the sent `msg.value` is added to the `this` balance before the call. 78 | /// So the balance of `address(this)` is always bigger or equal to the `msg.value`! 79 | function withdraw(address _l1Receiver) external payable override { 80 | uint256 amount = msg.value; 81 | 82 | // Silent burning of the ether 83 | unchecked { 84 | // This is safe, since this contract holds the ether balances, and if user 85 | // send a `msg.value` it will be added to the contract (`this`) balance. 86 | balance[address(this)] -= amount; 87 | totalSupply -= amount; 88 | } 89 | 90 | // Send the L2 log, a user could use it as proof of the withdrawal 91 | bytes memory message = _getL1WithdrawMessage(_l1Receiver, amount); 92 | L1_MESSENGER_CONTRACT.sendToL1(message); 93 | 94 | emit Withdrawal(msg.sender, _l1Receiver, amount); 95 | } 96 | 97 | /// @dev Get the message to be sent to L1 to initiate a withdrawal. 98 | function _getL1WithdrawMessage(address _to, uint256 _amount) internal pure returns (bytes memory) { 99 | return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount); 100 | } 101 | 102 | /// @dev This method has not been stabilized and might be 103 | /// removed later on. 104 | function name() external pure override returns (string memory) { 105 | return "Ether"; 106 | } 107 | 108 | /// @dev This method has not been stabilized and might be 109 | /// removed later on. 110 | function symbol() external pure override returns (string memory) { 111 | return "ETH"; 112 | } 113 | 114 | /// @dev This method has not been stabilized and might be 115 | /// removed later on. 116 | function decimals() external pure override returns (uint8) { 117 | return 18; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /l2/system-contracts/MsgValueSimulator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./libraries/Utils.sol"; 6 | import "./libraries/EfficientCall.sol"; 7 | import {SystemContractHelper, ISystemContract} from "./libraries/SystemContractHelper.sol"; 8 | import {MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, ETH_TOKEN_SYSTEM_CONTRACT, MAX_MSG_VALUE} from "./Constants.sol"; 9 | 10 | /** 11 | * @author Matter Labs 12 | * @notice The contract responsible for simulating transactions with `msg.value` inside zkEVM. 13 | * @dev It accepts value and whether the call should be system in the first extraAbi param and 14 | * the address to call in the second extraAbi param, transfers the funds and uses `mimicCall` to continue the 15 | * call with the same msg.sender. 16 | */ 17 | contract MsgValueSimulator is ISystemContract { 18 | /// @notice Extract value, isSystemCall and to from the extraAbi params. 19 | /// @dev The contract accepts value, the callee and whether the call should a system one via its ABI params. 20 | /// @dev The first ABI param contains the value in the [0..127] bits. The 128th contains 21 | /// the flag whether or not the call should be a system one. 22 | /// The second ABI params contains the callee. 23 | function _getAbiParams() internal view returns (uint256 value, bool isSystemCall, address to) { 24 | value = SystemContractHelper.getExtraAbiData(0); 25 | uint256 addressAsUint = SystemContractHelper.getExtraAbiData(1); 26 | uint256 mask = SystemContractHelper.getExtraAbiData(2); 27 | 28 | isSystemCall = (mask & MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT) != 0; 29 | 30 | to = address(uint160(addressAsUint)); 31 | } 32 | 33 | fallback(bytes calldata _data) external payable onlySystemCall returns (bytes memory) { 34 | (uint256 value, bool isSystemCall, address to) = _getAbiParams(); 35 | 36 | // Prevent mimic call to the MsgValueSimulator to prevent an unexpected change of callee. 37 | require(to != address(this), "MsgValueSimulator calls itself"); 38 | 39 | if (value != 0) { 40 | (bool success, ) = address(ETH_TOKEN_SYSTEM_CONTRACT).call( 41 | abi.encodeCall(ETH_TOKEN_SYSTEM_CONTRACT.transferFromTo, (msg.sender, to, value)) 42 | ); 43 | 44 | // If the transfer of ETH fails, we do the most Ethereum-like behaviour in such situation: revert(0,0) 45 | if (!success) { 46 | assembly { 47 | revert(0, 0) 48 | } 49 | } 50 | } 51 | 52 | // For the next call this `msg.value` will be used. 53 | SystemContractHelper.setValueForNextFarCall(Utils.safeCastToU128(value)); 54 | 55 | return EfficientCall.mimicCall(gasleft(), to, _data, msg.sender, false, isSystemCall); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /l2/system-contracts/SystemContext.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import {ISystemContext} from "./interfaces/ISystemContext.sol"; 6 | import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; 7 | import {BOOTLOADER_FORMAL_ADDRESS} from "./Constants.sol"; 8 | 9 | /** 10 | * @author Matter Labs 11 | * @notice Contract that stores some of the context variables, that may be either 12 | * block-scoped, tx-scoped or system-wide. 13 | */ 14 | contract SystemContext is ISystemContext { 15 | modifier onlyBootloader() { 16 | require(msg.sender == BOOTLOADER_FORMAL_ADDRESS); 17 | _; 18 | } 19 | 20 | /// @notice The chainId of the network. It is set at the genesis. 21 | uint256 public chainId; 22 | 23 | /// @notice The `tx.origin` in the current transaction. 24 | /// @dev It is updated before each transaction by the bootloader 25 | address public origin; 26 | 27 | /// @notice The `tx.gasPrice` in the current transaction. 28 | /// @dev It is updated before each transaction by the bootloader 29 | uint256 public gasPrice; 30 | 31 | /// @notice The current block's gasLimit. 32 | uint256 public blockGasLimit = type(uint32).max; 33 | 34 | /// @notice The `block.coinbase` in the current transaction. 35 | /// @dev For the support of coinbase, we will the bootloader formal address for now 36 | address public coinbase = BOOTLOADER_FORMAL_ADDRESS; 37 | 38 | /// @notice Formal `block.difficulty` parameter. 39 | uint256 public difficulty = 2500000000000000; 40 | 41 | /// @notice The `block.basefee`. 42 | /// @dev It is currently a constant. 43 | uint256 public baseFee; 44 | 45 | /// @notice The coefficient with which the current block's number 46 | /// is stored in the current block info 47 | uint256 constant BLOCK_INFO_BLOCK_NUMBER_PART = 2 ** 128; 48 | 49 | /// @notice block.number and block.timestamp stored packed. 50 | /// @dev It is equal to 2^128 * block_number + block_timestamp. 51 | uint256 public currentBlockInfo; 52 | 53 | /// @notice The hashes of blocks. 54 | /// @dev It stores block hashes for all previous blocks. 55 | mapping(uint256 => bytes32) public blockHash; 56 | 57 | /// @notice Set the current tx origin. 58 | /// @param _newOrigin The new tx origin. 59 | function setTxOrigin(address _newOrigin) external onlyBootloader { 60 | origin = _newOrigin; 61 | } 62 | 63 | /// @notice Set the the current gas price. 64 | /// @param _gasPrice The new tx gasPrice. 65 | function setGasPrice(uint256 _gasPrice) external onlyBootloader { 66 | gasPrice = _gasPrice; 67 | } 68 | 69 | /// @notice The method that emulates `blockhash` opcode in EVM. 70 | /// @dev Just like the blockhash in the EVM, it returns bytes32(0), when 71 | /// when queried about hashes that are older than 256 blocks ago. 72 | function getBlockHashEVM(uint256 _block) external view returns (bytes32 hash) { 73 | if (block.number < _block || block.number - _block > 256) { 74 | hash = bytes32(0); 75 | } else { 76 | hash = blockHash[_block]; 77 | } 78 | } 79 | 80 | /// @notice Returns the current blocks' number and timestamp. 81 | /// @return blockNumber and blockTimestamp tuple of the current block's number and the current block's timestamp 82 | function getBlockNumberAndTimestamp() public view returns (uint256 blockNumber, uint256 blockTimestamp) { 83 | uint256 blockInfo = currentBlockInfo; 84 | blockNumber = blockInfo / BLOCK_INFO_BLOCK_NUMBER_PART; 85 | blockTimestamp = blockInfo % BLOCK_INFO_BLOCK_NUMBER_PART; 86 | } 87 | 88 | /// @notice Returns the current block's number. 89 | /// @return blockNumber The current block's number. 90 | function getBlockNumber() public view returns (uint256 blockNumber) { 91 | (blockNumber, ) = getBlockNumberAndTimestamp(); 92 | } 93 | 94 | /// @notice Returns the current block's timestamp. 95 | /// @return timestamp The current block's timestamp. 96 | function getBlockTimestamp() public view returns (uint256 timestamp) { 97 | (, timestamp) = getBlockNumberAndTimestamp(); 98 | } 99 | 100 | /// @notice Increments the current block number and sets the new timestamp 101 | /// @dev Called by the bootloader at the start of the block. 102 | /// @param _prevBlockHash The hash of the previous block. 103 | /// @param _newTimestamp The timestamp of the new block. 104 | /// @param _expectedNewNumber The new block's number 105 | /// @dev Whie _expectedNewNumber can be derived as prevBlockNumber + 1, we still 106 | /// manually supply it here for consistency checks. 107 | /// @dev The correctness of the _prevBlockHash and _newTimestamp should be enforced on L1. 108 | function setNewBlock( 109 | bytes32 _prevBlockHash, 110 | uint256 _newTimestamp, 111 | uint256 _expectedNewNumber, 112 | uint256 _baseFee 113 | ) external onlyBootloader { 114 | (uint256 currentBlockNumber, uint256 currentBlockTimestamp) = getBlockNumberAndTimestamp(); 115 | require(_newTimestamp > currentBlockTimestamp, "Timestamps should be incremental"); 116 | require(currentBlockNumber + 1 == _expectedNewNumber, "The provided block number is not correct"); 117 | 118 | blockHash[currentBlockNumber] = _prevBlockHash; 119 | 120 | // Setting new block number and timestamp 121 | currentBlockInfo = (currentBlockNumber + 1) * BLOCK_INFO_BLOCK_NUMBER_PART + _newTimestamp; 122 | 123 | baseFee = _baseFee; 124 | 125 | // The correctness of this block hash and the timestamp will be checked on L1: 126 | SystemContractHelper.toL1(false, bytes32(_newTimestamp), _prevBlockHash); 127 | } 128 | 129 | /// @notice A testing method that manually sets the current blocks' number and timestamp. 130 | /// @dev Should be used only for testing / ethCalls and should never be used in production. 131 | function unsafeOverrideBlock(uint256 _newTimestamp, uint256 number, uint256 _baseFee) external onlyBootloader { 132 | currentBlockInfo = (number) * BLOCK_INFO_BLOCK_NUMBER_PART + _newTimestamp; 133 | baseFee = _baseFee; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../libraries/TransactionHelper.sol"; 6 | 7 | bytes4 constant ACCOUNT_VALIDATION_SUCCESS_MAGIC = IAccount.validateTransaction.selector; 8 | 9 | interface IAccount { 10 | /// @notice Called by the bootloader to validate that an account agrees to process the transaction 11 | /// (and potentially pay for it). 12 | /// @param _txHash The hash of the transaction to be used in the explorer 13 | /// @param _suggestedSignedHash The hash of the transaction is signed by EOAs 14 | /// @param _transaction The transaction itself 15 | /// @return magic The magic value that should be equal to the signature of this function 16 | /// if the user agrees to proceed with the transaction. 17 | /// @dev The developer should strive to preserve as many steps as possible both for valid 18 | /// and invalid transactions as this very method is also used during the gas fee estimation 19 | /// (without some of the necessary data, e.g. signature). 20 | function validateTransaction( 21 | bytes32 _txHash, 22 | bytes32 _suggestedSignedHash, 23 | Transaction calldata _transaction 24 | ) external payable returns (bytes4 magic); 25 | 26 | function executeTransaction( 27 | bytes32 _txHash, 28 | bytes32 _suggestedSignedHash, 29 | Transaction calldata _transaction 30 | ) external payable; 31 | 32 | // There is no point in providing possible signed hash in the `executeTransactionFromOutside` method, 33 | // since it typically should not be trusted. 34 | function executeTransactionFromOutside(Transaction calldata _transaction) external payable; 35 | 36 | function payForTransaction( 37 | bytes32 _txHash, 38 | bytes32 _suggestedSignedHash, 39 | Transaction calldata _transaction 40 | ) external payable; 41 | 42 | function prepareForPaymaster( 43 | bytes32 _txHash, 44 | bytes32 _possibleSignedHash, 45 | Transaction calldata _transaction 46 | ) external payable; 47 | } 48 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IAccountCodeStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IAccountCodeStorage { 6 | function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external; 7 | 8 | function storeAccountConstructedCodeHash(address _address, bytes32 _hash) external; 9 | 10 | function markAccountCodeHashAsConstructed(address _address) external; 11 | 12 | function getRawCodeHash(address _address) external view returns (bytes32 codeHash); 13 | 14 | function getCodeHash(uint256 _input) external view returns (bytes32 codeHash); 15 | 16 | function getCodeSize(uint256 _input) external view returns (uint256 codeSize); 17 | } 18 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IBootloaderUtilities.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../libraries/TransactionHelper.sol"; 6 | 7 | interface IBootloaderUtilities { 8 | function getTransactionHashes( 9 | Transaction calldata _transaction 10 | ) external view returns (bytes32 txHash, bytes32 signedTxHash); 11 | } 12 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IBytecodeCompressor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IBytecodeCompressor { 6 | function publishCompressedBytecode( 7 | bytes calldata _bytecode, 8 | bytes calldata _rawCompressedData 9 | ) external payable returns (bytes32 bytecodeHash); 10 | } 11 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IContractDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IContractDeployer { 6 | /// @notice Defines the version of the account abstraction protocol 7 | /// that a contract claims to follow. 8 | /// - `None` means that the account is just a contract and it should never be interacted 9 | /// with as a custom account 10 | /// - `Version1` means that the account follows the first version of the account abstraction protocol 11 | enum AccountAbstractionVersion { 12 | None, 13 | Version1 14 | } 15 | 16 | /// @notice Defines the nonce ordering used by the account 17 | /// - `Sequential` means that it is expected that the nonces are monotonic and increment by 1 18 | /// at a time (the same as EOAs). 19 | /// - `Arbitrary` means that the nonces for the accounts can be arbitrary. The operator 20 | /// should serve the transactions from such an account on a first-come-first-serve basis. 21 | /// @dev This ordering is more of a suggestion to the operator on how the AA expects its transactions 22 | /// to be processed and is not considered as a system invariant. 23 | enum AccountNonceOrdering { 24 | Sequential, 25 | Arbitrary 26 | } 27 | 28 | struct AccountInfo { 29 | AccountAbstractionVersion supportedAAVersion; 30 | AccountNonceOrdering nonceOrdering; 31 | } 32 | 33 | event ContractDeployed( 34 | address indexed deployerAddress, 35 | bytes32 indexed bytecodeHash, 36 | address indexed contractAddress 37 | ); 38 | 39 | event AccountNonceOrderingUpdated(address indexed accountAddress, AccountNonceOrdering nonceOrdering); 40 | 41 | event AccountVersionUpdated(address indexed accountAddress, AccountAbstractionVersion aaVersion); 42 | 43 | function getNewAddressCreate2( 44 | address _sender, 45 | bytes32 _bytecodeHash, 46 | bytes32 _salt, 47 | bytes calldata _input 48 | ) external view returns (address newAddress); 49 | 50 | function getNewAddressCreate(address _sender, uint256 _senderNonce) external pure returns (address newAddress); 51 | 52 | function create2( 53 | bytes32 _salt, 54 | bytes32 _bytecodeHash, 55 | bytes calldata _input 56 | ) external payable returns (address newAddress); 57 | 58 | function create2Account( 59 | bytes32 _salt, 60 | bytes32 _bytecodeHash, 61 | bytes calldata _input, 62 | AccountAbstractionVersion _aaVersion 63 | ) external payable returns (address newAddress); 64 | 65 | /// @dev While the `_salt` parameter is not used anywhere here, 66 | /// it is still needed for consistency between `create` and 67 | /// `create2` functions (required by the compiler). 68 | function create( 69 | bytes32 _salt, 70 | bytes32 _bytecodeHash, 71 | bytes calldata _input 72 | ) external payable returns (address newAddress); 73 | 74 | /// @dev While `_salt` is never used here, we leave it here as a parameter 75 | /// for the consistency with the `create` function. 76 | function createAccount( 77 | bytes32 _salt, 78 | bytes32 _bytecodeHash, 79 | bytes calldata _input, 80 | AccountAbstractionVersion _aaVersion 81 | ) external payable returns (address newAddress); 82 | 83 | /// @notice Returns the information about a certain AA. 84 | function getAccountInfo(address _address) external view returns (AccountInfo memory info); 85 | 86 | /// @notice Can be called by an account to update its account version 87 | function updateAccountVersion(AccountAbstractionVersion _version) external; 88 | 89 | /// @notice Can be called by an account to update its nonce ordering 90 | function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external; 91 | } 92 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IEthToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IEthToken { 6 | function balanceOf(uint256) external view returns (uint256); 7 | 8 | function transferFromTo(address _from, address _to, uint256 _amount) external; 9 | 10 | function totalSupply() external view returns (uint256); 11 | 12 | function name() external pure returns (string memory); 13 | 14 | function symbol() external pure returns (string memory); 15 | 16 | function decimals() external pure returns (uint8); 17 | 18 | function mint(address _account, uint256 _amount) external; 19 | 20 | function withdraw(address _l1Receiver) external payable; 21 | 22 | event Mint(address indexed account, uint256 amount); 23 | 24 | event Transfer(address indexed from, address indexed to, uint256 value); 25 | 26 | event Withdrawal(address indexed _l2Sender, address indexed _l1Receiver, uint256 _amount); 27 | } 28 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IImmutableSimulator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | struct ImmutableData { 6 | uint256 index; 7 | bytes32 value; 8 | } 9 | 10 | interface IImmutableSimulator { 11 | function getImmutable(address _dest, uint256 _index) external view returns (bytes32); 12 | 13 | function setImmutables(address _dest, ImmutableData[] calldata _immutables) external; 14 | } 15 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IKnownCodesStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IKnownCodesStorage { 6 | event MarkedAsKnown(bytes32 indexed bytecodeHash, bool indexed sendBytecodeToL1); 7 | 8 | function markFactoryDeps(bool _shouldSendToL1, bytes32[] calldata _hashes) external; 9 | 10 | function markBytecodeAsPublished( 11 | bytes32 _bytecodeHash, 12 | bytes32 _l1PreimageHash, 13 | uint256 _l1PreimageBytesLen 14 | ) external; 15 | 16 | function getMarker(bytes32 _hash) external view returns (uint256); 17 | } 18 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IL1Messenger.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IL1Messenger { 6 | // Possibly in the future we will be able to track the messages sent to L1 with 7 | // some hooks in the VM. For now, it is much easier to track them with L2 events. 8 | event L1MessageSent(address indexed _sender, bytes32 indexed _hash, bytes _message); 9 | 10 | function sendToL1(bytes memory _message) external returns (bytes32); 11 | } 12 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IL2StandardToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IL2StandardToken { 6 | event BridgeMint(address indexed _account, uint256 _amount); 7 | 8 | event BridgeBurn(address indexed _account, uint256 _amount); 9 | 10 | function bridgeMint(address _account, uint256 _amount) external; 11 | 12 | function bridgeBurn(address _account, uint256 _amount) external; 13 | 14 | function l1Address() external view returns (address); 15 | 16 | function l2Bridge() external view returns (address); 17 | } 18 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IMailbox.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IMailbox { 6 | function finalizeEthWithdrawal( 7 | uint256 _l2BlockNumber, 8 | uint256 _l2MessageIndex, 9 | uint16 _l2TxNumberInBlock, 10 | bytes calldata _message, 11 | bytes32[] calldata _merkleProof 12 | ) external; 13 | } 14 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/INonceHolder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @dev Interface of the nonce holder contract -- a contract used by the system to ensure 8 | * that there is always a unique identifier for a transaction with a particular account (we call it nonce). 9 | * In other words, the pair of (address, nonce) should always be unique. 10 | * @dev Custom accounts should use methods of this contract to store nonces or other possible unique identifiers 11 | * for the transaction. 12 | */ 13 | interface INonceHolder { 14 | event ValueSetUnderNonce(address indexed accountAddress, uint256 indexed key, uint256 value); 15 | 16 | /// @dev Returns the current minimal nonce for account. 17 | function getMinNonce(address _address) external view returns (uint256); 18 | 19 | /// @dev Returns the raw version of the current minimal nonce 20 | /// (equal to minNonce + 2^128 * deployment nonce). 21 | function getRawNonce(address _address) external view returns (uint256); 22 | 23 | /// @dev Increases the minimal nonce for the msg.sender. 24 | function increaseMinNonce(uint256 _value) external returns (uint256); 25 | 26 | /// @dev Sets the nonce value `key` as used. 27 | function setValueUnderNonce(uint256 _key, uint256 _value) external; 28 | 29 | /// @dev Gets the value stored inside a custom nonce. 30 | function getValueUnderNonce(uint256 _key) external view returns (uint256); 31 | 32 | /// @dev A convenience method to increment the minimal nonce if it is equal 33 | /// to the `_expectedNonce`. 34 | function incrementMinNonceIfEquals(uint256 _expectedNonce) external; 35 | 36 | /// @dev Returns the deployment nonce for the accounts used for CREATE opcode. 37 | function getDeploymentNonce(address _address) external view returns (uint256); 38 | 39 | /// @dev Increments the deployment nonce for the account and returns the previous one. 40 | function incrementDeploymentNonce(address _address) external returns (uint256); 41 | 42 | /// @dev Determines whether a certain nonce has been already used for an account. 43 | function validateNonceUsage(address _address, uint256 _key, bool _shouldBeUsed) external view; 44 | 45 | /// @dev Returns whether a nonce has been used for an account. 46 | function isNonceUsed(address _address, uint256 _nonce) external view returns (bool); 47 | } 48 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IPaymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../libraries/TransactionHelper.sol"; 6 | 7 | enum ExecutionResult { 8 | Revert, 9 | Success 10 | } 11 | 12 | bytes4 constant PAYMASTER_VALIDATION_SUCCESS_MAGIC = IPaymaster.validateAndPayForPaymasterTransaction.selector; 13 | 14 | interface IPaymaster { 15 | /// @dev Called by the bootloader to verify that the paymaster agrees to pay for the 16 | /// fee for the transaction. This transaction should also send the necessary amount of funds onto the bootloader 17 | /// address. 18 | /// @param _txHash The hash of the transaction 19 | /// @param _suggestedSignedHash The hash of the transaction that is signed by an EOA 20 | /// @param _transaction The transaction itself. 21 | /// @return magic The value that should be equal to the signature of the validateAndPayForPaymasterTransaction 22 | /// if the paymaster agrees to pay for the transaction. 23 | /// @return context The "context" of the transaction: an array of bytes of length at most 1024 bytes, which will be 24 | /// passed to the `postTransaction` method of the account. 25 | /// @dev The developer should strive to preserve as many steps as possible both for valid 26 | /// and invalid transactions as this very method is also used during the gas fee estimation 27 | /// (without some of the necessary data, e.g. signature). 28 | function validateAndPayForPaymasterTransaction( 29 | bytes32 _txHash, 30 | bytes32 _suggestedSignedHash, 31 | Transaction calldata _transaction 32 | ) external payable returns (bytes4 magic, bytes memory context); 33 | 34 | /// @dev Called by the bootloader after the execution of the transaction. Please note that 35 | /// there is no guarantee that this method will be called at all. Unlike the original EIP4337, 36 | /// this method won't be called if the transaction execution results in out-of-gas. 37 | /// @param _context, the context of the execution, returned by the "validateAndPayForPaymasterTransaction" method. 38 | /// @param _transaction, the users' transaction. 39 | /// @param _txResult, the result of the transaction execution (success or failure). 40 | /// @param _maxRefundedGas, the upper bound on the amout of gas that could be refunded to the paymaster. 41 | /// @dev The exact amount refunded depends on the gas spent by the "postOp" itself and so the developers should 42 | /// take that into account. 43 | function postTransaction( 44 | bytes calldata _context, 45 | Transaction calldata _transaction, 46 | bytes32 _txHash, 47 | bytes32 _suggestedSignedHash, 48 | ExecutionResult _txResult, 49 | uint256 _maxRefundedGas 50 | ) external payable; 51 | } 52 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/IPaymasterFlow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @dev The interface that is used for encoding/decoding of 8 | * different types of paymaster flows. 9 | * @notice This is NOT an interface to be implementated 10 | * by contracts. It is just used for encoding. 11 | */ 12 | interface IPaymasterFlow { 13 | function general(bytes calldata input) external; 14 | 15 | function approvalBased(address _token, uint256 _minAllowance, bytes calldata _innerInput) external; 16 | } 17 | -------------------------------------------------------------------------------- /l2/system-contracts/interfaces/ISystemContext.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @notice Contract that stores some of the context variables, that may be either 8 | * block-scoped, tx-scoped or system-wide. 9 | */ 10 | interface ISystemContext { 11 | function chainId() external view returns (uint256); 12 | 13 | function origin() external view returns (address); 14 | 15 | function gasPrice() external view returns (uint256); 16 | 17 | function blockGasLimit() external view returns (uint256); 18 | 19 | function coinbase() external view returns (address); 20 | 21 | function difficulty() external view returns (uint256); 22 | 23 | function baseFee() external view returns (uint256); 24 | 25 | function blockHash(uint256 _block) external view returns (bytes32); 26 | 27 | function getBlockHashEVM(uint256 _block) external view returns (bytes32); 28 | 29 | function getBlockNumberAndTimestamp() external view returns (uint256 blockNumber, uint256 blockTimestamp); 30 | 31 | // Note, that for now, the implementation of the bootloader allows this variables to 32 | // be incremented multiple times inside a block, so it should not relied upon right now. 33 | function getBlockNumber() external view returns (uint256); 34 | 35 | function getBlockTimestamp() external view returns (uint256); 36 | } 37 | -------------------------------------------------------------------------------- /l2/system-contracts/libraries/RLPEncoder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | library RLPEncoder { 6 | function encodeAddress(address _val) internal pure returns (bytes memory encoded) { 7 | // The size is equal to 20 bytes of the address itself + 1 for encoding bytes length in RLP. 8 | encoded = new bytes(0x15); 9 | 10 | bytes20 shiftedVal = bytes20(_val); 11 | assembly { 12 | // In the first byte we write the encoded length as 0x80 + 0x14 == 0x94. 13 | mstore(add(encoded, 0x20), 0x9400000000000000000000000000000000000000000000000000000000000000) 14 | // Write address data without stripping zeros. 15 | mstore(add(encoded, 0x21), shiftedVal) 16 | } 17 | } 18 | 19 | function encodeUint256(uint256 _val) internal pure returns (bytes memory encoded) { 20 | unchecked { 21 | if (_val < 128) { 22 | encoded = new bytes(1); 23 | // Handle zero as a non-value, since stripping zeroes results in an empty byte array 24 | encoded[0] = (_val == 0) ? bytes1(uint8(128)) : bytes1(uint8(_val)); 25 | } else { 26 | uint256 hbs = _highestByteSet(_val); 27 | 28 | encoded = new bytes(hbs + 2); 29 | encoded[0] = bytes1(uint8(hbs + 0x81)); 30 | 31 | uint256 lbs = 31 - hbs; 32 | uint256 shiftedVal = _val << (lbs * 8); 33 | 34 | assembly { 35 | mstore(add(encoded, 0x21), shiftedVal) 36 | } 37 | } 38 | } 39 | } 40 | 41 | /// @notice Encodes the size of bytes in RLP format. 42 | /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. 43 | /// NOTE: panics if the length is 1 since the length encoding is ambiguous in this case. 44 | function encodeNonSingleBytesLen(uint64 _len) internal pure returns (bytes memory) { 45 | assert(_len != 1); 46 | return _encodeLength(_len, 0x80); 47 | } 48 | 49 | /// @notice Encodes the size of list items in RLP format. 50 | /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. 51 | function encodeListLen(uint64 _len) internal pure returns (bytes memory) { 52 | return _encodeLength(_len, 0xc0); 53 | } 54 | 55 | function _encodeLength(uint64 _len, uint256 _offset) private pure returns (bytes memory encoded) { 56 | unchecked { 57 | if (_len < 56) { 58 | encoded = new bytes(1); 59 | encoded[0] = bytes1(uint8(_len + _offset)); 60 | } else { 61 | uint256 hbs = _highestByteSet(uint256(_len)); 62 | 63 | encoded = new bytes(hbs + 2); 64 | encoded[0] = bytes1(uint8(_offset + hbs + 56)); 65 | 66 | uint256 lbs = 31 - hbs; 67 | uint256 shiftedVal = uint256(_len) << (lbs * 8); 68 | 69 | assembly { 70 | mstore(add(encoded, 0x21), shiftedVal) 71 | } 72 | } 73 | } 74 | } 75 | 76 | /// @notice Computes the index of the highest byte set in number. 77 | /// @notice Uses little endian ordering (The least significant byte has index `0`). 78 | /// NOTE: returns `0` for `0` 79 | function _highestByteSet(uint256 _number) private pure returns (uint256 hbs) { 80 | unchecked { 81 | if (_number > type(uint128).max) { 82 | _number >>= 128; 83 | hbs += 16; 84 | } 85 | if (_number > type(uint64).max) { 86 | _number >>= 64; 87 | hbs += 8; 88 | } 89 | if (_number > type(uint32).max) { 90 | _number >>= 32; 91 | hbs += 4; 92 | } 93 | if (_number > type(uint16).max) { 94 | _number >>= 16; 95 | hbs += 2; 96 | } 97 | if (_number > type(uint8).max) { 98 | hbs += 1; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /l2/system-contracts/libraries/UnsafeBytesCalldata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT OR Apache-2.0 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @author Matter Labs 7 | * @dev The library provides a set of functions that help read data from calldata bytes. 8 | * @dev Each of the functions accepts the `bytes calldata` and the offset where data should be read and returns a value of a certain type. 9 | * 10 | * @dev WARNING! 11 | * 1) Functions don't check the length of the bytes array, so it can go out of bounds. 12 | * The user of the library must check for bytes length before using any functions from the library! 13 | * 14 | * 2) Read variables are not cleaned up - https://docs.soliditylang.org/en/v0.8.16/internals/variable_cleanup.html. 15 | * Using data in inline assembly can lead to unexpected behavior! 16 | */ 17 | library UnsafeBytesCalldata { 18 | function readUint16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16 result) { 19 | assembly { 20 | let offset := sub(_bytes.offset, 30) 21 | result := calldataload(add(offset, _start)) 22 | } 23 | } 24 | 25 | function readUint64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64 result) { 26 | assembly { 27 | let offset := sub(_bytes.offset, 24) 28 | result := calldataload(add(offset, _start)) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /l2/system-contracts/libraries/Utils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0; 3 | 4 | import "./EfficientCall.sol"; 5 | 6 | /** 7 | * @author Matter Labs 8 | * @dev Common utilities used in zkSync system contracts 9 | */ 10 | library Utils { 11 | /// @dev Bit mask of bytecode hash "isConstructor" marker 12 | bytes32 constant IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK = 13 | 0x00ff000000000000000000000000000000000000000000000000000000000000; 14 | 15 | /// @dev Bit mask to set the "isConstructor" marker in the bytecode hash 16 | bytes32 constant SET_IS_CONSTRUCTOR_MARKER_BIT_MASK = 17 | 0x0001000000000000000000000000000000000000000000000000000000000000; 18 | 19 | function safeCastToU128(uint256 _x) internal pure returns (uint128) { 20 | require(_x <= type(uint128).max, "Overflow"); 21 | 22 | return uint128(_x); 23 | } 24 | 25 | function safeCastToU32(uint256 _x) internal pure returns (uint32) { 26 | require(_x <= type(uint32).max, "Overflow"); 27 | 28 | return uint32(_x); 29 | } 30 | 31 | function safeCastToU24(uint256 _x) internal pure returns (uint24) { 32 | require(_x <= type(uint24).max, "Overflow"); 33 | 34 | return uint24(_x); 35 | } 36 | 37 | /// @return codeLength The bytecode length in bytes 38 | function bytecodeLenInBytes(bytes32 _bytecodeHash) internal pure returns (uint256 codeLength) { 39 | codeLength = bytecodeLenInWords(_bytecodeHash) << 5; // _bytecodeHash * 32 40 | } 41 | 42 | /// @return codeLengthInWords The bytecode length in machine words 43 | function bytecodeLenInWords(bytes32 _bytecodeHash) internal pure returns (uint256 codeLengthInWords) { 44 | unchecked { 45 | codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3])); 46 | } 47 | } 48 | 49 | /// @notice Denotes whether bytecode hash corresponds to a contract that already constructed 50 | function isContractConstructed(bytes32 _bytecodeHash) internal pure returns (bool) { 51 | return _bytecodeHash[1] == 0x00; 52 | } 53 | 54 | /// @notice Denotes whether bytecode hash corresponds to a contract that is on constructor or has already been constructed 55 | function isContractConstructing(bytes32 _bytecodeHash) internal pure returns (bool) { 56 | return _bytecodeHash[1] == 0x01; 57 | } 58 | 59 | /// @notice Sets "isConstructor" flag to TRUE for the bytecode hash 60 | /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag 61 | /// @return The bytecode hash with "isConstructor" flag set to TRUE 62 | function constructingBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { 63 | // Clear the "isConstructor" marker and set it to 0x01. 64 | return constructedBytecodeHash(_bytecodeHash) | SET_IS_CONSTRUCTOR_MARKER_BIT_MASK; 65 | } 66 | 67 | /// @notice Sets "isConstructor" flag to FALSE for the bytecode hash 68 | /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag 69 | /// @return The bytecode hash with "isConstructor" flag set to FALSE 70 | function constructedBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { 71 | return _bytecodeHash & ~IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK; 72 | } 73 | 74 | /// @notice Validate the bytecode format and calculate its hash. 75 | /// @param _bytecode The bytecode to hash. 76 | /// @return hashedBytecode The 32-byte hash of the bytecode. 77 | /// Note: The function reverts the execution if the bytecode has non expected format: 78 | /// - Bytecode bytes length is not a multiple of 32 79 | /// - Bytecode bytes length is not less than 2^21 bytes (2^16 words) 80 | /// - Bytecode words length is not odd 81 | function hashL2Bytecode(bytes calldata _bytecode) internal view returns (bytes32 hashedBytecode) { 82 | // Note that the length of the bytecode must be provided in 32-byte words. 83 | require(_bytecode.length % 32 == 0, "po"); 84 | 85 | uint256 bytecodeLenInWords = _bytecode.length / 32; 86 | require(bytecodeLenInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words 87 | require(bytecodeLenInWords % 2 == 1, "pr"); // bytecode length in words must be odd 88 | hashedBytecode = 89 | EfficientCall.sha(_bytecode) & 90 | 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 91 | // Setting the version of the hash 92 | hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); 93 | // Setting the length 94 | hashedBytecode = hashedBytecode | bytes32(bytecodeLenInWords << 224); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /l2/system-contracts/openzeppelin/token/ERC20/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC20 standard as defined in the EIP. 8 | */ 9 | interface IERC20 { 10 | /** 11 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 12 | * another (`to`). 13 | * 14 | * Note that `value` may be zero. 15 | */ 16 | event Transfer(address indexed from, address indexed to, uint256 value); 17 | 18 | /** 19 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 20 | * a call to {approve}. `value` is the new allowance. 21 | */ 22 | event Approval(address indexed owner, address indexed spender, uint256 value); 23 | 24 | /** 25 | * @dev Returns the amount of tokens in existence. 26 | */ 27 | function totalSupply() external view returns (uint256); 28 | 29 | /** 30 | * @dev Returns the amount of tokens owned by `account`. 31 | */ 32 | function balanceOf(address account) external view returns (uint256); 33 | 34 | /** 35 | * @dev Moves `amount` tokens from the caller's account to `to`. 36 | * 37 | * Returns a boolean value indicating whether the operation succeeded. 38 | * 39 | * Emits a {Transfer} event. 40 | */ 41 | function transfer(address to, uint256 amount) external returns (bool); 42 | 43 | /** 44 | * @dev Returns the remaining number of tokens that `spender` will be 45 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 46 | * zero by default. 47 | * 48 | * This value changes when {approve} or {transferFrom} are called. 49 | */ 50 | function allowance(address owner, address spender) external view returns (uint256); 51 | 52 | /** 53 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 54 | * 55 | * Returns a boolean value indicating whether the operation succeeded. 56 | * 57 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 58 | * that someone may use both the old and the new allowance by unfortunate 59 | * transaction ordering. One possible solution to mitigate this race 60 | * condition is to first reduce the spender's allowance to 0 and set the 61 | * desired value afterwards: 62 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 63 | * 64 | * Emits an {Approval} event. 65 | */ 66 | function approve(address spender, uint256 amount) external returns (bool); 67 | 68 | /** 69 | * @dev Moves `amount` tokens from `from` to `to` using the 70 | * allowance mechanism. `amount` is then deducted from the caller's 71 | * allowance. 72 | * 73 | * Returns a boolean value indicating whether the operation succeeded. 74 | * 75 | * Emits a {Transfer} event. 76 | */ 77 | function transferFrom( 78 | address from, 79 | address to, 80 | uint256 amount 81 | ) external returns (bool); 82 | } 83 | -------------------------------------------------------------------------------- /l2/system-contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 8 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 9 | * 10 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 11 | * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't 12 | * need to send a transaction, and thus is not required to hold Ether at all. 13 | */ 14 | interface IERC20Permit { 15 | /** 16 | * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, 17 | * given ``owner``'s signed approval. 18 | * 19 | * IMPORTANT: The same issues {IERC20-approve} has related to transaction 20 | * ordering also apply here. 21 | * 22 | * Emits an {Approval} event. 23 | * 24 | * Requirements: 25 | * 26 | * - `spender` cannot be the zero address. 27 | * - `deadline` must be a timestamp in the future. 28 | * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` 29 | * over the EIP712-formatted function arguments. 30 | * - the signature must use ``owner``'s current nonce (see {nonces}). 31 | * 32 | * For more information on the signature format, see the 33 | * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP 34 | * section]. 35 | */ 36 | function permit( 37 | address owner, 38 | address spender, 39 | uint256 value, 40 | uint256 deadline, 41 | uint8 v, 42 | bytes32 r, 43 | bytes32 s 44 | ) external; 45 | 46 | /** 47 | * @dev Returns the current nonce for `owner`. This value must be 48 | * included whenever a signature is generated for {permit}. 49 | * 50 | * Every successful call to {permit} increases ``owner``'s nonce by one. This 51 | * prevents a signature from being used multiple times. 52 | */ 53 | function nonces(address owner) external view returns (uint256); 54 | 55 | /** 56 | * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. 57 | */ 58 | // solhint-disable-next-line func-name-mixedcase 59 | function DOMAIN_SEPARATOR() external view returns (bytes32); 60 | } 61 | -------------------------------------------------------------------------------- /l2/system-contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../IERC20.sol"; 7 | import "../extensions/IERC20Permit.sol"; 8 | import "../../../utils/Address.sol"; 9 | 10 | /** 11 | * @title SafeERC20 12 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 13 | * contract returns false). Tokens that return no value (and instead revert or 14 | * throw on failure) are also supported, non-reverting calls are assumed to be 15 | * successful. 16 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 17 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 18 | */ 19 | library SafeERC20 { 20 | using Address for address; 21 | 22 | function safeTransfer( 23 | IERC20 token, 24 | address to, 25 | uint256 value 26 | ) internal { 27 | _callOptionalReturn( 28 | token, 29 | abi.encodeWithSelector(token.transfer.selector, to, value) 30 | ); 31 | } 32 | 33 | function safeTransferFrom( 34 | IERC20 token, 35 | address from, 36 | address to, 37 | uint256 value 38 | ) internal { 39 | _callOptionalReturn( 40 | token, 41 | abi.encodeWithSelector(token.transferFrom.selector, from, to, value) 42 | ); 43 | } 44 | 45 | /** 46 | * @dev Deprecated. This function has issues similar to the ones found in 47 | * {IERC20-approve}, and its usage is discouraged. 48 | * 49 | * Whenever possible, use {safeIncreaseAllowance} and 50 | * {safeDecreaseAllowance} instead. 51 | */ 52 | function safeApprove( 53 | IERC20 token, 54 | address spender, 55 | uint256 value 56 | ) internal { 57 | // safeApprove should only be called when setting an initial allowance, 58 | // or when resetting it to zero. To increase and decrease it, use 59 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 60 | require( 61 | (value == 0) || (token.allowance(address(this), spender) == 0), 62 | "SafeERC20: approve from non-zero to non-zero allowance" 63 | ); 64 | _callOptionalReturn( 65 | token, 66 | abi.encodeWithSelector(token.approve.selector, spender, value) 67 | ); 68 | } 69 | 70 | function safeIncreaseAllowance( 71 | IERC20 token, 72 | address spender, 73 | uint256 value 74 | ) internal { 75 | uint256 newAllowance = token.allowance(address(this), spender) + value; 76 | _callOptionalReturn( 77 | token, 78 | abi.encodeWithSelector( 79 | token.approve.selector, 80 | spender, 81 | newAllowance 82 | ) 83 | ); 84 | } 85 | 86 | function safeDecreaseAllowance( 87 | IERC20 token, 88 | address spender, 89 | uint256 value 90 | ) internal { 91 | unchecked { 92 | uint256 oldAllowance = token.allowance(address(this), spender); 93 | require( 94 | oldAllowance >= value, 95 | "SafeERC20: decreased allowance below zero" 96 | ); 97 | uint256 newAllowance = oldAllowance - value; 98 | _callOptionalReturn( 99 | token, 100 | abi.encodeWithSelector( 101 | token.approve.selector, 102 | spender, 103 | newAllowance 104 | ) 105 | ); 106 | } 107 | } 108 | 109 | function safePermit( 110 | IERC20Permit token, 111 | address owner, 112 | address spender, 113 | uint256 value, 114 | uint256 deadline, 115 | uint8 v, 116 | bytes32 r, 117 | bytes32 s 118 | ) internal { 119 | uint256 nonceBefore = token.nonces(owner); 120 | token.permit(owner, spender, value, deadline, v, r, s); 121 | uint256 nonceAfter = token.nonces(owner); 122 | require( 123 | nonceAfter == nonceBefore + 1, 124 | "SafeERC20: permit did not succeed" 125 | ); 126 | } 127 | 128 | /** 129 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 130 | * on the return value: the return value is optional (but if data is returned, it must not be false). 131 | * @param token The token targeted by the call. 132 | * @param data The call data (encoded using abi.encode or one of its variants). 133 | */ 134 | function _callOptionalReturn(IERC20 token, bytes memory data) private { 135 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 136 | // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that 137 | // the target address contains contract code and also asserts for success in the low-level call. 138 | 139 | bytes memory returndata = address(token).functionCall( 140 | data, 141 | "SafeERC20: low-level call failed" 142 | ); 143 | if (returndata.length > 0) { 144 | // Return data is optional 145 | require( 146 | abi.decode(returndata, (bool)), 147 | "SafeERC20: ERC20 operation did not succeed" 148 | ); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /l2/system-contracts/precompiles/Ecrecover.yul: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Matter Labs 3 | * @notice The contract used to emulate EVM's ecrecover precompile. 4 | * @dev It uses `precompileCall` to call the zkEVM built-in precompiles. 5 | */ 6 | object "Ecrecover" { 7 | code { } 8 | object "Ecrecover_deployed" { 9 | code { 10 | //////////////////////////////////////////////////////////////// 11 | // CONSTANTS 12 | //////////////////////////////////////////////////////////////// 13 | 14 | // Group order of secp256k1, see https://en.bitcoin.it/wiki/Secp256k1 15 | function SECP256K1_GROUP_SIZE() -> ret { 16 | ret := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 17 | } 18 | 19 | /// @dev The gas cost of processing ecrecover circuit precompile. 20 | function ECRECOVER_GAS_COST() -> ret { 21 | ret := 1112 22 | } 23 | 24 | //////////////////////////////////////////////////////////////// 25 | // HELPER FUNCTIONS 26 | //////////////////////////////////////////////////////////////// 27 | 28 | // @dev Packs precompile parameters into one word. 29 | // Note: functions expect to work with 32/64 bits unsigned integers. 30 | // Caller should ensure the type matching before! 31 | function unsafePackPrecompileParams( 32 | uint32_inputOffsetInWords, 33 | uint32_inputLengthInWords, 34 | uint32_outputOffsetInWords, 35 | uint32_outputLengthInWords, 36 | uint64_perPrecompileInterpreted 37 | ) -> rawParams { 38 | rawParams := uint32_inputOffsetInWords 39 | rawParams := or(rawParams, shl(32, uint32_inputLengthInWords)) 40 | rawParams := or(rawParams, shl(64, uint32_outputOffsetInWords)) 41 | rawParams := or(rawParams, shl(96, uint32_outputLengthInWords)) 42 | rawParams := or(rawParams, shl(192, uint64_perPrecompileInterpreted)) 43 | } 44 | 45 | /// @dev Executes the `precompileCall` opcode. 46 | function precompileCall(precompileParams, gasToBurn) -> ret { 47 | // Compiler simulation for calling `precompileCall` opcode 48 | ret := verbatim_2i_1o("precompile", precompileParams, gasToBurn) 49 | } 50 | 51 | //////////////////////////////////////////////////////////////// 52 | // FALLBACK 53 | //////////////////////////////////////////////////////////////// 54 | 55 | let digest := calldataload(0) 56 | let v := calldataload(32) 57 | let r := calldataload(64) 58 | let s := calldataload(96) 59 | 60 | // Validate the input by the yellow paper rules (Appendix E. Precompiled contracts) 61 | let vIsInvalid := iszero(or(eq(v, 27), eq(v, 28))) 62 | let sIsInvalid := or(eq(s, 0), gt(s, sub(SECP256K1_GROUP_SIZE(), 1))) 63 | let rIsInvalid := or(eq(r, 0), gt(r, sub(SECP256K1_GROUP_SIZE(), 1))) 64 | 65 | if or(vIsInvalid, or(sIsInvalid, rIsInvalid)) { 66 | return(0, 0) 67 | } 68 | 69 | // Store the data in memory, so the ecrecover circuit will read it 70 | mstore(0, digest) 71 | mstore(32, sub(v, 27)) 72 | mstore(64, r) 73 | mstore(96, s) 74 | 75 | let precompileParams := unsafePackPrecompileParams( 76 | 0, // input offset in words 77 | 4, // input length in words (the signed digest, v, r, s) 78 | 0, // output offset in words 79 | 2, // output length in words (success, signer) 80 | 0 // No special meaning, ecrecover circuit doesn't check this value 81 | ) 82 | let gasToPay := ECRECOVER_GAS_COST() 83 | 84 | // Check whether the call is successfully handled by the ecrecover circuit 85 | let success := precompileCall(precompileParams, gasToPay) 86 | let internalSuccess := mload(0) 87 | 88 | switch and(success, internalSuccess) 89 | case 0 { 90 | return(0, 0) 91 | } 92 | default { 93 | return(32, 32) 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /l2/system-contracts/precompiles/Keccak256.yul: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Matter Labs 3 | * @notice The contract used to emulate EVM's keccak256 opcode. 4 | * @dev It accepts the data to be hashed, pad it by the specification 5 | * and uses `precompileCall` to call the zkEVM built-in precompiles. 6 | * @dev Thus keccak256 precompile circuit operates over padded data to perform efficient sponge round computation. 7 | */ 8 | object "Keccak256" { 9 | code { } 10 | object "Keccak256_deployed" { 11 | code { 12 | //////////////////////////////////////////////////////////////// 13 | // CONSTANTS 14 | //////////////////////////////////////////////////////////////// 15 | 16 | /// @dev The size of the processing keccak256 block in bytes. 17 | function BLOCK_SIZE() -> ret { 18 | ret := 136 19 | } 20 | 21 | /// @dev The gas cost of processing one keccak256 round. 22 | function KECCAK_ROUND_GAS_COST() -> ret { 23 | ret := 40 24 | } 25 | 26 | //////////////////////////////////////////////////////////////// 27 | // HELPER FUNCTIONS 28 | //////////////////////////////////////////////////////////////// 29 | 30 | // @dev Packs precompile parameters into one word. 31 | // Note: functions expect to work with 32/64 bits unsigned integers. 32 | // Caller should ensure the type matching before! 33 | function unsafePackPrecompileParams( 34 | uint32_inputOffsetInWords, 35 | uint32_inputLengthInWords, 36 | uint32_outputOffsetInWords, 37 | uint32_outputLengthInWords, 38 | uint64_perPrecompileInterpreted 39 | ) -> rawParams { 40 | rawParams := uint32_inputOffsetInWords 41 | rawParams := or(rawParams, shl(32, uint32_inputLengthInWords)) 42 | rawParams := or(rawParams, shl(64, uint32_outputOffsetInWords)) 43 | rawParams := or(rawParams, shl(96, uint32_outputLengthInWords)) 44 | rawParams := or(rawParams, shl(192, uint64_perPrecompileInterpreted)) 45 | } 46 | 47 | /// @dev Executes the `precompileCall` opcode. 48 | function precompileCall(precompileParams, gasToBurn) -> ret { 49 | // Compiler simulation for calling `precompileCall` opcode 50 | ret := verbatim_2i_1o("precompile", precompileParams, gasToBurn) 51 | } 52 | 53 | //////////////////////////////////////////////////////////////// 54 | // FALLBACK 55 | //////////////////////////////////////////////////////////////// 56 | 57 | // Copy calldata to memory for pad it 58 | let bytesSize := calldatasize() 59 | calldatacopy(0, 0, bytesSize) 60 | 61 | let precompileParams 62 | let gasToPay 63 | 64 | // Most often keccak256 is called with "short" input, so optimize it as a special case. 65 | // NOTE: we consider the special case for sizes less than `BLOCK_SIZE() - 1`, so 66 | // there is only one round and it is and padding can be done branchless 67 | switch lt(bytesSize, sub(BLOCK_SIZE(), 1)) 68 | case true { 69 | // Write the 0x01 after the payload bytes and 0x80 at last byte of padded bytes 70 | mstore(bytesSize, 0x0100000000000000000000000000000000000000000000000000000000000000) 71 | mstore( 72 | sub(BLOCK_SIZE(), 1), 73 | 0x8000000000000000000000000000000000000000000000000000000000000000 74 | ) 75 | 76 | precompileParams := unsafePackPrecompileParams( 77 | 0, // input offset in words 78 | 5, // input length in words (Math.ceil(136/32) = 5) 79 | 0, // output offset in words 80 | 1, // output length in words 81 | 1 // number of rounds 82 | ) 83 | gasToPay := KECCAK_ROUND_GAS_COST() 84 | } 85 | default { 86 | let padLen := sub(BLOCK_SIZE(), mod(bytesSize, BLOCK_SIZE())) 87 | let paddedByteSize := add(bytesSize, padLen) 88 | 89 | switch eq(padLen, 1) 90 | case true { 91 | // Write 0x81 after the payload bytes 92 | mstore(bytesSize, 0x8100000000000000000000000000000000000000000000000000000000000000) 93 | } 94 | default { 95 | // Write the 0x01 after the payload bytes and 0x80 at last byte of padded bytes 96 | mstore(bytesSize, 0x0100000000000000000000000000000000000000000000000000000000000000) 97 | mstore( 98 | sub(paddedByteSize, 1), 99 | 0x8000000000000000000000000000000000000000000000000000000000000000 100 | ) 101 | } 102 | 103 | let numRounds := div(paddedByteSize, BLOCK_SIZE()) 104 | precompileParams := unsafePackPrecompileParams( 105 | 0, // input offset in words 106 | div(add(paddedByteSize, 31), 32), // input length in words (safe to pass, never exceed `type(uint32).max`) 107 | 0, // output offset in words 108 | 1, // output length in words 109 | numRounds // number of rounds (safe to pass, never exceed `type(uint64).max`) 110 | ) 111 | gasToPay := mul(KECCAK_ROUND_GAS_COST(), numRounds) 112 | } 113 | 114 | let success := precompileCall(precompileParams, gasToPay) 115 | 116 | switch success 117 | case 0 { 118 | revert(0, 0) 119 | } 120 | default { 121 | return(0, 32) 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /l2/system-contracts/precompiles/SHA256.yul: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Matter Labs 3 | * @notice The contract used to emulate EVM's sha256 precompile. 4 | * @dev It accepts the data to be hashed, pad it by the specification 5 | * and uses `precompileCall` to call the zkEVM built-in precompiles. 6 | * @dev Thus sha256 precompile circuit operates over padded data to perform efficient sponge round computation. 7 | */ 8 | object "SHA256" { 9 | code { } 10 | object "SHA256_deployed" { 11 | code { 12 | //////////////////////////////////////////////////////////////// 13 | // CONSTANTS 14 | //////////////////////////////////////////////////////////////// 15 | 16 | /// @dev The size of the processing sha256 block in bytes. 17 | function BLOCK_SIZE() -> ret { 18 | ret := 64 19 | } 20 | 21 | /// @dev The gas cost of processing one sha256 round. 22 | function SHA256_ROUND_GAS_COST() -> ret { 23 | ret := 7 24 | } 25 | 26 | //////////////////////////////////////////////////////////////// 27 | // HELPER FUNCTIONS 28 | //////////////////////////////////////////////////////////////// 29 | 30 | // @dev Packs precompile parameters into one word. 31 | // Note: functions expect to work with 32/64 bits unsigned integers. 32 | // Caller should ensure the type matching before! 33 | function unsafePackPrecompileParams( 34 | uint32_inputOffsetInWords, 35 | uint32_inputLengthInWords, 36 | uint32_outputOffsetInWords, 37 | uint32_outputLengthInWords, 38 | uint64_perPrecompileInterpreted 39 | ) -> rawParams { 40 | rawParams := uint32_inputOffsetInWords 41 | rawParams := or(rawParams, shl(32, uint32_inputLengthInWords)) 42 | rawParams := or(rawParams, shl(64, uint32_outputOffsetInWords)) 43 | rawParams := or(rawParams, shl(96, uint32_outputLengthInWords)) 44 | rawParams := or(rawParams, shl(192, uint64_perPrecompileInterpreted)) 45 | } 46 | 47 | /// @dev Executes the `precompileCall` opcode. 48 | function precompileCall(precompileParams, gasToBurn) -> ret { 49 | // Compiler simulation for calling `precompileCall` opcode 50 | ret := verbatim_2i_1o("precompile", precompileParams, gasToBurn) 51 | } 52 | 53 | //////////////////////////////////////////////////////////////// 54 | // FALLBACK 55 | //////////////////////////////////////////////////////////////// 56 | 57 | // Copy calldata to memory for pad it 58 | let bytesSize := calldatasize() 59 | calldatacopy(0, 0, bytesSize) 60 | 61 | // The sha256 padding includes additional 8 bytes of the total message's length in bits, 62 | // so calculate the "full" message length with it. 63 | let extendBytesLen := add(bytesSize, 8) 64 | 65 | let padLen := sub(BLOCK_SIZE(), mod(extendBytesLen, BLOCK_SIZE())) 66 | let paddedBytesSize := add(extendBytesLen, padLen) 67 | 68 | // The original message size in bits 69 | let binSize := mul(bytesSize, 8) 70 | // Same bin size, but shifted to the left, needed for the padding 71 | let leftShiftedBinSize := shl(sub(256, 64), binSize) 72 | 73 | // Write 0x80000... as padding according the sha256 specification 74 | mstore(bytesSize, 0x8000000000000000000000000000000000000000000000000000000000000000) 75 | // then will be some zeroes and BE encoded bit length 76 | mstore(sub(paddedBytesSize, 8), leftShiftedBinSize) 77 | 78 | let numRounds := div(paddedBytesSize, BLOCK_SIZE()) 79 | let precompileParams := unsafePackPrecompileParams( 80 | 0, // input offset in words 81 | // Always divisable by 32, since `BLOCK_SIZE()` is 64 bytes 82 | div(paddedBytesSize, 32), // input length in words (safe to pass, never exceed `type(uint32).max`) 83 | 0, // output offset in words 84 | 1, // output length in words 85 | numRounds // number of rounds (safe to pass, never exceed `type(uint64).max`) 86 | ) 87 | let gasToPay := mul(SHA256_ROUND_GAS_COST(), numRounds) 88 | 89 | let success := precompileCall(precompileParams, gasToPay) 90 | 91 | switch success 92 | case 0 { 93 | revert(0, 0) 94 | } 95 | default { 96 | return(0, 32) 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /l2/system-contracts/test-contracts/TestSystemContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../Constants.sol"; 6 | 7 | import "../DefaultAccount.sol"; 8 | 9 | import "../libraries/EfficientCall.sol"; 10 | import {SystemContractHelper, ISystemContract} from "../libraries/SystemContractHelper.sol"; 11 | import {TestSystemContractHelper} from "./TestSystemContractHelper.sol"; 12 | 13 | /// @notice An example of a system contract that be used for local testing. 14 | /// @dev It is not used anywhere except for testing 15 | contract TestSystemContract is ISystemContract { 16 | modifier onlySelf() { 17 | require(msg.sender == address(this)); 18 | _; 19 | } 20 | 21 | function testPrecompileCall() external view { 22 | // Without precompile call 23 | { 24 | uint256 gasBefore = gasleft(); 25 | uint256 gasAfter = gasleft(); 26 | require(gasBefore - gasAfter < 10, "Spent too much gas"); 27 | } 28 | 29 | { 30 | uint256 gasBefore = gasleft(); 31 | SystemContractHelper.precompileCall(0, 10000); 32 | uint256 gasAfter = gasleft(); 33 | require(gasBefore - gasAfter > 10000, "Did not spend enough gas"); 34 | require(gasBefore - gasAfter < 10100, "Spent too much gas"); 35 | } 36 | } 37 | 38 | function testMimicCallAndValue(address whoToMimic, uint128 value) external { 39 | // Note that we don't need to actually have the needed balance to set the `msg.value` for the next call 40 | SystemContractHelper.setValueForNextFarCall(value); 41 | this.performMimicCall( 42 | address(this), 43 | whoToMimic, 44 | abi.encodeCall(TestSystemContract.saveContext, ()), 45 | false, 46 | false 47 | ); 48 | 49 | require(latestMsgSender == whoToMimic, "mimicCall does not work"); 50 | require(latestMsgValue == value, "setValueForNextFarCall does not work"); 51 | } 52 | 53 | address public latestMsgSender; 54 | uint128 public latestMsgValue; 55 | uint256 public extraAbiData1; 56 | uint256 public extraAbiData2; 57 | 58 | function saveContext() external payable { 59 | latestMsgSender = msg.sender; 60 | latestMsgValue = uint128(msg.value); 61 | extraAbiData1 = SystemContractHelper.getExtraAbiData(0); 62 | extraAbiData2 = SystemContractHelper.getExtraAbiData(1); 63 | } 64 | 65 | function testOnlySystemModifier() external { 66 | // Firstly, system contracts should be able to call it 67 | (bool success, ) = address(this).call(abi.encodeCall(TestSystemContract.requireOnlySystem, ())); 68 | require(success, "System contracts can call onlySystemCall methods"); 69 | 70 | // Non-system contract accounts should not be able to call it. 71 | success = this.performRawMimicCall( 72 | address(this), 73 | address(MAX_SYSTEM_CONTRACT_ADDRESS + 1), 74 | abi.encodeCall(TestSystemContract.requireOnlySystem, ()), 75 | false, 76 | false 77 | ); 78 | require(!success, "Normal acounts can not call onlySystemCall methods without proper flags"); 79 | 80 | success = this.performRawMimicCall( 81 | address(this), 82 | address(MAX_SYSTEM_CONTRACT_ADDRESS + 1), 83 | abi.encodeCall(TestSystemContract.requireOnlySystem, ()), 84 | false, 85 | true 86 | ); 87 | require(success, "Normal acounts can not call onlySystemCall methods without proper flags"); 88 | } 89 | 90 | function requireOnlySystem() external onlySystemCall {} 91 | 92 | function testSystemMimicCall() external { 93 | this.performSystemMimicCall( 94 | address(this), 95 | address(MAX_SYSTEM_CONTRACT_ADDRESS + 1), 96 | abi.encodeCall(TestSystemContract.saveContext, ()), 97 | false, 98 | 100, 99 | 120 100 | ); 101 | 102 | require(extraAbiData1 == 100, "extraAbiData1 passed incorrectly"); 103 | require(extraAbiData2 == 120, "extraAbiData2 passed incorrectly"); 104 | } 105 | 106 | function performMimicCall( 107 | address to, 108 | address whoToMimic, 109 | bytes calldata data, 110 | bool isConstructor, 111 | bool isSystem 112 | ) external onlySelf returns (bytes memory) { 113 | return EfficientCall.mimicCall(uint32(gasleft()), to, data, whoToMimic, isConstructor, isSystem); 114 | } 115 | 116 | function performRawMimicCall( 117 | address to, 118 | address whoToMimic, 119 | bytes calldata data, 120 | bool isConstructor, 121 | bool isSystem 122 | ) external onlySelf returns (bool) { 123 | return EfficientCall.rawMimicCall(uint32(gasleft()), to, data, whoToMimic, isConstructor, isSystem); 124 | } 125 | 126 | function performSystemMimicCall( 127 | address to, 128 | address whoToMimic, 129 | bytes calldata data, 130 | bool isConstructor, 131 | uint256 extraAbiParam1, 132 | uint256 extraAbiParam2 133 | ) external onlySelf { 134 | TestSystemContractHelper.systemMimicCall(to, whoToMimic, data, isConstructor, extraAbiParam1, extraAbiParam2); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /l2/system-contracts/test-contracts/TestSystemContractHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8; 4 | 5 | import {MAX_SYSTEM_CONTRACT_ADDRESS, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol"; 6 | 7 | import "../libraries/SystemContractsCaller.sol"; 8 | import "../libraries/SystemContractHelper.sol"; 9 | import "../libraries/Utils.sol"; 10 | 11 | library TestSystemContractHelper { 12 | /// @notice Perform a `mimicCall` with `isSystem` flag, with the ability to pass extra abi data. 13 | /// @param to The address to call 14 | /// @param whoToMimic The `msg.sender` for the next call. 15 | /// @param data The calldata 16 | /// @param isConstructor Whether the call should contain the `isConstructor` flag. 17 | /// @param extraAbiParam1 The first extraAbi param to pass with the call 18 | /// @param extraAbiParam2 The second extraAbi param to pass with the call 19 | /// @return The returndata if the call was successful. Reverts otherwise. 20 | /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) 21 | function systemMimicCall( 22 | address to, 23 | address whoToMimic, 24 | bytes calldata data, 25 | bool isConstructor, 26 | uint256 extraAbiParam1, 27 | uint256 extraAbiParam2 28 | ) internal returns (bytes memory) { 29 | bool success = rawSystemMimicCall(to, whoToMimic, data, isConstructor, extraAbiParam1, extraAbiParam2); 30 | 31 | uint256 size; 32 | assembly { 33 | size := returndatasize() 34 | } 35 | if (!success) { 36 | assembly { 37 | returndatacopy(0, 0, size) 38 | revert(0, size) 39 | } 40 | } 41 | 42 | bytes memory result = new bytes(size); 43 | assembly { 44 | mstore(result, size) 45 | returndatacopy(add(result, 0x20), 0, size) 46 | } 47 | return result; 48 | } 49 | 50 | /// @notice Perform a `mimicCall` with `isSystem` flag, with the ability to pass extra abi data. 51 | /// @param to The address to call 52 | /// @param whoToMimic The `msg.sender` for the next call. 53 | /// @param data The calldata 54 | /// @param isConstructor Whether the call should contain the `isConstructor` flag. 55 | /// @param extraAbiParam1 The first extraAbi param to pass with the call 56 | /// @param extraAbiParam2 The second extraAbi param to pass with the call 57 | /// @return success whether the call was successful. 58 | /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) 59 | function rawSystemMimicCall( 60 | address to, 61 | address whoToMimic, 62 | bytes calldata data, 63 | bool isConstructor, 64 | uint256 extraAbiParam1, 65 | uint256 extraAbiParam2 66 | ) internal returns (bool success) { 67 | SystemContractHelper.loadCalldataIntoActivePtr(); 68 | 69 | // Currently, zkEVM considers the pointer valid if(ptr.offset < ptr.length || (ptr.length == 0 && ptr.offset == 0)), otherwise panics. 70 | // So, if the data is empty we need to make the `ptr.length = ptr.offset = 0`, otherwise follow standard logic. 71 | if (data.length == 0) { 72 | // Safe to cast, offset is never bigger than `type(uint32).max` 73 | SystemContractHelper.ptrShrinkIntoActive(uint32(msg.data.length)); 74 | } else { 75 | uint256 dataOffset; 76 | assembly { 77 | dataOffset := data.offset 78 | } 79 | 80 | // Safe to cast, offset is never bigger than `type(uint32).max` 81 | SystemContractHelper.ptrAddIntoActive(uint32(dataOffset)); 82 | // Safe to cast, `data.length` is never bigger than `type(uint32).max` 83 | uint32 shrinkTo = uint32(msg.data.length - (data.length + dataOffset)); 84 | SystemContractHelper.ptrShrinkIntoActive(shrinkTo); 85 | } 86 | 87 | uint32 gas = Utils.safeCastToU32(gasleft()); 88 | uint256 farCallAbi = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( 89 | gas, 90 | // Only rollup is supported for now 91 | 0, 92 | CalldataForwardingMode.ForwardFatPointer, 93 | isConstructor, 94 | true 95 | ); 96 | SystemContractHelper.ptrPackIntoActivePtr(farCallAbi); 97 | 98 | address callAddr = SYSTEM_MIMIC_CALL_BY_REF_CALL_ADDRESS; 99 | uint256 cleanupMask = ADDRESS_MASK; 100 | assembly { 101 | // Clearing values before usage in assembly, since Solidity 102 | // doesn't do it by default 103 | whoToMimic := and(whoToMimic, cleanupMask) 104 | 105 | success := call(to, callAddr, 0, 0, whoToMimic, extraAbiParam1, extraAbiParam2) 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /l2/system-contracts/tests/Counter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | contract Counter { 6 | uint256 public counter; 7 | 8 | function increment() public { 9 | counter += 1; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /l2/system-contracts/tests/TransactionHelperTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../libraries/TransactionHelper.sol"; 6 | 7 | contract TransactionHelperTest { 8 | using TransactionHelper for Transaction; 9 | 10 | function encodeHash(Transaction calldata _transaction) public view returns (bytes32 resultHash) { 11 | resultHash = _transaction.encodeHash(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@matterlabs/zksync-contracts", 3 | "version": "0.6.1", 4 | "license": "MIT", 5 | "peerDependencies": { 6 | "@openzeppelin/contracts": "4.6.0", 7 | "@openzeppelin/contracts-upgradeable": "4.6.0" 8 | }, 9 | "devDependencies": { 10 | "@openzeppelin/contracts": "^4.8.1", 11 | "@openzeppelin/contracts-upgradeable": "^4.8.1", 12 | "hardhat": "^2.12.6" 13 | } 14 | } 15 | --------------------------------------------------------------------------------