More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6885117 | 2 hrs ago | 0.00001451 ETH | ||||
6878081 | 4 hrs ago | 0.00001227 ETH | ||||
6877897 | 4 hrs ago | 0.00001224 ETH | ||||
6868590 | 7 hrs ago | 0.00002113 ETH | ||||
6868515 | 7 hrs ago | 0.00001239 ETH | ||||
6859780 | 9 hrs ago | 0.00001229 ETH | ||||
6854546 | 11 hrs ago | 0.00001237 ETH | ||||
6847265 | 13 hrs ago | 0.00001229 ETH | ||||
6833558 | 17 hrs ago | 0.00001222 ETH | ||||
6833306 | 17 hrs ago | 0.0000122 ETH | ||||
6831917 | 17 hrs ago | 0.00001535 ETH | ||||
6831769 | 17 hrs ago | 0.00001224 ETH | ||||
6831423 | 17 hrs ago | 0.00001224 ETH | ||||
6831366 | 17 hrs ago | 0.00001224 ETH | ||||
6831128 | 17 hrs ago | 0.00001223 ETH | ||||
6831063 | 17 hrs ago | 0.00001223 ETH | ||||
6830972 | 17 hrs ago | 0.00001223 ETH | ||||
6826583 | 19 hrs ago | 0.00001225 ETH | ||||
6819471 | 21 hrs ago | 0.00001347 ETH | ||||
6811938 | 23 hrs ago | 0.00001922 ETH | ||||
6811564 | 23 hrs ago | 0.00002174 ETH | ||||
6810830 | 23 hrs ago | 0.00001563 ETH | ||||
6810797 | 23 hrs ago | 0.00002323 ETH | ||||
6810693 | 23 hrs ago | 0.00001563 ETH | ||||
6801250 | 26 hrs ago | 0.00001251 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
VerifyingSingletonPaymaster
Compiler Version
v0.8.20+commit.a1b79de6
ZkSolc Version
v1.5.7
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; /* solhint-disable reason-string */ /* solhint-disable no-inline-assembly */ import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; import {BasePaymaster} from '../base/BasePaymaster.sol'; import {Transaction} from '@matterlabs/zksync-contracts/contracts/system-contracts/libraries/TransactionHelper.sol'; import {IPaymasterFlow} from '@matterlabs/zksync-contracts/contracts/system-contracts/interfaces/IPaymasterFlow.sol'; import {ExecutionResult} from '@matterlabs/zksync-contracts/contracts/system-contracts/interfaces/IPaymaster.sol'; /** * @title VerifyingSingletonPaymaster * @dev SaaS-oriented Paymaster contract for zkSync that enables dApps to sponsor user transactions. * Each sponsor (paymasterId) can deposit funds, which are used to cover transaction fees for their users. */ contract VerifyingSingletonPaymaster is BasePaymaster, ReentrancyGuard { using ECDSA for bytes32; using MessageHashUtils for bytes32; // Role identifiers for access control bytes32 private constant SIGNER = keccak256('SIGNER'); bytes32 private constant CASHIER = keccak256('CASHIER'); // Offsets for decoding paymaster data uint256 private constant PAYMASTER_ID_OFFSET = 4; // Offset for paymasterId in paymasterData uint256 private constant VALID_UTIL_OFFSET = 24; // Offset for validity util timestamp uint256 private constant VALID_AFTER_OFFSET = 30; // Offset for validity after timestamp uint256 private constant SIGNATURE_OFFSET = 36; // Offset for signature // Mapping to track balances for each paymasterId mapping(address => uint256) private paymasterIdBalances; uint256 private globBalance; mapping(bytes32 => bytes32) public txHashBySignedHash; // Events event GasDeposited(address indexed paymasterId, uint256 indexed value); event GasWithdrawn(address indexed paymasterId, address indexed to, uint256 indexed value); event PaymasterSponsored( address indexed paymasterId, address indexed user, bytes32 indexed signedHash, uint256 deducted ); event EPGasOverheadChanged(uint256 indexed _oldValue, uint256 indexed _newValue); /** * @dev Constructor to initialize the Paymaster with an admin. * @param _admin Address of the admin who manages the Paymaster contract. */ constructor(address _admin) payable { _grantRole(DEFAULT_ADMIN_ROLE, _admin); } /** * @dev Allows sponsors (paymasterId) to deposit funds to pay for user transactions. * @param paymasterId Unique identifier for the sponsor/dApp making the deposit. */ function depositFor(address paymasterId) external payable nonReentrant { require(paymasterId != address(0), 'invalid paymasterId'); require(msg.value > 0, 'deposit can not be zero'); paymasterIdBalances[paymasterId] = paymasterIdBalances[paymasterId] + msg.value; globBalance = globBalance + msg.value; emit GasDeposited(paymasterId, msg.value); } /** * @dev Retrieves the current balance for a specific paymasterId. * @param paymasterId Unique identifier for the sponsor/dApp. * @return balance The current balance for the given paymasterId. */ function getBalance(address paymasterId) external view returns (uint256 balance) { balance = paymasterIdBalances[paymasterId]; } /** * @dev Withdraws funds from a sponsor's balance and sends them to a recipient address. * @param recipient Address to receive the withdrawn funds. * @param amount Amount of funds to withdraw. */ function withdrawTo(address payable recipient, uint256 amount) public nonReentrant { require(recipient != address(0), 'can not withdraw to zero address'); uint256 currentBalance = paymasterIdBalances[msg.sender]; require(amount <= currentBalance, 'can not withdraw more than balance'); paymasterIdBalances[msg.sender] = paymasterIdBalances[msg.sender] - amount; globBalance = globBalance - amount; super._withdrawTo(recipient, amount); emit GasWithdrawn(msg.sender, recipient, amount); } function withdrawAdditional(address payable recipient) public onlyRole(CASHIER) { super._withdrawTo(recipient, address(this).balance - globBalance); } /** * @dev Validates the transaction and ensures it meets Paymaster requirements (e.g., signature, balance). * @param _transaction The transaction to validate. * @return context Encoded context data for use in postTransaction. */ function _validatePaymasterTransaction( Transaction calldata _transaction, uint256 requiredETH, uint256 gasPrice ) internal virtual override returns (bytes memory context) { require( bytes4(_transaction.paymasterInput[0:4]) == IPaymasterFlow.general.selector, 'flow is not supported' ); // Parse and verify Paymaster data ( address paymasterId, uint48 validUntil, uint48 validAfter, bytes calldata signature ) = parsePaymasterData(_transaction.paymasterInput); // Reconstruct the signed message for validation bytes32 signedHash = keccak256( bytes.concat( abi.encode( address(uint160(_transaction.from)), _transaction.nonce, address(uint160(_transaction.to)), _transaction.value, keccak256(_transaction.data), _transaction.gasLimit, _transaction.maxFeePerGas, _transaction.maxPriorityFeePerGas ), abi.encode(block.chainid, address(this), paymasterId, validUntil, validAfter) ) ).toEthSignedMessageHash(); uint256 balance = paymasterIdBalances[paymasterId]; // Validate the signature against the signer role require(hasRole(SIGNER, signedHash.recover(signature)), 'invalid signature'); // Ensure the paymasterId has sufficient balance require(requiredETH <= balance, 'insufficient balance of paymasterId'); require( validUntil >= block.timestamp && validAfter <= block.timestamp, 'invalid time range' ); paymasterIdBalances[paymasterId] = balance - requiredETH; globBalance = globBalance - requiredETH; txHashBySignedHash[signedHash] = bytes32(type(uint256).max); emit PaymasterSponsored( paymasterId, address(uint160(_transaction.from)), signedHash, requiredETH ); context = abi.encodePacked(signedHash); } /** * @dev Parses paymasterData into individual components (paymasterId, validity periods, signature). * @param paymasterData Encoded Paymaster data from the transaction. * @return paymasterId Sponsor identifier. * @return validUntil Timestamp after which the paymaster sponsorship is invalid. * @return validAfter Timestamp before which the paymaster sponsorship is invalid. * @return signature The cryptographic signature for validation. */ function parsePaymasterData( bytes calldata paymasterData ) public pure returns ( address paymasterId, uint48 validUntil, uint48 validAfter, bytes calldata signature ) { paymasterId = address(bytes20(paymasterData[PAYMASTER_ID_OFFSET:VALID_UTIL_OFFSET])); validUntil = uint48(bytes6(paymasterData[VALID_UTIL_OFFSET:VALID_AFTER_OFFSET])); validAfter = uint48(bytes6(paymasterData[VALID_AFTER_OFFSET:SIGNATURE_OFFSET])); signature = paymasterData[SIGNATURE_OFFSET:]; } function postTransaction( bytes calldata _context, Transaction calldata /*_transaction*/, bytes32 _txHash, bytes32 /*_suggestedSignedHash*/, ExecutionResult /*_txResult*/, uint256 /*_maxRefundedGas*/ ) external payable override { bytes32 signedHash = bytes32(_context); txHashBySignedHash[signedHash] = _txHash; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.20; /* solhint-disable reason-string */ import {AccessControl} from '@openzeppelin/contracts/access/AccessControl.sol'; import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from '@matterlabs/zksync-contracts/contracts/system-contracts/interfaces/IPaymaster.sol'; import {Transaction} from '@matterlabs/zksync-contracts/contracts/system-contracts/libraries/TransactionHelper.sol'; import {BOOTLOADER_FORMAL_ADDRESS} from '@matterlabs/zksync-contracts/contracts/system-contracts/Constants.sol'; /** * Helper class for creating a paymaster. * provides helper methods for staking. * validates that the postOp is called only by the entryPoint */ abstract contract BasePaymaster is IPaymaster, AccessControl { modifier onlyBootloader() { require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, 'only bootloader can call this method'); // Continue execution if called from the bootloader. _; } /// @inheritdoc IPaymaster function validateAndPayForPaymasterTransaction( bytes32 /**_txHash*/, bytes32 /**_suggestedSignedHash*/, Transaction calldata _transaction ) external payable onlyBootloader returns (bytes4 magic, bytes memory context) { // By default we consider the transaction as accepted. magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; require(_transaction.paymasterInput.length >= 4, 'short paymaster input'); uint256 gasPrice; if (_transaction.maxFeePerGas == _transaction.maxPriorityFeePerGas) { gasPrice = _transaction.maxFeePerGas; } else { gasPrice = block.basefee + _transaction.maxPriorityFeePerGas; if (gasPrice > _transaction.maxFeePerGas) { gasPrice = _transaction.maxFeePerGas; } } uint256 requiredETH = _transaction.gasLimit * gasPrice; context = _validatePaymasterTransaction(_transaction, requiredETH, gasPrice); // The bootloader never returns any data, so it can safely be ignored here. (bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{value: requiredETH}(''); require(success, 'failed fee transfer to the bootloader'); } /// @inheritdoc IPaymaster function postTransaction( bytes calldata _context, Transaction calldata _transaction, bytes32 _txHash, bytes32 _suggestedSignedHash, ExecutionResult _txResult, uint256 _maxRefundedGas ) external payable virtual onlyBootloader {} function _validatePaymasterTransaction( Transaction calldata _transaction, uint256 requiredETH, uint256 gasPrice ) internal virtual returns (bytes memory context); /** * withdraw value from the deposit * @param recipient target to send to * @param amount to withdraw */ function _withdrawTo(address payable recipient, uint256 amount) internal virtual { (bool success, ) = recipient.call{value: amount}(''); require(success, 'transfer failed'); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {IERC20} from "../openzeppelin/token/ERC20/IERC20.sol"; import {SafeERC20} from "../openzeppelin/token/ERC20/utils/SafeERC20.sol"; import {IPaymasterFlow} from "../interfaces/IPaymasterFlow.sol"; import {BASE_TOKEN_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS} from "../Constants.sol"; import {RLPEncoder} from "./RLPEncoder.sol"; import {EfficientCall} from "./EfficientCall.sol"; import {UnsupportedTxType, InvalidInput, UnsupportedPaymasterFlow} from "../SystemContractErrors.sol"; /// @dev The type id of ZKsync's EIP-712-signed transaction. uint8 constant EIP_712_TX_TYPE = 0x71; /// @dev The type id of legacy transactions. uint8 constant LEGACY_TX_TYPE = 0x0; /// @dev The type id of legacy transactions. uint8 constant EIP_2930_TX_TYPE = 0x01; /// @dev The type id of EIP1559 transactions. uint8 constant EIP_1559_TX_TYPE = 0x02; /// @notice Structure used to represent a ZKsync transaction. struct Transaction { // The type of the transaction. uint256 txType; // The caller. uint256 from; // The callee. uint256 to; // The gasLimit to pass with the transaction. // It has the same meaning as Ethereum's gasLimit. uint256 gasLimit; // The maximum amount of gas the user is willing to pay for a byte of pubdata. uint256 gasPerPubdataByteLimit; // The maximum fee per gas that the user is willing to pay. // It is akin to EIP1559's maxFeePerGas. uint256 maxFeePerGas; // The maximum priority fee per gas that the user is willing to pay. // It is akin to EIP1559's maxPriorityFeePerGas. uint256 maxPriorityFeePerGas; // The transaction's paymaster. If there is no paymaster, it is equal to 0. uint256 paymaster; // The nonce of the transaction. uint256 nonce; // The value to pass with the transaction. uint256 value; // In the future, we might want to add some // new fields to the struct. The `txData` struct // is to be passed to account and any changes to its structure // would mean a breaking change to these accounts. In order to prevent this, // we should keep some fields as "reserved". // It is also recommended that their length is fixed, since // it would allow easier proof integration (in case we will need // some special circuit for preprocessing transactions). uint256[4] reserved; // The transaction's calldata. bytes data; // The signature of the transaction. bytes signature; // The properly formatted hashes of bytecodes that must be published on L1 // with the inclusion of this transaction. Note, that a bytecode has been published // before, the user won't pay fees for its republishing. bytes32[] factoryDeps; // The input to the paymaster. bytes paymasterInput; // Reserved dynamic type for the future use-case. Using it should be avoided, // But it is still here, just in case we want to enable some additional functionality. bytes reservedDynamic; } /** * @author Matter Labs * @custom:security-contact [email protected] * @notice Library is used to help custom accounts to work with common methods for the Transaction type. */ library TransactionHelper { using SafeERC20 for IERC20; /// @notice The EIP-712 typehash for the contract's domain bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId)"); bytes32 internal constant EIP712_TRANSACTION_TYPE_HASH = keccak256( "Transaction(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,bytes data,bytes32[] factoryDeps,bytes paymasterInput)" ); /// @notice Whether the token is Ethereum. /// @param _addr The address of the token /// @return `true` or `false` based on whether the token is Ether. /// @dev This method assumes that address is Ether either if the address is 0 (for convenience) /// or if the address is the address of the L2BaseToken system contract. function isEthToken(uint256 _addr) internal pure returns (bool) { return _addr == uint256(uint160(address(BASE_TOKEN_SYSTEM_CONTRACT))) || _addr == 0; } /// @notice Calculate the suggested signed hash of the transaction, /// i.e. the hash that is signed by EOAs and is recommended to be signed by other accounts. function encodeHash(Transaction calldata _transaction) internal view returns (bytes32 resultHash) { if (_transaction.txType == LEGACY_TX_TYPE) { resultHash = _encodeHashLegacyTransaction(_transaction); } else if (_transaction.txType == EIP_712_TX_TYPE) { resultHash = _encodeHashEIP712Transaction(_transaction); } else if (_transaction.txType == EIP_1559_TX_TYPE) { resultHash = _encodeHashEIP1559Transaction(_transaction); } else if (_transaction.txType == EIP_2930_TX_TYPE) { resultHash = _encodeHashEIP2930Transaction(_transaction); } else { // Currently no other transaction types are supported. // Any new transaction types will be processed in a similar manner. revert UnsupportedTxType(_transaction.txType); } } /// @notice Encode hash of the ZKsync native transaction type. /// @return keccak256 hash of the EIP-712 encoded representation of transaction function _encodeHashEIP712Transaction(Transaction calldata _transaction) private view returns (bytes32) { bytes32 structHash = keccak256( // solhint-disable-next-line func-named-parameters abi.encode( EIP712_TRANSACTION_TYPE_HASH, _transaction.txType, _transaction.from, _transaction.to, _transaction.gasLimit, _transaction.gasPerPubdataByteLimit, _transaction.maxFeePerGas, _transaction.maxPriorityFeePerGas, _transaction.paymaster, _transaction.nonce, _transaction.value, EfficientCall.keccak(_transaction.data), keccak256(abi.encodePacked(_transaction.factoryDeps)), EfficientCall.keccak(_transaction.paymasterInput) ) ); bytes32 domainSeparator = keccak256( abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256("zkSync"), keccak256("2"), block.chainid) ); return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } /// @notice Encode hash of the legacy transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashLegacyTransaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of legacy transactions are encoded as one of the: // - RLP(nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0) // - RLP(nonce, gasPrice, gasLimit, to, value, data) // // In this RLP encoding, only the first one above list appears, so we encode each element // inside list and then concatenate the length of all elements with them. bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); // Encode `gasPrice` and `gasLimit` together to prevent "stack too deep error". bytes memory encodedGasParam; { bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); encodedGasParam = bytes.concat(encodedGasPrice, encodedGasLimit); } bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // Encode `chainId` according to EIP-155, but only if the `chainId` is specified in the transaction. bytes memory encodedChainId; if (_transaction.reserved[0] != 0) { encodedChainId = bytes.concat(RLPEncoder.encodeUint256(block.chainid), hex"80_80"); } bytes memory encodedListLength; unchecked { uint256 listLength = encodedNonce.length + encodedGasParam.length + encodedTo.length + encodedValue.length + encodedDataLength.length + _transaction.data.length + encodedChainId.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( // solhint-disable-next-line func-named-parameters bytes.concat( encodedListLength, encodedNonce, encodedGasParam, encodedTo, encodedValue, encodedDataLength, _transaction.data, encodedChainId ) ); } /// @notice Encode hash of the EIP2930 transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashEIP2930Transaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of EIP2930 transactions is encoded the following way: // H(0x01 || RLP(chain_id, nonce, gas_price, gas_limit, destination, amount, data, access_list)) // // Note, that on ZKsync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedGasPrice = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); // solhint-disable-next-line func-named-parameters encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedGasPrice, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( // solhint-disable-next-line func-named-parameters bytes.concat( "\x01", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength ) ); } /// @notice Encode hash of the EIP1559 transaction type. /// @return keccak256 of the serialized RLP encoded representation of transaction function _encodeHashEIP1559Transaction(Transaction calldata _transaction) private view returns (bytes32) { // Hash of EIP1559 transactions is encoded the following way: // H(0x02 || RLP(chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list)) // // Note, that on ZKsync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; { bytes memory encodedChainId = RLPEncoder.encodeUint256(block.chainid); bytes memory encodedNonce = RLPEncoder.encodeUint256(_transaction.nonce); bytes memory encodedMaxPriorityFeePerGas = RLPEncoder.encodeUint256(_transaction.maxPriorityFeePerGas); bytes memory encodedMaxFeePerGas = RLPEncoder.encodeUint256(_transaction.maxFeePerGas); bytes memory encodedGasLimit = RLPEncoder.encodeUint256(_transaction.gasLimit); bytes memory encodedTo = RLPEncoder.encodeAddress(address(uint160(_transaction.to))); bytes memory encodedValue = RLPEncoder.encodeUint256(_transaction.value); // solhint-disable-next-line func-named-parameters encodedFixedLengthParams = bytes.concat( encodedChainId, encodedNonce, encodedMaxPriorityFeePerGas, encodedMaxFeePerGas, encodedGasLimit, encodedTo, encodedValue ); } // Encode only the length of the transaction data, and not the data itself, // so as not to copy to memory a potentially huge transaction data twice. bytes memory encodedDataLength; { // Safe cast, because the length of the transaction data can't be so large. uint64 txDataLen = uint64(_transaction.data.length); if (txDataLen != 1) { // If the length is not equal to one, then only using the length can it be encoded definitely. encodedDataLength = RLPEncoder.encodeNonSingleBytesLen(txDataLen); } else if (_transaction.data[0] >= 0x80) { // If input is a byte in [0x80, 0xff] range, RLP encoding will concatenates 0x81 with the byte. encodedDataLength = hex"81"; } // Otherwise the length is not encoded at all. } // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; unchecked { uint256 listLength = encodedFixedLengthParams.length + encodedDataLength.length + _transaction.data.length + encodedAccessListLength.length; // Safe cast, because the length of the list can't be so large. encodedListLength = RLPEncoder.encodeListLen(uint64(listLength)); } return keccak256( // solhint-disable-next-line func-named-parameters bytes.concat( "\x02", encodedListLength, encodedFixedLengthParams, encodedDataLength, _transaction.data, encodedAccessListLength ) ); } /// @notice Processes the common paymaster flows, e.g. setting proper allowance /// for tokens, etc. For more information on the expected behavior, check out /// the "Paymaster flows" section in the documentation. function processPaymasterInput(Transaction calldata _transaction) internal { if (_transaction.paymasterInput.length < 4) { revert InvalidInput(); } bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { if (_transaction.paymasterInput.length < 68) { revert InvalidInput(); } // While the actual data consists of address, uint256 and bytes data, // the data is needed only for the paymaster, so we ignore it here for the sake of optimization (address token, uint256 minAllowance) = abi.decode(_transaction.paymasterInput[4:68], (address, uint256)); address paymaster = address(uint160(_transaction.paymaster)); uint256 currentAllowance = IERC20(token).allowance(address(this), paymaster); if (currentAllowance < minAllowance) { // Some tokens, e.g. USDT require that the allowance is firsty set to zero // and only then updated to the new value. IERC20(token).safeApprove(paymaster, 0); IERC20(token).safeApprove(paymaster, minAllowance); } } else if (paymasterInputSelector == IPaymasterFlow.general.selector) { // Do nothing. general(bytes) paymaster flow means that the paymaster must interpret these bytes on his own. } else { revert UnsupportedPaymasterFlow(); } } /// @notice Pays the required fee for the transaction to the bootloader. /// @dev Currently it pays the maximum amount "_transaction.maxFeePerGas * _transaction.gasLimit", /// it will change in the future. function payToTheBootloader(Transaction calldata _transaction) internal returns (bool success) { address bootloaderAddr = BOOTLOADER_FORMAL_ADDRESS; uint256 amount = _transaction.maxFeePerGas * _transaction.gasLimit; assembly { success := call(gas(), bootloaderAddr, amount, 0, 0, 0, 0) } } // Returns the balance required to process the transaction. function totalRequiredBalance(Transaction calldata _transaction) internal pure returns (uint256 requiredBalance) { if (address(uint160(_transaction.paymaster)) != address(0)) { // Paymaster pays for the fee requiredBalance = _transaction.value; } else { // The user should have enough balance for both the fee and the value of the transaction requiredBalance = _transaction.maxFeePerGas * _transaction.gasLimit + _transaction.value; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {Transaction} from "../libraries/TransactionHelper.sol"; enum ExecutionResult { Revert, Success } bytes4 constant PAYMASTER_VALIDATION_SUCCESS_MAGIC = IPaymaster.validateAndPayForPaymasterTransaction.selector; interface IPaymaster { /// @dev Called by the bootloader to verify that the paymaster agrees to pay for the /// fee for the transaction. This transaction should also send the necessary amount of funds onto the bootloader /// address. /// @param _txHash The hash of the transaction /// @param _suggestedSignedHash The hash of the transaction that is signed by an EOA /// @param _transaction The transaction itself. /// @return magic The value that should be equal to the signature of the validateAndPayForPaymasterTransaction /// if the paymaster agrees to pay for the transaction. /// @return context The "context" of the transaction: an array of bytes of length at most 1024 bytes, which will be /// passed to the `postTransaction` method of the account. /// @dev The developer should strive to preserve as many steps as possible both for valid /// and invalid transactions as this very method is also used during the gas fee estimation /// (without some of the necessary data, e.g. signature). function validateAndPayForPaymasterTransaction( bytes32 _txHash, bytes32 _suggestedSignedHash, Transaction calldata _transaction ) external payable returns (bytes4 magic, bytes memory context); /// @dev Called by the bootloader after the execution of the transaction. Please note that /// there is no guarantee that this method will be called at all. Unlike the original EIP4337, /// this method won't be called if the transaction execution results in out-of-gas. /// @param _context, the context of the execution, returned by the "validateAndPayForPaymasterTransaction" method. /// @param _transaction, the users' transaction. /// @param _txResult, the result of the transaction execution (success or failure). /// @param _maxRefundedGas, the upper bound on the amount of gas that could be refunded to the paymaster. /// @dev The exact amount refunded depends on the gas spent by the "postOp" itself and so the developers should /// take that into account. function postTransaction( bytes calldata _context, Transaction calldata _transaction, bytes32 _txHash, bytes32 _suggestedSignedHash, ExecutionResult _txResult, uint256 _maxRefundedGas ) external payable; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @dev The interface that is used for encoding/decoding of * different types of paymaster flows. * @notice This is NOT an interface to be implemented * by contracts. It is just used for encoding. */ interface IPaymasterFlow { function general(bytes calldata input) external; function approvalBased(address _token, uint256 _minAllowance, bytes calldata _innerInput) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {IAccountCodeStorage} from "./interfaces/IAccountCodeStorage.sol"; import {INonceHolder} from "./interfaces/INonceHolder.sol"; import {IContractDeployer} from "./interfaces/IContractDeployer.sol"; import {IKnownCodesStorage} from "./interfaces/IKnownCodesStorage.sol"; import {IImmutableSimulator} from "./interfaces/IImmutableSimulator.sol"; import {IBaseToken} from "./interfaces/IBaseToken.sol"; import {IL1Messenger} from "./interfaces/IL1Messenger.sol"; import {ISystemContext} from "./interfaces/ISystemContext.sol"; import {ICompressor} from "./interfaces/ICompressor.sol"; import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; import {IBootloaderUtilities} from "./interfaces/IBootloaderUtilities.sol"; import {IPubdataChunkPublisher} from "./interfaces/IPubdataChunkPublisher.sol"; /// @dev All the system contracts introduced by ZKsync have their addresses /// started from 2^15 in order to avoid collision with Ethereum precompiles. uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15 /// @dev Unlike the value above, it is not overridden for the purpose of testing and /// is identical to the constant value actually used as the system contracts offset on /// mainnet. uint160 constant REAL_SYSTEM_CONTRACTS_OFFSET = 0x8000; /// @dev All the system contracts must be located in the kernel space, /// i.e. their addresses must be below 2^16. uint160 constant MAX_SYSTEM_CONTRACT_ADDRESS = 0xffff; // 2^16 - 1 address constant ECRECOVER_SYSTEM_CONTRACT = address(0x01); address constant SHA256_SYSTEM_CONTRACT = address(0x02); address constant ECADD_SYSTEM_CONTRACT = address(0x06); address constant ECMUL_SYSTEM_CONTRACT = address(0x07); address constant ECPAIRING_SYSTEM_CONTRACT = address(0x08); /// @dev The number of gas that need to be spent for a single byte of pubdata regardless of the pubdata price. /// This variable is used to ensure the following: /// - That the long-term storage of the operator is compensated properly. /// - That it is not possible that the pubdata counter grows too high without spending proportional amount of computation. uint256 constant COMPUTATIONAL_PRICE_FOR_PUBDATA = 80; /// @dev The maximal possible address of an L1-like precompie. These precompiles maintain the following properties: /// - Their extcodehash is EMPTY_STRING_KECCAK /// - Their extcodesize is 0 despite having a bytecode formally deployed there. uint256 constant CURRENT_MAX_PRECOMPILE_ADDRESS = 0xff; address payable constant BOOTLOADER_FORMAL_ADDRESS = payable(address(SYSTEM_CONTRACTS_OFFSET + 0x01)); IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( address(SYSTEM_CONTRACTS_OFFSET + 0x02) ); INonceHolder constant NONCE_HOLDER_SYSTEM_CONTRACT = INonceHolder(address(SYSTEM_CONTRACTS_OFFSET + 0x03)); IKnownCodesStorage constant KNOWN_CODE_STORAGE_CONTRACT = IKnownCodesStorage(address(SYSTEM_CONTRACTS_OFFSET + 0x04)); IImmutableSimulator constant IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT = IImmutableSimulator( address(SYSTEM_CONTRACTS_OFFSET + 0x05) ); IContractDeployer constant DEPLOYER_SYSTEM_CONTRACT = IContractDeployer(address(SYSTEM_CONTRACTS_OFFSET + 0x06)); IContractDeployer constant REAL_DEPLOYER_SYSTEM_CONTRACT = IContractDeployer(address(REAL_SYSTEM_CONTRACTS_OFFSET + 0x06)); // A contract that is allowed to deploy any codehash // on any address. To be used only during an upgrade. address constant FORCE_DEPLOYER = address(SYSTEM_CONTRACTS_OFFSET + 0x07); IL1Messenger constant L1_MESSENGER_CONTRACT = IL1Messenger(address(SYSTEM_CONTRACTS_OFFSET + 0x08)); address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09); IBaseToken constant BASE_TOKEN_SYSTEM_CONTRACT = IBaseToken(address(SYSTEM_CONTRACTS_OFFSET + 0x0a)); IBaseToken constant REAL_BASE_TOKEN_SYSTEM_CONTRACT = IBaseToken(address(REAL_SYSTEM_CONTRACTS_OFFSET + 0x0a)); // Hardcoded because even for tests we should keep the address. (Instead `SYSTEM_CONTRACTS_OFFSET + 0x10`) // Precompile call depends on it. // And we don't want to mock this contract. address constant KECCAK256_SYSTEM_CONTRACT = address(0x8010); ISystemContext constant SYSTEM_CONTEXT_CONTRACT = ISystemContext(payable(address(SYSTEM_CONTRACTS_OFFSET + 0x0b))); ISystemContext constant REAL_SYSTEM_CONTEXT_CONTRACT = ISystemContext(payable(address(REAL_SYSTEM_CONTRACTS_OFFSET + 0x0b))); IBootloaderUtilities constant BOOTLOADER_UTILITIES = IBootloaderUtilities(address(SYSTEM_CONTRACTS_OFFSET + 0x0c)); // It will be a different value for tests, while shouldn't. But for now, this constant is not used by other contracts, so that's fine. address constant EVENT_WRITER_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x0d); ICompressor constant COMPRESSOR_CONTRACT = ICompressor(address(SYSTEM_CONTRACTS_OFFSET + 0x0e)); IComplexUpgrader constant COMPLEX_UPGRADER_CONTRACT = IComplexUpgrader(address(SYSTEM_CONTRACTS_OFFSET + 0x0f)); IPubdataChunkPublisher constant PUBDATA_CHUNK_PUBLISHER = IPubdataChunkPublisher( address(SYSTEM_CONTRACTS_OFFSET + 0x11) ); /// @dev If the bitwise AND of the extraAbi[2] param when calling the MSG_VALUE_SIMULATOR /// is non-zero, the call will be assumed to be a system one. uint256 constant MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT = 1; /// @dev The maximal msg.value that context can have uint256 constant MAX_MSG_VALUE = type(uint128).max; /// @dev Prefix used during derivation of account addresses using CREATE2 /// @dev keccak256("zksyncCreate2") bytes32 constant CREATE2_PREFIX = 0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494; /// @dev Prefix used during derivation of account addresses using CREATE /// @dev keccak256("zksyncCreate") bytes32 constant CREATE_PREFIX = 0x63bae3a9951d38e8a3fbb7b70909afc1200610fc5bc55ade242f815974674f23; /// @dev Each state diff consists of 156 bytes of actual data and 116 bytes of unused padding, needed for circuit efficiency. uint256 constant STATE_DIFF_ENTRY_SIZE = 272; enum SystemLogKey { L2_TO_L1_LOGS_TREE_ROOT_KEY, TOTAL_L2_TO_L1_PUBDATA_KEY, STATE_DIFF_HASH_KEY, PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY, PREV_BATCH_HASH_KEY, CHAINED_PRIORITY_TXN_HASH_KEY, NUMBER_OF_LAYER_1_TXS_KEY, BLOB_ONE_HASH_KEY, BLOB_TWO_HASH_KEY, BLOB_THREE_HASH_KEY, BLOB_FOUR_HASH_KEY, BLOB_FIVE_HASH_KEY, BLOB_SIX_HASH_KEY, EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY } /// @dev The number of leaves in the L2->L1 log Merkle tree. /// While formally a tree of any length is acceptable, the node supports only a constant length of 16384 leaves. uint256 constant L2_TO_L1_LOGS_MERKLE_TREE_LEAVES = 16_384; /// @dev The length of the derived key in bytes inside compressed state diffs. uint256 constant DERIVED_KEY_LENGTH = 32; /// @dev The length of the enum index in bytes inside compressed state diffs. uint256 constant ENUM_INDEX_LENGTH = 8; /// @dev The length of value in bytes inside compressed state diffs. uint256 constant VALUE_LENGTH = 32; /// @dev The length of the compressed initial storage write in bytes. uint256 constant COMPRESSED_INITIAL_WRITE_SIZE = DERIVED_KEY_LENGTH + VALUE_LENGTH; /// @dev The length of the compressed repeated storage write in bytes. uint256 constant COMPRESSED_REPEATED_WRITE_SIZE = ENUM_INDEX_LENGTH + VALUE_LENGTH; /// @dev The position from which the initial writes start in the compressed state diffs. uint256 constant INITIAL_WRITE_STARTING_POSITION = 4; /// @dev Each storage diffs consists of the following elements: /// [20bytes address][32bytes key][32bytes derived key][8bytes enum index][32bytes initial value][32bytes final value] /// @dev The offset of the derived key in a storage diff. uint256 constant STATE_DIFF_DERIVED_KEY_OFFSET = 52; /// @dev The offset of the enum index in a storage diff. uint256 constant STATE_DIFF_ENUM_INDEX_OFFSET = 84; /// @dev The offset of the final value in a storage diff. uint256 constant STATE_DIFF_FINAL_VALUE_OFFSET = 124; /// @dev Total number of bytes in a blob. Blob = 4096 field elements * 31 bytes per field element /// @dev EIP-4844 defines it as 131_072 but we use 4096 * 31 within our circuits to always fit within a field element /// @dev Our circuits will prove that a EIP-4844 blob and our internal blob are the same. uint256 constant BLOB_SIZE_BYTES = 126_976; /// @dev Max number of blobs currently supported uint256 constant MAX_NUMBER_OF_BLOBS = 6;
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; // 0x86bb51b8 error AddressHasNoCode(address); // 0xefce78c7 error CallerMustBeBootloader(); // 0xb7549616 error CallerMustBeForceDeployer(); // 0x9eedbd2b error CallerMustBeSystemContract(); // 0x4f951510 error CompressionValueAddError(uint256 expected, uint256 actual); // 0x1e6aff87 error CompressionValueTransformError(uint256 expected, uint256 actual); // 0xc2ea251e error CompressionValueSubError(uint256 expected, uint256 actual); // 0x849acb7f error CompressorInitialWritesProcessedNotEqual(uint256 expected, uint256 actual); // 0x61a6a4b3 error CompressorEnumIndexNotEqual(uint256 expected, uint256 actual); // 0x9be48d8d error DerivedKeyNotEqualToCompressedValue(bytes32 expected, bytes32 provided); // 0xe223db5e error DictionaryDividedByEightNotGreaterThanEncodedDividedByTwo(); // 0x1c25715b error EmptyBytes32(); // 0x92bf3cf8 error EmptyVirtualBlocks(); // 0xc06d5cb2 error EncodedAndRealBytecodeChunkNotEqual(uint64 expected, uint64 provided); // 0x2bfbfc11 error EncodedLengthNotFourTimesSmallerThanOriginal(); // 0xe95a1fbe error FailedToChargeGas(); // 0x1f70c58f error FailedToPayOperator(); // 0x9d5da395 error FirstL2BlockInitializationError(); // 0x9e4a3c8a error HashIsNonZero(bytes32); // 0x86302004 error HashMismatch(bytes32 expected, uint256 actual); // 0x4e23d035 error IndexOutOfBounds(); // 0x122e73e9 error IndexSizeError(); // 0x03eb8b54 error InsufficientFunds(uint256 required, uint256 actual); // 0x1c26714c error InsufficientGas(); // 0xae962d4e error InvalidCall(); // 0x6a84bc39 error InvalidCodeHash(CodeHashReason); // 0xb4fa3fb3 error InvalidInput(); // 0x60b85677 error InvalidNonceOrderingChange(); // 0x90f049c9 error InvalidSig(SigField, uint256); // 0xf4a271b5 error Keccak256InvalidReturnData(); // 0xd2906dd9 error L2BlockMustBeGreaterThanZero(); // 0x43e266b0 error MalformedBytecode(BytecodeError); // 0xe90aded4 error NonceAlreadyUsed(address account, uint256 nonce); // 0x45ac24a6 error NonceIncreaseError(uint256 max, uint256 proposed); // 0x13595475 error NonceJumpError(); // 0x1f2f8478 error NonceNotUsed(address account, uint256 nonce); // 0x760a1568 error NonEmptyAccount(); // 0x536ec84b error NonEmptyMsgValue(); // 0xd018e08e error NonIncreasingTimestamp(); // 0x50df6bc3 error NotAllowedToDeployInKernelSpace(); // 0x35278d12 error Overflow(); // 0x7f7b0cf7 error ReconstructionMismatch(PubdataField, bytes32 expected, bytes32 actual); // 0x3adb5f1d error ShaInvalidReturnData(); // 0xbd8665e2 error StateDiffLengthMismatch(); // 0x71c3da01 error SystemCallFlagRequired(); // 0xe0456dfe error TooMuchPubdata(uint256 limit, uint256 supplied); // 0x8e4a23d6 error Unauthorized(address); // 0x3e5efef9 error UnknownCodeHash(bytes32); // 0x9ba6061b error UnsupportedOperation(); // 0xff15b069 error UnsupportedPaymasterFlow(); // 0x17a84415 error UnsupportedTxType(uint256); // 0x5708aead error UpgradeMustBeFirstTxn(); // 0x626ade30 error ValueMismatch(uint256 expected, uint256 actual); // 0x460b9939 error ValuesNotEqual(uint256 expected, uint256 actual); // 0x6818f3f9 error ZeroNonceError(); enum CodeHashReason { NotContractOnConstructor, NotConstructedContract } enum SigField { Length, V, S } enum PubdataField { NumberOfLogs, LogsHash, MsgHash, Bytecode, StateDiffCompressionVersion, ExtraData } enum BytecodeError { Version, NumberOfWords, Length, WordsMustBeOdd, DictionaryLength }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.0; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require( oldAllowance >= value, "SafeERC20: decreased allowance below zero" ); uint256 newAllowance = oldAllowance - value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit({owner: owner, spender: spender, value: value, deadline : deadline, v: v, r: r, s: s}); uint256 nonceAfter = token.nonces(owner); require( nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed" ); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall( data, "SafeERC20: low-level call failed" ); if (returndata.length > 0) { // Return data is optional require( abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed" ); } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice This library provides RLP encoding functionality. */ library RLPEncoder { function encodeAddress(address _val) internal pure returns (bytes memory encoded) { // The size is equal to 20 bytes of the address itself + 1 for encoding bytes length in RLP. encoded = new bytes(0x15); bytes20 shiftedVal = bytes20(_val); assembly { // In the first byte we write the encoded length as 0x80 + 0x14 == 0x94. mstore(add(encoded, 0x20), 0x9400000000000000000000000000000000000000000000000000000000000000) // Write address data without stripping zeros. mstore(add(encoded, 0x21), shiftedVal) } } function encodeUint256(uint256 _val) internal pure returns (bytes memory encoded) { unchecked { if (_val < 128) { encoded = new bytes(1); // Handle zero as a non-value, since stripping zeroes results in an empty byte array encoded[0] = (_val == 0) ? bytes1(uint8(128)) : bytes1(uint8(_val)); } else { uint256 hbs = _highestByteSet(_val); encoded = new bytes(hbs + 2); encoded[0] = bytes1(uint8(hbs + 0x81)); uint256 lbs = 31 - hbs; uint256 shiftedVal = _val << (lbs * 8); assembly { mstore(add(encoded, 0x21), shiftedVal) } } } } /// @notice Encodes the size of bytes in RLP format. /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. /// NOTE: panics if the length is 1 since the length encoding is ambiguous in this case. function encodeNonSingleBytesLen(uint64 _len) internal pure returns (bytes memory) { assert(_len != 1); return _encodeLength(_len, 0x80); } /// @notice Encodes the size of list items in RLP format. /// @param _len The length of the bytes to encode. It has a `uint64` type since as larger values are not supported. function encodeListLen(uint64 _len) internal pure returns (bytes memory) { return _encodeLength(_len, 0xc0); } function _encodeLength(uint64 _len, uint256 _offset) private pure returns (bytes memory encoded) { unchecked { if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len + _offset)); } else { uint256 hbs = _highestByteSet(uint256(_len)); encoded = new bytes(hbs + 2); encoded[0] = bytes1(uint8(_offset + hbs + 56)); uint256 lbs = 31 - hbs; uint256 shiftedVal = uint256(_len) << (lbs * 8); assembly { mstore(add(encoded, 0x21), shiftedVal) } } } } /// @notice Computes the index of the highest byte set in number. /// @notice Uses little endian ordering (The least significant byte has index `0`). /// NOTE: returns `0` for `0` function _highestByteSet(uint256 _number) private pure returns (uint256 hbs) { unchecked { if (_number > type(uint128).max) { _number >>= 128; hbs += 16; } if (_number > type(uint64).max) { _number >>= 64; hbs += 8; } if (_number > type(uint32).max) { _number >>= 32; hbs += 4; } if (_number > type(uint16).max) { _number >>= 16; hbs += 2; } if (_number > type(uint8).max) { ++hbs; } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {SystemContractHelper, ADDRESS_MASK} from "./SystemContractHelper.sol"; import {SystemContractsCaller, CalldataForwardingMode, RAW_FAR_CALL_BY_REF_CALL_ADDRESS, SYSTEM_CALL_BY_REF_CALL_ADDRESS, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, MIMIC_CALL_BY_REF_CALL_ADDRESS} from "./SystemContractsCaller.sol"; import {Utils} from "./Utils.sol"; import {SHA256_SYSTEM_CONTRACT, KECCAK256_SYSTEM_CONTRACT, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol"; import {Keccak256InvalidReturnData, ShaInvalidReturnData} from "../SystemContractErrors.sol"; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice This library is used to perform ultra-efficient calls using zkEVM-specific features. * @dev EVM calls always accept a memory slice as input and return a memory slice as output. * Therefore, even if the user has a ready-made calldata slice, they still need to copy it to memory * before calling. This is especially inefficient for large inputs (proxies, multi-calls, etc.). * In turn, zkEVM operates over a fat pointer, which is a set of (memory page, offset, start, length) in the memory/calldata/returndata. * This allows forwarding the calldata slice as is, without copying it to memory. * @dev Fat pointer is not just an integer, it is an extended data type supported on the VM level. * zkEVM creates the wellformed fat pointers for all the calldata/returndata regions, later * the contract may manipulate the already created fat pointers to forward a slice of the data, but not * to create new fat pointers! * @dev The allowed operation on fat pointers are: * 1. `ptr.add` - Transforms `ptr.offset` into `ptr.offset + u32(_value)`. If overflow happens then it panics. * 2. `ptr.sub` - Transforms `ptr.offset` into `ptr.offset - u32(_value)`. If underflow happens then it panics. * 3. `ptr.pack` - Do the concatenation between the lowest 128 bits of the pointer itself and the highest 128 bits of `_value`. It is typically used to prepare the ABI for external calls. * 4. `ptr.shrink` - Transforms `ptr.length` into `ptr.length - u32(_shrink)`. If underflow happens then it panics. * @dev The call opcodes accept the fat pointer and change it to its canonical form before passing it to the child call * 1. `ptr.start` is transformed into `ptr.offset + ptr.start` * 2. `ptr.length` is transformed into `ptr.length - ptr.offset` * 3. `ptr.offset` is transformed into `0` */ library EfficientCall { /// @notice Call the `keccak256` without copying calldata to memory. /// @param _data The preimage data. /// @return The `keccak256` hash. function keccak(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), KECCAK256_SYSTEM_CONTRACT, _data); if (returnData.length != 32) { revert Keccak256InvalidReturnData(); } return bytes32(returnData); } /// @notice Call the `sha256` precompile without copying calldata to memory. /// @param _data The preimage data. /// @return The `sha256` hash. function sha(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), SHA256_SYSTEM_CONTRACT, _data); if (returnData.length != 32) { revert ShaInvalidReturnData(); } return bytes32(returnData); } /// @notice Perform a `call` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _value The `msg.value` to send. /// @param _data The calldata to use for the call. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return returnData The copied to memory return data. function call( uint256 _gas, address _address, uint256 _value, bytes calldata _data, bool _isSystem ) internal returns (bytes memory returnData) { bool success = rawCall({_gas: _gas, _address: _address, _value: _value, _data: _data, _isSystem: _isSystem}); returnData = _verifyCallResult(success); } /// @notice Perform a `staticCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return returnData The copied to memory return data. function staticCall( uint256 _gas, address _address, bytes calldata _data ) internal view returns (bytes memory returnData) { bool success = rawStaticCall(_gas, _address, _data); returnData = _verifyCallResult(success); } /// @notice Perform a `delegateCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return returnData The copied to memory return data. function delegateCall( uint256 _gas, address _address, bytes calldata _data ) internal returns (bytes memory returnData) { bool success = rawDelegateCall(_gas, _address, _data); returnData = _verifyCallResult(success); } /// @notice Perform a `mimicCall` (a call with custom msg.sender) without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @param _whoToMimic The `msg.sender` for the next call. /// @param _isConstructor Whether the call should contain the `isConstructor` flag. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return returnData The copied to memory return data. function mimicCall( uint256 _gas, address _address, bytes calldata _data, address _whoToMimic, bool _isConstructor, bool _isSystem ) internal returns (bytes memory returnData) { bool success = rawMimicCall({ _gas: _gas, _address: _address, _data: _data, _whoToMimic: _whoToMimic, _isConstructor: _isConstructor, _isSystem: _isSystem }); returnData = _verifyCallResult(success); } /// @notice Perform a `call` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _value The `msg.value` to send. /// @param _data The calldata to use for the call. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return success whether the call was successful. function rawCall( uint256 _gas, address _address, uint256 _value, bytes calldata _data, bool _isSystem ) internal returns (bool success) { if (_value == 0) { _loadFarCallABIIntoActivePtr(_gas, _data, false, _isSystem); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := call(_address, callAddr, 0, 0, 0xFFFF, 0, 0) } } else { _loadFarCallABIIntoActivePtr(_gas, _data, false, true); // If there is provided `msg.value` call the `MsgValueSimulator` to forward ether. address msgValueSimulator = MSG_VALUE_SYSTEM_CONTRACT; address callAddr = SYSTEM_CALL_BY_REF_CALL_ADDRESS; // We need to supply the mask to the MsgValueSimulator to denote // that the call should be a system one. uint256 forwardMask = _isSystem ? MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT : 0; assembly { success := call(msgValueSimulator, callAddr, _value, _address, 0xFFFF, forwardMask, 0) } } } /// @notice Perform a `staticCall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return success whether the call was successful. function rawStaticCall(uint256 _gas, address _address, bytes calldata _data) internal view returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, false, false); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := staticcall(_address, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Perform a `delegatecall` without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @return success whether the call was successful. function rawDelegateCall(uint256 _gas, address _address, bytes calldata _data) internal returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, false, false); address callAddr = RAW_FAR_CALL_BY_REF_CALL_ADDRESS; assembly { success := delegatecall(_address, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Perform a `mimicCall` (call with custom msg.sender) without copying calldata to memory. /// @param _gas The gas to use for the call. /// @param _address The address to call. /// @param _data The calldata to use for the call. /// @param _whoToMimic The `msg.sender` for the next call. /// @param _isConstructor Whether the call should contain the `isConstructor` flag. /// @param _isSystem Whether the call should contain the `isSystem` flag. /// @return success whether the call was successful. /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) function rawMimicCall( uint256 _gas, address _address, bytes calldata _data, address _whoToMimic, bool _isConstructor, bool _isSystem ) internal returns (bool success) { _loadFarCallABIIntoActivePtr(_gas, _data, _isConstructor, _isSystem); address callAddr = MIMIC_CALL_BY_REF_CALL_ADDRESS; uint256 cleanupMask = ADDRESS_MASK; assembly { // Clearing values before usage in assembly, since Solidity // doesn't do it by default _whoToMimic := and(_whoToMimic, cleanupMask) success := call(_address, callAddr, 0, 0, _whoToMimic, 0, 0) } } /// @dev Verify that a low-level call was successful, and revert if it wasn't, by bubbling the revert reason. /// @param _success Whether the call was successful. /// @return returnData The copied to memory return data. function _verifyCallResult(bool _success) private pure returns (bytes memory returnData) { if (_success) { uint256 size; assembly { size := returndatasize() } returnData = new bytes(size); assembly { returndatacopy(add(returnData, 0x20), 0, size) } } else { propagateRevert(); } } /// @dev Propagate the revert reason from the current call to the caller. function propagateRevert() internal pure { assembly { let size := returndatasize() returndatacopy(0, 0, size) revert(0, size) } } /// @dev Load the far call ABI into active ptr, that will be used for the next call by reference. /// @param _gas The gas to be passed to the call. /// @param _data The calldata to be passed to the call. /// @param _isConstructor Whether the call is a constructor call. /// @param _isSystem Whether the call is a system call. function _loadFarCallABIIntoActivePtr( uint256 _gas, bytes calldata _data, bool _isConstructor, bool _isSystem ) private view { SystemContractHelper.loadCalldataIntoActivePtr(); uint256 dataOffset; assembly { dataOffset := _data.offset } // Safe to cast, offset is never bigger than `type(uint32).max` SystemContractHelper.ptrAddIntoActive(uint32(dataOffset)); // Safe to cast, `data.length` is never bigger than `type(uint32).max` uint32 shrinkTo = uint32(msg.data.length - (_data.length + dataOffset)); SystemContractHelper.ptrShrinkIntoActive(shrinkTo); uint32 gas = Utils.safeCastToU32(_gas); uint256 farCallAbi = SystemContractsCaller.getFarCallABIWithEmptyFatPointer({ gasPassed: gas, // Only rollup is supported for now shardId: 0, forwardingMode: CalldataForwardingMode.ForwardFatPointer, isConstructorCall: _isConstructor, isSystemCall: _isSystem }); SystemContractHelper.ptrPackIntoActivePtr(farCallAbi); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; interface IAccountCodeStorage { function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external; function storeAccountConstructedCodeHash(address _address, bytes32 _hash) external; function markAccountCodeHashAsConstructed(address _address) external; function getRawCodeHash(address _address) external view returns (bytes32 codeHash); function getCodeHash(uint256 _input) external view returns (bytes32 codeHash); function getCodeSize(uint256 _input) external view returns (uint256 codeSize); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @dev Interface of the nonce holder contract -- a contract used by the system to ensure * that there is always a unique identifier for a transaction with a particular account (we call it nonce). * In other words, the pair of (address, nonce) should always be unique. * @dev Custom accounts should use methods of this contract to store nonces or other possible unique identifiers * for the transaction. */ interface INonceHolder { event ValueSetUnderNonce(address indexed accountAddress, uint256 indexed key, uint256 value); /// @dev Returns the current minimal nonce for account. function getMinNonce(address _address) external view returns (uint256); /// @dev Returns the raw version of the current minimal nonce /// (equal to minNonce + 2^128 * deployment nonce). function getRawNonce(address _address) external view returns (uint256); /// @dev Increases the minimal nonce for the msg.sender. function increaseMinNonce(uint256 _value) external returns (uint256); /// @dev Sets the nonce value `key` as used. function setValueUnderNonce(uint256 _key, uint256 _value) external; /// @dev Gets the value stored inside a custom nonce. function getValueUnderNonce(uint256 _key) external view returns (uint256); /// @dev A convenience method to increment the minimal nonce if it is equal /// to the `_expectedNonce`. function incrementMinNonceIfEquals(uint256 _expectedNonce) external; /// @dev Returns the deployment nonce for the accounts used for CREATE opcode. function getDeploymentNonce(address _address) external view returns (uint256); /// @dev Increments the deployment nonce for the account and returns the previous one. function incrementDeploymentNonce(address _address) external returns (uint256); /// @dev Determines whether a certain nonce has been already used for an account. function validateNonceUsage(address _address, uint256 _key, bool _shouldBeUsed) external view; /// @dev Returns whether a nonce has been used for an account. function isNonceUsed(address _address, uint256 _nonce) external view returns (bool); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; interface IContractDeployer { /// @notice Defines the version of the account abstraction protocol /// that a contract claims to follow. /// - `None` means that the account is just a contract and it should never be interacted /// with as a custom account /// - `Version1` means that the account follows the first version of the account abstraction protocol enum AccountAbstractionVersion { None, Version1 } /// @notice Defines the nonce ordering used by the account /// - `Sequential` means that it is expected that the nonces are monotonic and increment by 1 /// at a time (the same as EOAs). /// - `Arbitrary` means that the nonces for the accounts can be arbitrary. The operator /// should serve the transactions from such an account on a first-come-first-serve basis. /// @dev This ordering is more of a suggestion to the operator on how the AA expects its transactions /// to be processed and is not considered as a system invariant. enum AccountNonceOrdering { Sequential, Arbitrary } struct AccountInfo { AccountAbstractionVersion supportedAAVersion; AccountNonceOrdering nonceOrdering; } event ContractDeployed( address indexed deployerAddress, bytes32 indexed bytecodeHash, address indexed contractAddress ); event AccountNonceOrderingUpdated(address indexed accountAddress, AccountNonceOrdering nonceOrdering); event AccountVersionUpdated(address indexed accountAddress, AccountAbstractionVersion aaVersion); function getNewAddressCreate2( address _sender, bytes32 _bytecodeHash, bytes32 _salt, bytes calldata _input ) external view returns (address newAddress); function getNewAddressCreate(address _sender, uint256 _senderNonce) external pure returns (address newAddress); function create2( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input ) external payable returns (address newAddress); function create2Account( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input, AccountAbstractionVersion _aaVersion ) external payable returns (address newAddress); /// @dev While the `_salt` parameter is not used anywhere here, /// it is still needed for consistency between `create` and /// `create2` functions (required by the compiler). function create( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input ) external payable returns (address newAddress); /// @dev While `_salt` is never used here, we leave it here as a parameter /// for the consistency with the `create` function. function createAccount( bytes32 _salt, bytes32 _bytecodeHash, bytes calldata _input, AccountAbstractionVersion _aaVersion ) external payable returns (address newAddress); /// @notice Returns the information about a certain AA. function getAccountInfo(address _address) external view returns (AccountInfo memory info); /// @notice Can be called by an account to update its account version function updateAccountVersion(AccountAbstractionVersion _version) external; /// @notice Can be called by an account to update its nonce ordering function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; interface IBaseToken { function balanceOf(uint256) external view returns (uint256); function transferFromTo(address _from, address _to, uint256 _amount) external; function totalSupply() external view returns (uint256); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function mint(address _account, uint256 _amount) external; function withdraw(address _l1Receiver) external payable; function withdrawWithMessage(address _l1Receiver, bytes calldata _additionalData) external payable; event Mint(address indexed account, uint256 amount); event Transfer(address indexed from, address indexed to, uint256 value); event Withdrawal(address indexed _l2Sender, address indexed _l1Receiver, uint256 _amount); event WithdrawalWithMessage( address indexed _l2Sender, address indexed _l1Receiver, uint256 _amount, bytes _additionalData ); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The interface for the KnownCodesStorage contract, which is responsible * for storing the hashes of the bytecodes that have been published to the network. */ interface IKnownCodesStorage { event MarkedAsKnown(bytes32 indexed bytecodeHash, bool indexed sendBytecodeToL1); function markFactoryDeps(bool _shouldSendToL1, bytes32[] calldata _hashes) external; function markBytecodeAsPublished(bytes32 _bytecodeHash) external; function getMarker(bytes32 _hash) external view returns (uint256); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /// @dev The log passed from L2 /// @param l2ShardId The shard identifier, 0 - rollup, 1 - porter. All other values are not used but are reserved for the future /// @param isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address. /// This field is required formally but does not have any special meaning. /// @param txNumberInBlock The L2 transaction number in a block, in which the log was sent /// @param sender The L2 address which sent the log /// @param key The 32 bytes of information that was sent in the log /// @param value The 32 bytes of information that was sent in the log // Both `key` and `value` are arbitrary 32-bytes selected by the log sender struct L2ToL1Log { uint8 l2ShardId; bool isService; uint16 txNumberInBlock; address sender; bytes32 key; bytes32 value; } /// @dev Bytes in raw L2 to L1 log /// @dev Equal to the bytes size of the tuple - (uint8 ShardId, bool isService, uint16 txNumberInBlock, address sender, bytes32 key, bytes32 value) uint256 constant L2_TO_L1_LOG_SERIALIZE_SIZE = 88; /// @dev The value of default leaf hash for L2 to L1 logs Merkle tree /// @dev An incomplete fixed-size tree is filled with this value to be a full binary tree /// @dev Actually equal to the `keccak256(new bytes(L2_TO_L1_LOG_SERIALIZE_SIZE))` bytes32 constant L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH = 0x72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba; /// @dev The current version of state diff compression being used. uint256 constant STATE_DIFF_COMPRESSION_VERSION_NUMBER = 1; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The interface of the L1 Messenger contract, responsible for sending messages to L1. */ interface IL1Messenger { // Possibly in the future we will be able to track the messages sent to L1 with // some hooks in the VM. For now, it is much easier to track them with L2 events. event L1MessageSent(address indexed _sender, bytes32 indexed _hash, bytes _message); event L2ToL1LogSent(L2ToL1Log _l2log); event BytecodeL1PublicationRequested(bytes32 _bytecodeHash); function sendToL1(bytes memory _message) external returns (bytes32); function sendL2ToL1Log(bool _isService, bytes32 _key, bytes32 _value) external returns (uint256 logIdInMerkleTree); // This function is expected to be called only by the KnownCodesStorage system contract function requestBytecodeL1Publication(bytes32 _bytecodeHash) external; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; struct ImmutableData { uint256 index; bytes32 value; } interface IImmutableSimulator { function getImmutable(address _dest, uint256 _index) external view returns (bytes32); function setImmutables(address _dest, ImmutableData[] calldata _immutables) external; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice Contract that stores some of the context variables, that may be either * block-scoped, tx-scoped or system-wide. */ interface ISystemContext { struct BlockInfo { uint128 timestamp; uint128 number; } /// @notice A structure representing the timeline for the upgrade from the batch numbers to the L2 block numbers. /// @dev It will be used for the L1 batch -> L2 block migration in Q3 2023 only. struct VirtualBlockUpgradeInfo { /// @notice In order to maintain consistent results for `blockhash` requests, we'll /// have to remember the number of the batch when the upgrade to the virtual blocks has been done. /// The hashes for virtual blocks before the upgrade are identical to the hashes of the corresponding batches. uint128 virtualBlockStartBatch; /// @notice L2 block when the virtual blocks have caught up with the L2 blocks. Starting from this block, /// all the information returned to users for block.timestamp/number, etc should be the information about the L2 blocks and /// not virtual blocks. uint128 virtualBlockFinishL2Block; } function chainId() external view returns (uint256); function origin() external view returns (address); function gasPrice() external view returns (uint256); function blockGasLimit() external view returns (uint256); function coinbase() external view returns (address); function difficulty() external view returns (uint256); function baseFee() external view returns (uint256); function txNumberInBlock() external view returns (uint16); function getBlockHashEVM(uint256 _block) external view returns (bytes32); function getBatchHash(uint256 _batchNumber) external view returns (bytes32 hash); function getBlockNumber() external view returns (uint128); function getBlockTimestamp() external view returns (uint128); function getBatchNumberAndTimestamp() external view returns (uint128 blockNumber, uint128 blockTimestamp); function getL2BlockNumberAndTimestamp() external view returns (uint128 blockNumber, uint128 blockTimestamp); function gasPerPubdataByte() external view returns (uint256 gasPerPubdataByte); function getCurrentPubdataSpent() external view returns (uint256 currentPubdataSpent); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; // The bitmask by applying which to the compressed state diff metadata we retrieve its operation. uint8 constant OPERATION_BITMASK = 7; // The number of bits shifting the compressed state diff metadata by which we retrieve its length. uint8 constant LENGTH_BITS_OFFSET = 3; // The maximal length in bytes that an enumeration index can have. uint8 constant MAX_ENUMERATION_INDEX_SIZE = 8; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The interface for the Compressor contract, responsible for verifying the correctness of * the compression of the state diffs and bytecodes. */ interface ICompressor { function publishCompressedBytecode( bytes calldata _bytecode, bytes calldata _rawCompressedData ) external returns (bytes32 bytecodeHash); function verifyCompressedStateDiffs( uint256 _numberOfStateDiffs, uint256 _enumerationIndexSize, bytes calldata _stateDiffs, bytes calldata _compressedStateDiffs ) external returns (bytes32 stateDiffHash); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice Interface for contract responsible chunking pubdata into the appropriate size for EIP-4844 blobs. */ interface IPubdataChunkPublisher { /// @notice Chunks pubdata into pieces that can fit into blobs. /// @param _pubdata The total l2 to l1 pubdata that will be sent via L1 blobs. function chunkAndPublishPubdata(bytes calldata _pubdata) external; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The interface for the ComplexUpgrader contract. */ interface IComplexUpgrader { function upgrade(address _delegateTo, bytes calldata _calldata) external payable; }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {Transaction} from "../libraries/TransactionHelper.sol"; interface IBootloaderUtilities { function getTransactionHashes( Transaction calldata _transaction ) external view returns (bytes32 txHash, bytes32 signedTxHash); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); (bool success, ) = recipient.call{value: amount}(""); require( success, "Address: unable to send value, recipient may have reverted" ); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue( target, data, 0, "Address: low-level call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); (bool success, bytes memory returndata) = target.call{value: value}( data ); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall( target, data, "Address: low-level static call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall( target, data, "Address: low-level delegate call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {MAX_SYSTEM_CONTRACT_ADDRESS} from "../Constants.sol"; import {CALLFLAGS_CALL_ADDRESS, CODE_ADDRESS_CALL_ADDRESS, EVENT_WRITE_ADDRESS, EVENT_INITIALIZE_ADDRESS, GET_EXTRA_ABI_DATA_ADDRESS, LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS, META_CODE_SHARD_ID_OFFSET, META_CALLER_SHARD_ID_OFFSET, META_SHARD_ID_OFFSET, META_AUX_HEAP_SIZE_OFFSET, META_HEAP_SIZE_OFFSET, META_PUBDATA_PUBLISHED_OFFSET, META_CALL_ADDRESS, PTR_CALLDATA_CALL_ADDRESS, PTR_ADD_INTO_ACTIVE_CALL_ADDRESS, PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS, PTR_PACK_INTO_ACTIVE_CALL_ADDRESS, PRECOMPILE_CALL_ADDRESS, SET_CONTEXT_VALUE_CALL_ADDRESS, TO_L1_CALL_ADDRESS} from "./SystemContractsCaller.sol"; import {IndexOutOfBounds, FailedToChargeGas} from "../SystemContractErrors.sol"; uint256 constant UINT32_MASK = type(uint32).max; uint256 constant UINT64_MASK = type(uint64).max; uint256 constant UINT128_MASK = type(uint128).max; uint256 constant ADDRESS_MASK = type(uint160).max; /// @notice NOTE: The `getZkSyncMeta` that is used to obtain this struct will experience a breaking change in 2024. struct ZkSyncMeta { uint32 pubdataPublished; uint32 heapSize; uint32 auxHeapSize; uint8 shardId; uint8 callerShardId; uint8 codeShardId; } enum Global { CalldataPtr, CallFlags, ExtraABIData1, ExtraABIData2, ReturndataPtr } /** * @author Matter Labs * @custom:security-contact [email protected] * @notice Library used for accessing zkEVM-specific opcodes, needed for the development * of system contracts. * @dev While this library will be eventually available to public, some of the provided * methods won't work for non-system contracts and also breaking changes at short notice are possible. * We do not recommend this library for external use. */ library SystemContractHelper { /// @notice Send an L2Log to L1. /// @param _isService The `isService` flag. /// @param _key The `key` part of the L2Log. /// @param _value The `value` part of the L2Log. /// @dev The meaning of all these parameters is context-dependent, but they /// have no intrinsic meaning per se. function toL1(bool _isService, bytes32 _key, bytes32 _value) internal { address callAddr = TO_L1_CALL_ADDRESS; assembly { // Ensuring that the type is bool _isService := and(_isService, 1) // This `success` is always 0, but the method always succeeds // (except for the cases when there is not enough gas) // solhint-disable-next-line no-unused-vars let success := call(_isService, callAddr, _key, _value, 0xFFFF, 0, 0) } } /// @notice Get address of the currently executed code. /// @dev This allows differentiating between `call` and `delegatecall`. /// During the former `this` and `codeAddress` are the same, while /// during the latter they are not. function getCodeAddress() internal view returns (address addr) { address callAddr = CODE_ADDRESS_CALL_ADDRESS; assembly { addr := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Provide a compiler hint, by placing calldata fat pointer into virtual `ACTIVE_PTR`, /// that can be manipulated by `ptr.add`/`ptr.sub`/`ptr.pack`/`ptr.shrink` later. /// @dev This allows making a call by forwarding calldata pointer to the child call. /// It is a much more efficient way to forward calldata, than standard EVM bytes copying. function loadCalldataIntoActivePtr() internal view { address callAddr = LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS; assembly { pop(staticcall(0, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.pack` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Do the concatenation between lowest part of `ACTIVE_PTR` and highest part of `_farCallAbi` /// forming packed fat pointer for a far call or ret ABI when necessary. /// Note: Panics if the lowest 128 bits of `_farCallAbi` are not zeroes. function ptrPackIntoActivePtr(uint256 _farCallAbi) internal view { address callAddr = PTR_PACK_INTO_ACTIVE_CALL_ADDRESS; assembly { pop(staticcall(_farCallAbi, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.add` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Transforms `ACTIVE_PTR.offset` into `ACTIVE_PTR.offset + u32(_value)`. If overflow happens then it panics. function ptrAddIntoActive(uint32 _value) internal view { address callAddr = PTR_ADD_INTO_ACTIVE_CALL_ADDRESS; uint256 cleanupMask = UINT32_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default _value := and(_value, cleanupMask) pop(staticcall(_value, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice Compiler simulation of the `ptr.shrink` opcode for the virtual `ACTIVE_PTR` pointer. /// @dev Transforms `ACTIVE_PTR.length` into `ACTIVE_PTR.length - u32(_shrink)`. If underflow happens then it panics. function ptrShrinkIntoActive(uint32 _shrink) internal view { address callAddr = PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS; uint256 cleanupMask = UINT32_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default _shrink := and(_shrink, cleanupMask) pop(staticcall(_shrink, callAddr, 0, 0xFFFF, 0, 0)) } } /// @notice packs precompile parameters into one word /// @param _inputMemoryOffset The memory offset in 32-byte words for the input data for calling the precompile. /// @param _inputMemoryLength The length of the input data in words. /// @param _outputMemoryOffset The memory offset in 32-byte words for the output data. /// @param _outputMemoryLength The length of the output data in words. /// @param _perPrecompileInterpreted The constant, the meaning of which is defined separately for /// each precompile. For information, please read the documentation of the precompilecall log in /// the VM. function packPrecompileParams( uint32 _inputMemoryOffset, uint32 _inputMemoryLength, uint32 _outputMemoryOffset, uint32 _outputMemoryLength, uint64 _perPrecompileInterpreted ) internal pure returns (uint256 rawParams) { rawParams = _inputMemoryOffset; rawParams |= uint256(_inputMemoryLength) << 32; rawParams |= uint256(_outputMemoryOffset) << 64; rawParams |= uint256(_outputMemoryLength) << 96; rawParams |= uint256(_perPrecompileInterpreted) << 192; } /// @notice Call precompile with given parameters. /// @param _rawParams The packed precompile params. They can be retrieved by /// the `packPrecompileParams` method. /// @param _gasToBurn The number of gas to burn during this call. /// @param _pubdataToSpend The number of pubdata bytes to burn during the call. /// @return success Whether the call was successful. /// @dev The list of currently available precompiles sha256, keccak256, ecrecover. /// NOTE: The precompile type depends on `this` which calls precompile, which means that only /// system contracts corresponding to the list of precompiles above can do `precompileCall`. /// @dev If used not in the `sha256`, `keccak256` or `ecrecover` contracts, it will just burn the gas provided. /// @dev This method is `unsafe` because it does not check whether there is enough gas to burn. function unsafePrecompileCall( uint256 _rawParams, uint32 _gasToBurn, uint32 _pubdataToSpend ) internal view returns (bool success) { address callAddr = PRECOMPILE_CALL_ADDRESS; uint256 params = uint256(_gasToBurn) + (uint256(_pubdataToSpend) << 32); uint256 cleanupMask = UINT64_MASK; assembly { // Clearing input params as they are not cleaned by Solidity by default params := and(params, cleanupMask) success := staticcall(_rawParams, callAddr, params, 0xFFFF, 0, 0) } } /// @notice Set `msg.value` to next far call. /// @param _value The msg.value that will be used for the *next* call. /// @dev If called not in kernel mode, it will result in a revert (enforced by the VM) function setValueForNextFarCall(uint128 _value) internal returns (bool success) { uint256 cleanupMask = UINT128_MASK; address callAddr = SET_CONTEXT_VALUE_CALL_ADDRESS; assembly { // Clearing input params as they are not cleaned by Solidity by default _value := and(_value, cleanupMask) success := call(0, callAddr, _value, 0, 0xFFFF, 0, 0) } } /// @notice Initialize a new event. /// @param initializer The event initializing value. /// @param value1 The first topic or data chunk. function eventInitialize(uint256 initializer, uint256 value1) internal { address callAddr = EVENT_INITIALIZE_ADDRESS; assembly { pop(call(initializer, callAddr, value1, 0, 0xFFFF, 0, 0)) } } /// @notice Continue writing the previously initialized event. /// @param value1 The first topic or data chunk. /// @param value2 The second topic or data chunk. function eventWrite(uint256 value1, uint256 value2) internal { address callAddr = EVENT_WRITE_ADDRESS; assembly { pop(call(value1, callAddr, value2, 0, 0xFFFF, 0, 0)) } } /// @notice Get the packed representation of the `ZkSyncMeta` from the current context. /// @notice NOTE: The behavior of this function will experience a breaking change in 2024. /// @return meta The packed representation of the ZkSyncMeta. /// @dev The fields in ZkSyncMeta are NOT tightly packed, i.e. there is a special rule on how /// they are packed. For more information, please read the documentation on ZkSyncMeta. function getZkSyncMetaBytes() internal view returns (uint256 meta) { address callAddr = META_CALL_ADDRESS; assembly { meta := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the bits [offset..offset+size-1] of the meta. /// @param meta Packed representation of the ZkSyncMeta. /// @param offset The offset of the bits. /// @param size The size of the extracted number in bits. /// @return result The extracted number. function extractNumberFromMeta(uint256 meta, uint256 offset, uint256 size) internal pure returns (uint256 result) { // Firstly, we delete all the bits after the field uint256 shifted = (meta << (256 - size - offset)); // Then we shift everything back result = (shifted >> (256 - size)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of pubdata /// bytes published in the batch so far. /// @notice NOTE: The behavior of this function will experience a breaking change in 2024. /// @param meta Packed representation of the ZkSyncMeta. /// @return pubdataPublished The amount of pubdata published in the system so far. function getPubdataPublishedFromMeta(uint256 meta) internal pure returns (uint32 pubdataPublished) { pubdataPublished = uint32(extractNumberFromMeta(meta, META_PUBDATA_PUBLISHED_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of the current size /// of the heap in bytes. /// @param meta Packed representation of the ZkSyncMeta. /// @return heapSize The size of the memory in bytes byte. /// @dev The following expression: getHeapSizeFromMeta(getZkSyncMetaBytes()) is /// equivalent to the MSIZE in Solidity. function getHeapSizeFromMeta(uint256 meta) internal pure returns (uint32 heapSize) { heapSize = uint32(extractNumberFromMeta(meta, META_HEAP_SIZE_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the number of the current size /// of the auxiliary heap in bytes. /// @param meta Packed representation of the ZkSyncMeta. /// @return auxHeapSize The size of the auxiliary memory in bytes byte. /// @dev You can read more on auxiliary memory in the VM1.2 documentation. function getAuxHeapSizeFromMeta(uint256 meta) internal pure returns (uint32 auxHeapSize) { auxHeapSize = uint32(extractNumberFromMeta(meta, META_AUX_HEAP_SIZE_OFFSET, 32)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of `this`. /// @param meta Packed representation of the ZkSyncMeta. /// @return shardId The shardId of `this`. /// @dev Currently only shard 0 (zkRollup) is supported. function getShardIdFromMeta(uint256 meta) internal pure returns (uint8 shardId) { shardId = uint8(extractNumberFromMeta(meta, META_SHARD_ID_OFFSET, 8)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of /// the msg.sender. /// @param meta Packed representation of the ZkSyncMeta. /// @return callerShardId The shardId of the msg.sender. /// @dev Currently only shard 0 (zkRollup) is supported. function getCallerShardIdFromMeta(uint256 meta) internal pure returns (uint8 callerShardId) { callerShardId = uint8(extractNumberFromMeta(meta, META_CALLER_SHARD_ID_OFFSET, 8)); } /// @notice Given the packed representation of `ZkSyncMeta`, retrieves the shardId of /// the currently executed code. /// @param meta Packed representation of the ZkSyncMeta. /// @return codeShardId The shardId of the currently executed code. /// @dev Currently only shard 0 (zkRollup) is supported. function getCodeShardIdFromMeta(uint256 meta) internal pure returns (uint8 codeShardId) { codeShardId = uint8(extractNumberFromMeta(meta, META_CODE_SHARD_ID_OFFSET, 8)); } /// @notice Retrieves the ZkSyncMeta structure. /// @notice NOTE: The behavior of this function will experience a breaking change in 2024. /// @return meta The ZkSyncMeta execution context parameters. function getZkSyncMeta() internal view returns (ZkSyncMeta memory meta) { uint256 metaPacked = getZkSyncMetaBytes(); meta.pubdataPublished = getPubdataPublishedFromMeta(metaPacked); meta.heapSize = getHeapSizeFromMeta(metaPacked); meta.auxHeapSize = getAuxHeapSizeFromMeta(metaPacked); meta.shardId = getShardIdFromMeta(metaPacked); meta.callerShardId = getCallerShardIdFromMeta(metaPacked); meta.codeShardId = getCodeShardIdFromMeta(metaPacked); } /// @notice Returns the call flags for the current call. /// @return callFlags The bitmask of the callflags. /// @dev Call flags is the value of the first register /// at the start of the call. /// @dev The zero bit of the callFlags indicates whether the call is /// a constructor call. The first bit of the callFlags indicates whether /// the call is a system one. function getCallFlags() internal view returns (uint256 callFlags) { address callAddr = CALLFLAGS_CALL_ADDRESS; assembly { callFlags := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the current calldata pointer. /// @return ptr The current calldata pointer. /// @dev NOTE: This file is just an integer and it cannot be used /// to forward the calldata to the next calls in any way. function getCalldataPtr() internal view returns (uint256 ptr) { address callAddr = PTR_CALLDATA_CALL_ADDRESS; assembly { ptr := staticcall(0, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns the N-th extraAbiParam for the current call. /// @return extraAbiData The value of the N-th extraAbiParam for this call. /// @dev It is equal to the value of the (N+2)-th register /// at the start of the call. function getExtraAbiData(uint256 index) internal view returns (uint256 extraAbiData) { // Note that there are only 10 accessible registers (indices 0-9 inclusively) if (index > 9) { revert IndexOutOfBounds(); } address callAddr = GET_EXTRA_ABI_DATA_ADDRESS; assembly { extraAbiData := staticcall(index, callAddr, 0, 0xFFFF, 0, 0) } } /// @notice Returns whether the current call is a system call. /// @return `true` or `false` based on whether the current call is a system call. function isSystemCall() internal view returns (bool) { uint256 callFlags = getCallFlags(); // When the system call is passed, the 2-bit is set to 1 return (callFlags & 2) != 0; } /// @notice Returns whether the address is a system contract. /// @param _address The address to test /// @return `true` or `false` based on whether the `_address` is a system contract. function isSystemContract(address _address) internal pure returns (bool) { return uint160(_address) <= uint160(MAX_SYSTEM_CONTRACT_ADDRESS); } /// @notice Method used for burning a certain amount of gas. /// @param _gasToPay The number of gas to burn. /// @param _pubdataToSpend The number of pubdata bytes to burn during the call. function burnGas(uint32 _gasToPay, uint32 _pubdataToSpend) internal view { bool precompileCallSuccess = unsafePrecompileCall( 0, // The precompile parameters are formal ones. We only need the precompile call to burn gas. _gasToPay, _pubdataToSpend ); if (!precompileCallSuccess) { revert FailedToChargeGas(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {MSG_VALUE_SYSTEM_CONTRACT, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT} from "../Constants.sol"; import {Utils} from "./Utils.sol"; // Addresses used for the compiler to be replaced with the // ZKsync-specific opcodes during the compilation. // IMPORTANT: these are just compile-time constants and are used // only if used in-place by Yul optimizer. address constant TO_L1_CALL_ADDRESS = address((1 << 16) - 1); address constant CODE_ADDRESS_CALL_ADDRESS = address((1 << 16) - 2); address constant PRECOMPILE_CALL_ADDRESS = address((1 << 16) - 3); address constant META_CALL_ADDRESS = address((1 << 16) - 4); address constant MIMIC_CALL_CALL_ADDRESS = address((1 << 16) - 5); address constant SYSTEM_MIMIC_CALL_CALL_ADDRESS = address((1 << 16) - 6); address constant MIMIC_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 7); address constant SYSTEM_MIMIC_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 8); address constant RAW_FAR_CALL_CALL_ADDRESS = address((1 << 16) - 9); address constant RAW_FAR_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 10); address constant SYSTEM_CALL_CALL_ADDRESS = address((1 << 16) - 11); address constant SYSTEM_CALL_BY_REF_CALL_ADDRESS = address((1 << 16) - 12); address constant SET_CONTEXT_VALUE_CALL_ADDRESS = address((1 << 16) - 13); address constant SET_PUBDATA_PRICE_CALL_ADDRESS = address((1 << 16) - 14); address constant INCREMENT_TX_COUNTER_CALL_ADDRESS = address((1 << 16) - 15); address constant PTR_CALLDATA_CALL_ADDRESS = address((1 << 16) - 16); address constant CALLFLAGS_CALL_ADDRESS = address((1 << 16) - 17); address constant PTR_RETURNDATA_CALL_ADDRESS = address((1 << 16) - 18); address constant EVENT_INITIALIZE_ADDRESS = address((1 << 16) - 19); address constant EVENT_WRITE_ADDRESS = address((1 << 16) - 20); address constant LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS = address((1 << 16) - 21); address constant LOAD_LATEST_RETURNDATA_INTO_ACTIVE_PTR_CALL_ADDRESS = address((1 << 16) - 22); address constant PTR_ADD_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 23); address constant PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 24); address constant PTR_PACK_INTO_ACTIVE_CALL_ADDRESS = address((1 << 16) - 25); address constant MULTIPLICATION_HIGH_ADDRESS = address((1 << 16) - 26); address constant GET_EXTRA_ABI_DATA_ADDRESS = address((1 << 16) - 27); // All the offsets are in bits uint256 constant META_PUBDATA_PUBLISHED_OFFSET = 0 * 8; uint256 constant META_HEAP_SIZE_OFFSET = 8 * 8; uint256 constant META_AUX_HEAP_SIZE_OFFSET = 12 * 8; uint256 constant META_SHARD_ID_OFFSET = 28 * 8; uint256 constant META_CALLER_SHARD_ID_OFFSET = 29 * 8; uint256 constant META_CODE_SHARD_ID_OFFSET = 30 * 8; /// @notice The way to forward the calldata: /// - Use the current heap (i.e. the same as on EVM). /// - Use the auxiliary heap. /// - Forward via a pointer /// @dev Note, that currently, users do not have access to the auxiliary /// heap and so the only type of forwarding that will be used by the users /// are UseHeap and ForwardFatPointer for forwarding a slice of the current calldata /// to the next call. enum CalldataForwardingMode { UseHeap, ForwardFatPointer, UseAuxHeap } /** * @author Matter Labs * @custom:security-contact [email protected] * @notice A library that allows calling contracts with the `isSystem` flag. * @dev It is needed to call ContractDeployer and NonceHolder. */ library SystemContractsCaller { /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return success Whether the transaction has been successful. /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCall(uint32 gasLimit, address to, uint256 value, bytes memory data) internal returns (bool success) { address callAddr = SYSTEM_CALL_CALL_ADDRESS; uint32 dataStart; assembly { dataStart := add(data, 0x20) } uint32 dataLength = Utils.safeCastToU32(data.length); uint256 farCallAbi = SystemContractsCaller.getFarCallABI({ dataOffset: 0, memoryPage: 0, dataStart: dataStart, dataLength: dataLength, gasPassed: gasLimit, // Only rollup is supported for now shardId: 0, forwardingMode: CalldataForwardingMode.UseHeap, isConstructorCall: false, isSystemCall: true }); if (value == 0) { // Doing the system call directly assembly { success := call(to, callAddr, 0, 0, farCallAbi, 0, 0) } } else { address msgValueSimulator = MSG_VALUE_SYSTEM_CONTRACT; // We need to supply the mask to the MsgValueSimulator to denote // that the call should be a system one. uint256 forwardMask = MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT; assembly { success := call(msgValueSimulator, callAddr, value, to, farCallAbi, forwardMask, 0) } } } /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return success Whether the transaction has been successful. /// @return returnData The returndata of the transaction (revert reason in case the transaction has failed). /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCallWithReturndata( uint32 gasLimit, address to, uint128 value, bytes memory data ) internal returns (bool success, bytes memory returnData) { success = systemCall(gasLimit, to, value, data); uint256 size; assembly { size := returndatasize() } returnData = new bytes(size); assembly { returndatacopy(add(returnData, 0x20), 0, size) } } /// @notice Makes a call with the `isSystem` flag. /// @param gasLimit The gas limit for the call. /// @param to The address to call. /// @param value The value to pass with the transaction. /// @param data The calldata. /// @return returnData The returndata of the transaction. In case the transaction reverts, the error /// bubbles up to the parent frame. /// @dev Note, that the `isSystem` flag can only be set when calling system contracts. function systemCallWithPropagatedRevert( uint32 gasLimit, address to, uint128 value, bytes memory data ) internal returns (bytes memory returnData) { bool success; (success, returnData) = systemCallWithReturndata(gasLimit, to, value, data); if (!success) { assembly { let size := mload(returnData) revert(add(returnData, 0x20), size) } } } /// @notice Calculates the packed representation of the FarCallABI. /// @param dataOffset Calldata offset in memory. Provide 0 unless using custom pointer. /// @param memoryPage Memory page to use. Provide 0 unless using custom pointer. /// @param dataStart The start of the calldata slice. Provide the offset in memory /// if not using custom pointer. /// @param dataLength The calldata length. Provide the length of the calldata in bytes /// unless using custom pointer. /// @param gasPassed The gas to pass with the call. /// @param shardId Of the account to call. Currently only 0 is supported. /// @param forwardingMode The forwarding mode to use: /// - provide CalldataForwardingMode.UseHeap when using your current memory /// - provide CalldataForwardingMode.ForwardFatPointer when using custom pointer. /// @param isConstructorCall Whether the call will be a call to the constructor /// (ignored when the caller is not a system contract). /// @param isSystemCall Whether the call will have the `isSystem` flag. /// @return farCallAbi The far call ABI. /// @dev The `FarCallABI` has the following structure: /// pub struct FarCallABI { /// pub memory_quasi_fat_pointer: FatPointer, /// pub gas_passed: u32, /// pub shard_id: u8, /// pub forwarding_mode: FarCallForwardPageType, /// pub constructor_call: bool, /// pub to_system: bool, /// } /// /// The FatPointer struct: /// /// pub struct FatPointer { /// pub offset: u32, // offset relative to `start` /// pub memory_page: u32, // memory page where slice is located /// pub start: u32, // absolute start of the slice /// pub length: u32, // length of the slice /// } /// /// @dev Note, that the actual layout is the following: /// /// [0..32) bits -- the calldata offset /// [32..64) bits -- the memory page to use. Can be left blank in most of the cases. /// [64..96) bits -- the absolute start of the slice /// [96..128) bits -- the length of the slice. /// [128..192) bits -- empty bits. /// [192..224) bits -- gasPassed. /// [224..232) bits -- forwarding_mode /// [232..240) bits -- shard id. /// [240..248) bits -- constructor call flag /// [248..256] bits -- system call flag function getFarCallABI( uint32 dataOffset, uint32 memoryPage, uint32 dataStart, uint32 dataLength, uint32 gasPassed, uint8 shardId, CalldataForwardingMode forwardingMode, bool isConstructorCall, bool isSystemCall ) internal pure returns (uint256 farCallAbi) { // Fill in the call parameter fields farCallAbi = getFarCallABIWithEmptyFatPointer({ gasPassed: gasPassed, shardId: shardId, forwardingMode: forwardingMode, isConstructorCall: isConstructorCall, isSystemCall: isSystemCall }); // Fill in the fat pointer fields farCallAbi |= dataOffset; farCallAbi |= (uint256(memoryPage) << 32); farCallAbi |= (uint256(dataStart) << 64); farCallAbi |= (uint256(dataLength) << 96); } /// @notice Calculates the packed representation of the FarCallABI with zero fat pointer fields. /// @param gasPassed The gas to pass with the call. /// @param shardId Of the account to call. Currently only 0 is supported. /// @param forwardingMode The forwarding mode to use: /// - provide CalldataForwardingMode.UseHeap when using your current memory /// - provide CalldataForwardingMode.ForwardFatPointer when using custom pointer. /// @param isConstructorCall Whether the call will be a call to the constructor /// (ignored when the caller is not a system contract). /// @param isSystemCall Whether the call will have the `isSystem` flag. /// @return farCallAbiWithEmptyFatPtr The far call ABI with zero fat pointer fields. function getFarCallABIWithEmptyFatPointer( uint32 gasPassed, uint8 shardId, CalldataForwardingMode forwardingMode, bool isConstructorCall, bool isSystemCall ) internal pure returns (uint256 farCallAbiWithEmptyFatPtr) { farCallAbiWithEmptyFatPtr |= (uint256(gasPassed) << 192); farCallAbiWithEmptyFatPtr |= (uint256(forwardingMode) << 224); farCallAbiWithEmptyFatPtr |= (uint256(shardId) << 232); if (isConstructorCall) { farCallAbiWithEmptyFatPtr |= (1 << 240); } if (isSystemCall) { farCallAbiWithEmptyFatPtr |= (1 << 248); } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; import {EfficientCall} from "./EfficientCall.sol"; import {MalformedBytecode, BytecodeError, Overflow} from "../SystemContractErrors.sol"; /** * @author Matter Labs * @custom:security-contact [email protected] * @dev Common utilities used in ZKsync system contracts */ library Utils { /// @dev Bit mask of bytecode hash "isConstructor" marker bytes32 internal constant IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK = 0x00ff000000000000000000000000000000000000000000000000000000000000; /// @dev Bit mask to set the "isConstructor" marker in the bytecode hash bytes32 internal constant SET_IS_CONSTRUCTOR_MARKER_BIT_MASK = 0x0001000000000000000000000000000000000000000000000000000000000000; function safeCastToU128(uint256 _x) internal pure returns (uint128) { if (_x > type(uint128).max) { revert Overflow(); } return uint128(_x); } function safeCastToU32(uint256 _x) internal pure returns (uint32) { if (_x > type(uint32).max) { revert Overflow(); } return uint32(_x); } function safeCastToU24(uint256 _x) internal pure returns (uint24) { if (_x > type(uint24).max) { revert Overflow(); } return uint24(_x); } /// @return codeLength The bytecode length in bytes function bytecodeLenInBytes(bytes32 _bytecodeHash) internal pure returns (uint256 codeLength) { codeLength = bytecodeLenInWords(_bytecodeHash) << 5; // _bytecodeHash * 32 } /// @return codeLengthInWords The bytecode length in machine words function bytecodeLenInWords(bytes32 _bytecodeHash) internal pure returns (uint256 codeLengthInWords) { unchecked { codeLengthInWords = uint256(uint8(_bytecodeHash[2])) * 256 + uint256(uint8(_bytecodeHash[3])); } } /// @notice Denotes whether bytecode hash corresponds to a contract that already constructed function isContractConstructed(bytes32 _bytecodeHash) internal pure returns (bool) { return _bytecodeHash[1] == 0x00; } /// @notice Denotes whether bytecode hash corresponds to a contract that is on constructor or has already been constructed function isContractConstructing(bytes32 _bytecodeHash) internal pure returns (bool) { return _bytecodeHash[1] == 0x01; } /// @notice Sets "isConstructor" flag to TRUE for the bytecode hash /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag /// @return The bytecode hash with "isConstructor" flag set to TRUE function constructingBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { // Clear the "isConstructor" marker and set it to 0x01. return constructedBytecodeHash(_bytecodeHash) | SET_IS_CONSTRUCTOR_MARKER_BIT_MASK; } /// @notice Sets "isConstructor" flag to FALSE for the bytecode hash /// @param _bytecodeHash The bytecode hash for which it is needed to set the constructing flag /// @return The bytecode hash with "isConstructor" flag set to FALSE function constructedBytecodeHash(bytes32 _bytecodeHash) internal pure returns (bytes32) { return _bytecodeHash & ~IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK; } /// @notice Validate the bytecode format and calculate its hash. /// @param _bytecode The bytecode to hash. /// @return hashedBytecode The 32-byte hash of the bytecode. /// Note: The function reverts the execution if the bytecode has non expected format: /// - Bytecode bytes length is not a multiple of 32 /// - Bytecode bytes length is not less than 2^21 bytes (2^16 words) /// - Bytecode words length is not odd function hashL2Bytecode(bytes calldata _bytecode) internal view returns (bytes32 hashedBytecode) { // Note that the length of the bytecode must be provided in 32-byte words. if (_bytecode.length % 32 != 0) { revert MalformedBytecode(BytecodeError.Length); } uint256 lengthInWords = _bytecode.length / 32; // bytecode length must be less than 2^16 words if (lengthInWords >= 2 ** 16) { revert MalformedBytecode(BytecodeError.NumberOfWords); } // bytecode length in words must be odd if (lengthInWords % 2 == 0) { revert MalformedBytecode(BytecodeError.WordsMustBeOdd); } hashedBytecode = EfficientCall.sha(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // Setting the version of the hash hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); // Setting the length hashedBytecode = hashedBytecode | bytes32(lengthInWords << 224); } }
{ "optimizer": { "enabled": true, "mode": "3" }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "abi", "metadata" ], "": [ "ast" ] } }, "detectMissingLibraries": false, "forceEVMLA": false, "enableEraVMExtensions": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_oldValue","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_newValue","type":"uint256"}],"name":"EPGasOverheadChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"paymasterId","type":"address"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"}],"name":"GasDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"paymasterId","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"}],"name":"GasWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"paymasterId","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"bytes32","name":"signedHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"deducted","type":"uint256"}],"name":"PaymasterSponsored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymasterId","type":"address"}],"name":"depositFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"paymasterId","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"paymasterData","type":"bytes"}],"name":"parsePaymasterData","outputs":[{"internalType":"address","name":"paymasterId","type":"address"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint48","name":"validAfter","type":"uint48"},{"internalType":"bytes","name":"signature","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_context","type":"bytes"},{"components":[{"internalType":"uint256","name":"txType","type":"uint256"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPerPubdataByteLimit","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"paymaster","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256[4]","name":"reserved","type":"uint256[4]"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32[]","name":"factoryDeps","type":"bytes32[]"},{"internalType":"bytes","name":"paymasterInput","type":"bytes"},{"internalType":"bytes","name":"reservedDynamic","type":"bytes"}],"internalType":"struct Transaction","name":"","type":"tuple"},{"internalType":"bytes32","name":"_txHash","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"enum ExecutionResult","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"postTransaction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"txHashBySignedHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"components":[{"internalType":"uint256","name":"txType","type":"uint256"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPerPubdataByteLimit","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"paymaster","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256[4]","name":"reserved","type":"uint256[4]"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32[]","name":"factoryDeps","type":"bytes32[]"},{"internalType":"bytes","name":"paymasterInput","type":"bytes"},{"internalType":"bytes","name":"reservedDynamic","type":"bytes"}],"internalType":"struct Transaction","name":"_transaction","type":"tuple"}],"name":"validateAndPayForPaymasterTransaction","outputs":[{"internalType":"bytes4","name":"magic","type":"bytes4"},{"internalType":"bytes","name":"context","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"withdrawAdditional","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
3cda335177848cc6491aefbc24663248d77de123319246bbef09198c9235d800000000b3010002796dfa73dd47befa15ad2ba98cfcc183598819e3fc6284fe6a28247c3200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a860b0c8187ae5eaf719a5d56334a53bcbade3d9
Deployed Bytecode
0x0004000000000002000900000000000200000000030200190000006004100270000002150240019700030000002103550002000000010355000002150040019d0000000100300190000000380000c13d0000008003000039000000400030043f000000040020008c000005580000413d000000000301043b000000e0033002700000021e0030009c000000900000a13d0000021f0030009c000000d50000213d000002250030009c000001620000213d000002280030009c000001e60000613d000002290030009c000005580000c13d000000440020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000002402100370000000000202043b000900000002001d000002180020009c000005580000213d0000000401100370000000000101043b000000000010043f000000200000043f00000040020000390000000001000019084f08300000040f0000000902000029000000000020043f000000200010043f00000000010000190000004002000039084f08300000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f0000023301000041000008500001042e0000001f0320003900000216033001970000008003300039000000400030043f0000001f0420018f00000217052001980000008003500039000000460000613d0000008006000039000000000701034f000000007807043c0000000006860436000000000036004b000000420000c13d000000000004004b000000530000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000001f0020008c000005580000a13d000000800300043d000002180030009c000005580000213d0000000101000039000000000011041b000000000030043f0000021901000041000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039000900000003001d084f084a0000040f00000009030000290000000100200190000005580000613d000000000101043b000000000101041a000000ff001001900000008b0000c13d000000000030043f0000021901000041000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f00000009060000290000000100200190000005580000613d000000000101043b000000000201041a000002730220019700000001022001bf000000000021041b0000000001000414000002150010009c0000021501008041000000c0011002100000021b011001c70000800d02000039000000040300003900000000070004110000021c040000410000000005000019084f08450000040f0000000100200190000005580000613d0000002001000039000001000010044300000120000004430000021d01000041000008500001042e0000022a0030009c000001040000a13d0000022b0030009c000001270000213d0000022e0030009c000001840000613d0000022f0030009c000005580000c13d000000440020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000402100370000000000202043b000900000002001d0000002401100370000000000101043b000800000001001d000002180010009c000005580000213d0000000901000029000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000101100039000000000101041a000700000001001d000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000002000411000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000101041a000000ff00100190000003070000c13d000000400100043d00000024021000390000000703000029000000f90000013d000002200030009c000001700000213d000002230030009c000002260000613d000002240030009c000005580000c13d000000240020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000401100370000000000101043b000900000001001d000002180010009c000005580000213d0000000001000411000000000010043f0000023401000041000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000101041a000000ff00100190000002780000c13d000000400100043d00000024021000390000023703000041000000000032043500000238020000410000000000210435000000040210003900000000030004110000000000320435000002150010009c0000021501008041000000400110021000000239011001c70000085100010430000002300030009c000002550000613d000002310030009c000001a60000613d000002320030009c000005580000c13d000000440020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000402100370000000000202043b000900000002001d000002180020009c000005580000213d0000002401100370000000000201043b0000000103000039000000000103041a000000020010008c000002310000613d0000000204000039000000000043041b000000090000006b000002a90000c13d0000023b01000041000000800010043f0000002001000039000000840010043f000000a40010043f0000024a01000041000000c40010043f0000023d0100004100000851000104300000022c0030009c000001950000613d0000022d0030009c000005580000c13d000000c40020008c000005580000413d0000000403100370000000000503043b0000023f0050009c000005580000213d0000002303500039000000000023004b000005580000813d0000000404500039000000000341034f000000000303043b0000023f0030009c000005580000213d00000000053500190000002405500039000000000025004b000005580000213d0000002405100370000000000505043b0000023f0050009c000005580000213d0000000002520049000002410020009c000005580000213d000002640020008c000005580000413d0000008402100370000000000202043b000000010020008c000005580000213d0000002002400039000000000221034f000000000202043b0000001f0030008c000001550000213d00000003043002100000010004400089000002740440021f000000000003004b0000000004006019000000000242016f000000000020043f0000000402000039000000200020043f0000004401100370000000000101043b000900000001001d00000040020000390000000001000019084f08300000040f0000000902000029000000000021041b0000000001000019000008500001042e000002260030009c000002350000613d000002270030009c000005580000c13d000000240020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000401100370000000000101043b000000000010043f00000004010000390000017f0000013d000002210030009c0000023b0000613d000002220030009c000005580000c13d000000240020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000401100370000000000101043b000002180010009c000005580000213d000000000010043f0000000201000039000000200010043f00000040020000390000000001000019084f08300000040f000001910000013d000000240020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000401100370000000000101043b000000000010043f000000200000043f00000040020000390000000001000019084f08300000040f0000000101100039000000000101041a000000800010043f0000023301000041000008500001042e000000440020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000002402100370000000000302043b000002180030009c000005580000213d0000000002000411000000000023004b000002660000c13d0000000401100370000000000101043b084f07700000040f0000000001000019000008500001042e000000640020008c000005580000413d0000004403100370000000000303043b0000023f0030009c000005580000213d0000000004320049000002410040009c000005580000213d000002640040008c000005580000413d0000000005000411000080010050008c0000029d0000c13d000902240030003d0000000905100360000000000505043b000000230440008a0000024f065001970000024f07400197000000000876013f000000000076004b00000000060000190000024f06004041000000000045004b00000000040000190000024f040080410000024f0080009c000000000604c019000000000006004b000005580000c13d00000000045300190000000405400039000000000451034f000000000404043b0000023f0040009c000005580000213d00000000024200490000002005500039000000000025004b00000000060000190000024f060020410000024f022001970000024f05500197000000000725013f000000000025004b00000000020000190000024f020040410000024f0070009c000000000206c019000000000002004b000005580000c13d000000030040008c000003720000213d0000023b01000041000000800010043f0000002001000039000000840010043f0000001501000039000000a40010043f0000026f01000041000000c40010043f0000023d010000410000085100010430000000240020008c000005580000413d0000000003000416000000000003004b000005580000c13d0000000401100370000000000101043b0000023f0010009c000005580000213d0000000401100039084f07270000040f084f081c0000040f0000024006200197000000400200043d0000002007200039000000000067043500000240033001970000004006200039000000000036043500000060032000390000008006000039000000000063043500000218011001970000000000120435000000800120003900000000005104350000001f0750018f0000027508500198000000a003200039000000000683001900000002044003670000020c0000613d000000000904034f000000000a030019000000009b09043c000000000aba043600000000006a004b000002080000c13d000000000007004b000002190000613d000000000484034f0000000307700210000000000806043300000000087801cf000000000878022f000000000404043b0000010007700089000000000474022f00000000047401cf000000000484019f00000000004604350000001f04500039000002750140019700000000035300190000000000030435000000a001100039000002150010009c00000215010080410000006001100210000002150020009c00000215020080410000004002200210000000000121019f000008500001042e000000240020008c000005580000413d0000000401100370000000000101043b000900000001001d000002180010009c000005580000213d0000000101000039000000000201041a000000020020008c0000026a0000c13d0000024b01000041000000800010043f000002430100004100000851000104300000000001000416000000000001004b000005580000c13d000000800000043f0000023301000041000008500001042e000000440020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000002402100370000000000202043b000900000002001d000002180020009c000005580000213d0000000401100370000000000101043b000800000001001d000000000010043f000000200000043f00000040020000390000000001000019084f08300000040f0000000101100039000000000101041a084f07410000040f00000008010000290000000902000029084f07700000040f0000000001000019000008500001042e000000240020008c000005580000413d0000000002000416000000000002004b000005580000c13d0000000401100370000000000101043b0000027000100198000005580000c13d000002710010009c00000000020000390000000102006039000002720010009c00000001022061bf000000800020043f0000023301000041000008500001042e0000024201000041000000800010043f000002430100004100000851000104300000000202000039000000000021041b000000090000006b000002900000c13d0000023b01000041000000800010043f0000002001000039000000840010043f0000001301000039000000a40010043f0000023e01000041000000c40010043f0000023d01000041000008510001043000000235010000410000000000100443000000000100041000000004001004430000000001000414000002150010009c0000021501008041000000c00110021000000236011001c70000800a02000039084f084a0000040f0000000100200190000006b20000613d0000000302000039000000000202041a000000000101043b000000000221004b000003520000813d0000026701000041000000000010043f0000001101000039000000040010043f0000025b0100004100000851000104300000000001000416000000000001004b000002cf0000c13d0000023b01000041000000800010043f0000002001000039000000840010043f0000001701000039000000a40010043f0000023c01000041000000c40010043f0000023d0100004100000851000104300000023b01000041000000800010043f0000002001000039000000840010043f0000002401000039000000a40010043f0000024c01000041000000c40010043f0000024d01000041000000e40010043f0000024e010000410000085100010430000700000003001d000800000002001d0000000001000411000000000010043f000000200040043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000101041a000000080110006c000003560000813d000000400100043d0000006402100039000002470300004100000000003204350000004402100039000002480300004100000000003204350000002402100039000000220300003900000000003204350000023b020000410000000000210435000000040210003900000020030000390000000000320435000002150010009c0000021501008041000000400110021000000249011001c700000851000104300000000901000029000000000010043f000000200020043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000201041a0000000001000416000800000002001d000000000012001a0000028a0000413d0000000901000029000000000010043f0000000201000039000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d00000000060004160000000802600029000000000101043b000000000021041b0000000303000039000000000103041a000000000061001a0000028a0000413d0000000001610019000000000013041b0000000001000414000002150010009c0000021501008041000000c0011002100000021b011001c70000800d020000390000023a040000410000000905000029084f08450000040f0000000100200190000005580000613d0000000101000039000000000011041b0000000001000019000008500001042e0000000901000029000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000101041a000000ff00100190000003500000c13d0000000901000029000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000802000029000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000201041a000002730220019700000001022001bf000000000021041b0000000001000414000002150010009c0000021501008041000000c0011002100000021b011001c70000800d0200003900000004030000390000021c04000041000000090500002900000008060000290000000007000411084f08450000040f0000000100200190000005580000613d0000000001000019000008500001042e0000000901000029084f07bf0000040f0000000001000019000008500001042e000600000001001d0000000001000411000000000010043f0000000201000039000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000602000029000000000021041b0000000301000039000000000201041a000000080220006c0000028a0000413d000000000021041b00000000010004140000000902000029000000040020008c000005330000c13d0000000101000031000005450000013d0000000904000029000001800240008a000000000221034f000001600440008a000000000441034f000000000404043b000000000202043b000800000004001d000000000042004b000003940000613d000002500100004100000000001004430000000001000414000002150010009c0000021501008041000000c00110021000000251011001c70000800b02000039084f084a0000040f0000000100200190000006b20000613d000000000101043b000000080010002a0000028a0000413d000000080410002900000002010003670000004402100370000000000302043b000000a402300039000000000221034f000000000202043b000000000024004b0000000004028019000800000004001d0000006404300039000000000241034f000000000202043b000000000002004b0000039d0000613d00000008052000b900000000022500d9000000080020006b0000028a0000c13d00000009061003600000000403300039000000000200003100000000053200490000001f0550008a000000000706043b0000024f087001970000024f06500197000000000968013f000000000068004b00000000080000190000024f08004041000000000057004b000000000a0000190000024f0a0080410000024f0090009c00000000080ac019000000000008004b000005580000c13d000700000037001d0000000707100360000000000707043b000900000007001d0000023f0070009c000005580000213d0000000907000029000000040070008c000005580000413d000000090820006a00000007070000290000002007700039000000000087004b00000000090000190000024f090020410000024f088001970000024f0a700197000000000b8a013f00000000008a004b00000000080000190000024f080040410000024f00b0009c000000000809c019000000000008004b000005580000c13d000000000871034f000000000808043b0000025208800197000002530080009c0000059a0000c13d00000009080000290006002400800094000005580000413d0000016004400039000000000441034f000000000404043b0000024f08400197000000000968013f000000000068004b00000000060000190000024f06004041000000000054004b00000000050000190000024f050080410000024f0090009c000000000605c0190000001e0570003900000004087000390000001807700039000000000771034f000000000881034f000000000551034f000000000505043b000500000005001d000000000508043b000400000005001d000000000507043b000300000005001d000000000006004b000005580000c13d0000000004340019000000000341034f000000000303043b0000023f0030009c000005580000213d000000000532004900000020064000390000024f045001970000024f07600197000000000847013f000000000047004b00000000040000190000024f04004041000000000056004b00000000050000190000024f050020410000024f0080009c000000000405c019000000000004004b000005580000c13d0000001f0430003900000275044001970000003f044000390000027505400197000000400400043d0000000005540019000000000045004b000000000700003900000001070040390000023f0050009c0000055c0000213d00000001007001900000055c0000c13d000000400050043f00000000053404360000000007630019000000000027004b000005580000213d000000000261034f00000275063001980000001f0730018f00000000016500190000041d0000613d000000000802034f0000000009050019000000008a08043c0000000009a90436000000000019004b000004190000c13d000000000007004b0000042a0000613d000000000262034f0000000306700210000000000701043300000000076701cf000000000767022f000000000202043b0000010006600089000000000262022f00000000026201cf000000000272019f000000000021043500000000013500190000000000010435000002150050009c000002150500804100000040015002100000000002040433000002150020009c00000215020080410000006002200210000000000112019f0000000002000414000002150020009c0000021502008041000000c002200210000000000112019f0000021b011001c70000801002000039084f084a0000040f0000000100200190000005580000613d00000002020003670000004403200370000000000303043b0000002404300039000000000442034f000000000404043b0000021804400197000000000101043b000000400600043d0000002005600039000100000005001d00000000004504350000010404300039000000000442034f000000000404043b000000400560003900000000004504350000004404300039000000000442034f000000000404043b0000021804400197000000600560003900000000004504350000012404300039000000000442034f000000000404043b000000a0056000390000000000150435000000800160003900000000004104350000006401300039000000000112034f000000000101043b000000c0046000390000000000140435000000a401300039000000000112034f000000000101043b000000e0046000390000000000140435000000c401300039000000000112034f000000000101043b0000010002600039000000000012043500000100010000390000000000160435000200000006001d000002550060009c0000055c0000213d000002560100004100000000001004430000000001000414000002150010009c0000021501008041000000c00110021000000251011001c70000800b02000039084f084a0000040f0000000100200190000006b20000613d0000000502000029000000d004200270000000040200002900000060032002700000000302000029000000d005200270000000000101043b0000000206000029000001c002600039000300000004001d0000000000420435000001a002600039000400000005001d00000000005204350000018002600039000500000003001d0000000000320435000001600260003900000000030004100000000000320435000001400360003900000000001304350000012005600039000000a0010000390000000000150435000002570060009c0000055c0000213d0000000204000029000001e001400039000000400010043f00000200024000390000000004040433000000000004004b0000000109000029000004a60000613d000000000600001900000000072600190000000008960019000000000808043300000000008704350000002006600039000000000046004b0000049f0000413d000000000624001900000000000604350000000005050433000000000005004b000004b30000613d000000000700001900000000086700190000000009370019000000000909043300000000009804350000002007700039000000000057004b000004ac0000413d00000000036500190000000000030435000000000345001900000000003104350000003f0330003900000275043001970000000003140019000000000043004b000000000400003900000001040040390000023f0030009c0000055c0000213d00000001004001900000055c0000c13d000000400030043f000002150020009c000002150200804100000040022002100000000001010433000002150010009c00000215010080410000006001100210000000000121019f0000000002000414000002150020009c0000021502008041000000c002200210000000000112019f0000021b011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000025802000041000000000020043f0000001c0010043f0000000001000414000002150010009c0000021501008041000000c00110021000000259011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000200000001001d0000000501000029000000000010043f0000000201000039000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d0000000003000031000000000201043b00000006010000290000023f0010009c0000055c0000213d0000000901000029000000050110008a00000275011001970000003f011000390000027504100197000000400100043d0000000004410019000000000014004b000000000500003900000001050040390000023f0040009c0000055c0000213d00000001005001900000055c0000c13d00000007050000290000004406500039000000000202041a000700000002001d000000400040043f000000060400002900000000024104360000000004640019000000000034004b000005580000213d000000060500002900000275045001980000001f0550018f00000002066003670000000003420019000005190000613d000000000706034f0000000008020019000000007907043c0000000008980436000000000038004b000005150000c13d000000000005004b000005260000613d000000000446034f0000000305500210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f00000000004304350000000903100029000000040330008a0000000000030435000000400300043d0000000004010433000000410040008c000005a10000c13d000000400410003900000000040404330000025c0040009c000005aa0000a13d0000026e01000041000005a20000013d000002150010009c0000021501008041000000c001100210000000080000006b0000053a0000c13d00000009020000290000053f0000013d0000021b011001c70000800902000039000000080300002900000009040000290000000005000019084f08450000040f000700000002001d00030000000103550000006001100270000102150010019d0000021501100197000000000001004b0000055a0000c13d00000007010000290000000100100190000005620000613d0000000001000414000002150010009c0000021501008041000000c0011002100000021b011001c70000800d0200003900000004030000390000024604000041000000000500041100000009060000290000000807000029084f08450000040f0000000100200190000003030000c13d000000000100001900000851000104300000023f0010009c000005730000a13d0000026701000041000000000010043f0000004101000039000000040010043f0000025b010000410000085100010430000000400100043d00000044021000390000024403000041000000000032043500000024021000390000000f0300003900000000003204350000023b020000410000000000210435000000040210003900000020030000390000000000320435000002150010009c0000021501008041000000400110021000000245011001c700000851000104300000001f0310003900000275033001970000003f033000390000027504300197000000400300043d0000000004430019000000000034004b000000000500003900000001050040390000023f0040009c0000055c0000213d00000001005001900000055c0000c13d000000400040043f000000000513043600000275021001980000001f0310018f000000000125001900000003040003670000058c0000613d000000000604034f000000006706043c0000000005750436000000000015004b000005880000c13d000000000003004b000005470000613d000000000224034f0000000303300210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f0000000000210435000005470000013d000000400100043d00000044021000390000025403000041000000000032043500000024021000390000001503000039000005680000013d0000025a01000041000000000013043500000004013000390000000000410435000002150030009c000002150300804100000040013002100000025b011001c700000851000104300000006001100039000000000101043300000000020204330000006005300039000000000045043500000040043000390000000000240435000000f8011002700000002002300039000000000012043500000002010000290000000000130435000000000000043f000002150030009c000002150300804100000040013002100000000002000414000002150020009c0000021502008041000000c002200210000000000112019f0000025d011001c70000000102000039084f084a0000040f00000060031002700000021503300197000000200030008c000000200400003900000000040340190000001f0540018f0000002004400190000005d00000613d000000000601034f0000000007000019000000006806043c0000000007870436000000000047004b000005cc0000c13d000000000005004b000005dd0000613d000000000641034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000100000003001f00030000000103550000000100200190000005ec0000613d000000000100043d00000218011001980000060a0000c13d000000400100043d0000026c020000410000000000210435000002150010009c000002150100804100000040011002100000026d011001c700000851000104300000001f0530018f0000021706300198000000400200043d0000000004620019000005f70000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000005f30000c13d000000000005004b000006040000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000002150020009c00000215020080410000004002200210000000000112019f0000085100010430000000000010043f0000025e01000041000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000000101041a000000ff00100190000006210000c13d000000400100043d00000044021000390000026b03000041000000000032043500000024021000390000001103000039000005680000013d00000002010003670000004402100370000000000202043b0000006402200039000000000121034f000000000101043b00000008011000b9000000070010006c000006340000a13d000000400100043d00000064021000390000026903000041000000000032043500000044021000390000026a03000041000000000032043500000024021000390000002303000039000002c40000013d0000025f0100004100000000001004430000000001000414000002150010009c0000021501008041000000c00110021000000251011001c70000800b02000039084f084a0000040f0000000100200190000006b20000613d000000000101043b000000040010006b000006b30000413d000000030010006b000006b30000213d00000002010003670000004402100370000000000202043b0000006402200039000000000121034f000000000101043b00000008011000b900090007001000730000028a0000413d0000000501000029000000000010043f0000000201000039000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b0000000902000029000000000021041b00000002010003670000004402100370000000000202043b0000006402200039000000000121034f000000000101043b00000008021000b90000000301000039000000000301041a000000000223004b0000028a0000413d000000000021041b0000000201000029000000000010043f0000000401000039000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000005580000613d000000000101043b000000010200008a000000000021041b00000002010003670000004402100370000000000202043b0000006403200039000000000331034f000000000303043b00000008033000b9000000400400043d00000000003404350000002402200039000000000121034f000002150040009c0000021504008041000000000101043b00000040024002100000000003000414000002150030009c0000021503008041000000c003300210000000000223019f000002180610019700000260012001c70000800d020000390000000403000039000002610400004100000005050000290000000207000029084f08450000040f0000000100200190000005580000613d000000400300043d000000200100003900000000021304360000000201000029000700000002001d0000000000120435000900000003001d000002620030009c0000055c0000213d00000009010000290000004001100039000000400010043f00000002010003670000004402100370000000000202043b0000006402200039000000000121034f000000000101043b00000008031000b90000000001000414000002150010009c0000021501008041000000c001100210000000000003004b000006ba0000c13d0000800102000039000006be0000013d000000000001042f000000400100043d00000044021000390000026803000041000000000032043500000024021000390000001203000039000005680000013d0000021b011001c7000080090200003900008001040000390000000005000019084f08450000040f00030000000103550000006003100270000102150030019d0000021503300198000006e90000613d0000001f0430003900000216044001970000003f044000390000026304400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000023f0040009c0000055c0000213d00000001006001900000055c0000c13d000000400040043f0000001f0430018f000000000635043600000217053001980000000003560019000006dc0000613d000000000701034f000000007807043c0000000006860436000000000036004b000006d80000c13d000000000004004b000006e90000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000400100043d000002150010009c00000215030000410000000003014019000800000003001d0000000100200190000007080000613d0000002002100039000000400300003900000000003204350000026602000041000000000021043500000009020000290000000003020433000900000003001d0000004002100039000000000032043500000060021000390000000701000029084f071a0000040f00000009010000290000001f0110003900000275011001970000006001100039000002150010009c0000021501008041000000080200002900000040022002100000006001100210000000000121019f000008500001042e0000006402100039000002640300004100000000003204350000004402100039000002650300004100000000003204350000002402100039000000250300003900000000003204350000023b0200004100000000002104350000000401100039000000200200003900000000002104350000000801000029000000400110021000000249011001c70000085100010430000000000003004b000007240000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000034004b0000071d0000413d00000000012300190000000000010435000000000001042d0000001f03100039000000000023004b00000000040000190000024f040040410000024f052001970000024f03300197000000000653013f000000000053004b00000000030000190000024f030020410000024f0060009c000000000304c019000000000003004b0000073f0000613d0000000203100367000000000303043b0000023f0030009c0000073f0000213d00000020011000390000000004310019000000000024004b0000073f0000213d0000000002030019000000000001042d000000000100001900000851000104300001000000000002000100000001001d000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007600000613d000000000101043b0000000002000411000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007600000613d000000000101043b000000000101041a000000ff00100190000007620000613d000000000001042d00000000010000190000085100010430000000400100043d00000024021000390000000103000029000000000032043500000238020000410000000000210435000000040210003900000000030004110000000000320435000002150010009c0000021501008041000000400110021000000239011001c700000851000104300002000000000002000100000002001d000200000001001d000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007bd0000613d000000000101043b00000001020000290000021802200197000100000002001d000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007bd0000613d000000000101043b000000000101041a000000ff00100190000007bc0000613d0000000201000029000000000010043f000000200000043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007bd0000613d000000000101043b0000000102000029000000000020043f000000200010043f0000000001000414000002150010009c0000021501008041000000c0011002100000021a011001c70000801002000039084f084a0000040f0000000100200190000007bd0000613d000000000101043b000000000201041a0000027302200197000000000021041b0000000001000414000002150010009c0000021501008041000000c0011002100000021b011001c70000800d0200003900000004030000390000000007000411000002760400004100000002050000290000000106000029084f08450000040f0000000100200190000007bd0000613d000000000001042d00000000010000190000085100010430000000000302001900000000020004140000021804100197000000040040008c000007c90000c13d00000001020000390000000101000031000000000001004b000007da0000c13d000008020000013d000002150020009c0000021502008041000000c001200210000000000003004b000007d20000613d0000021b011001c700008009020000390000000005000019000007d30000013d0000000002040019084f08450000040f00030000000103550000006001100270000102150010019d0000021501100197000000000001004b000008020000613d000002770010009c000008050000813d0000001f0410003900000275044001970000003f044000390000027505400197000000400400043d0000000005540019000000000045004b000000000600003900000001060040390000023f0050009c000008050000213d0000000100600190000008050000c13d000000400050043f000000000614043600000275031001980000001f0410018f00000000013600190000000305000367000007f50000613d000000000705034f000000007807043c0000000006860436000000000016004b000007f10000c13d000000000004004b000008020000613d000000000335034f0000000304400210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f000000000031043500000001002001900000080b0000613d000000000001042d0000026701000041000000000010043f0000004101000039000000040010043f0000025b010000410000085100010430000000400100043d00000044021000390000024403000041000000000032043500000024021000390000000f0300003900000000003204350000023b020000410000000000210435000000040210003900000020030000390000000000320435000002150010009c0000021501008041000000400110021000000245011001c70000085100010430000000240520008c0000082d0000413d0000001e0210003900000002042003670000001802100039000000020220036700000004061000390000000203600367000000000303043b0000006006300270000000000202043b000000d002200270000000000304043b000000d00330027000000024041000390000000001060019000000000001042d00000000010000190000085100010430000000000001042f000002150010009c00000215010080410000004001100210000002150020009c00000215020080410000006002200210000000000112019f0000000002000414000002150020009c0000021502008041000000c002200210000000000112019f0000021b011001c70000801002000039084f084a0000040f0000000100200190000008430000613d000000000101043b000000000001042d0000000001000019000008510001043000000848002104210000000102000039000000000001042d0000000002000019000000000001042d0000084d002104230000000102000039000000000001042d0000000002000019000000000001042d0000084f00000432000008500001042e00000851000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5020000000000000000000000000000000000004000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d00000002000000000000000000000000000000400000010000000000000000000000000000000000000000000000000000000000000000000000000081e4d81c00000000000000000000000000000000000000000000000000000000aa67c91800000000000000000000000000000000000000000000000000000000d547741e00000000000000000000000000000000000000000000000000000000d547741f00000000000000000000000000000000000000000000000000000000f8b2cb4f00000000000000000000000000000000000000000000000000000000aa67c91900000000000000000000000000000000000000000000000000000000c05f832300000000000000000000000000000000000000000000000000000000a217fdde00000000000000000000000000000000000000000000000000000000a217fddf00000000000000000000000000000000000000000000000000000000a93b95e30000000000000000000000000000000000000000000000000000000081e4d81d0000000000000000000000000000000000000000000000000000000091d1485400000000000000000000000000000000000000000000000000000000248a9ca20000000000000000000000000000000000000000000000000000000036568abd0000000000000000000000000000000000000000000000000000000036568abe00000000000000000000000000000000000000000000000000000000817b17f000000000000000000000000000000000000000000000000000000000248a9ca3000000000000000000000000000000000000000000000000000000002f2ff15d0000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000038a24bc00000000000000000000000000000000000000000000000000000000205c287800000000000000000000000000000000000000200000008000000000000000005821928a037de2d307f1245c7ef10c651f659a2d16351a08696cf3f9fa4dad249cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f390200000200000000000000000000000000000024000000000000000000000000af0d3ae5661af50c10d4a5f8117fa3fc098b633d350de8cd751d260a50e3eb29e2517d3f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000001dbbf474736d6415d6a265fabee708fe6e988f6fd0c9d870ded36cab380898dd08c379a0000000000000000000000000000000000000000000000000000000006465706f7369742063616e206e6f74206265207a65726f0000000000000000000000000000000000000000000000000000000064000000800000000000000000696e76616c6964207061796d6173746572496400000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6697b2320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008000000000000000007472616e73666572206661696c656400000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000926a144b6fffc1d73f115b81af7ec66a7c12aed0ff73197c39a683753fc1d925636500000000000000000000000000000000000000000000000000000000000063616e206e6f74207769746864726177206d6f7265207468616e2062616c616e000000000000000000000000000000000000008400000000000000000000000063616e206e6f7420776974686472617720746f207a65726f20616464726573733ee5aeb5000000000000000000000000000000000000000000000000000000006f6e6c7920626f6f746c6f616465722063616e2063616c6c2074686973206d6574686f6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000080000000000000000000000000000000000000000000000000000000000000006ef25c3ab4fb9cba75ff1971e3f261040c39b067df172dd5185087fc5553a5b60200000200000000000000000000000000000004000000000000000000000000ffffffff000000000000000000000000000000000000000000000000000000008c5a344500000000000000000000000000000000000000000000000000000000666c6f77206973206e6f7420737570706f727465640000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffedf9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b000000000000000000000000000000000000000000000000fffffffffffffe1f19457468657265756d205369676e6564204d6573736167653a0a333200000000020000000000000000000000000000000000003c000000000000000000000000fce698f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a00000000000000000000000000000000000000080000000000000000000000000db8ccd0e71cbf52bceafef256d2658d12104739e125d9c49583283aa4b756454796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320200000000000000000000000000000000000020000000000000000000000000baf31b528b94d1f5c0cab08502c95b744b875281fbd536cf12aa7ccb59f6cd3d000000000000000000000000000000000000000000000000ffffffffffffffbf00000000000000000000000000000000000000000000000000000003ffffffe06f616465720000000000000000000000000000000000000000000000000000006661696c656420666565207472616e7366657220746f2074686520626f6f746c038a24bc000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000696e76616c69642074696d652072616e676500000000000000000000000000007249640000000000000000000000000000000000000000000000000000000000696e73756666696369656e742062616c616e6365206f66207061796d61737465696e76616c6964207369676e6174757265000000000000000000000000000000f645eedf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000d78bce0c0000000000000000000000000000000000000000000000000000000073686f7274207061796d617374657220696e707574000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff01ffc9a7000000000000000000000000000000000000000000000000000000007965db0b00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b00000000000000000000000000000000000000000000000100000000000000008173359d6eadb1bb8b1b9e621763051429627d39f4882163d888670ab05f0c2d
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a860b0c8187ae5eaf719a5d56334a53bcbade3d9
-----Decoded View---------------
Arg [0] : _admin (address): 0xA860b0C8187aE5EAF719A5d56334a53BCBade3D9
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a860b0c8187ae5eaf719a5d56334a53bcbade3d9
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.