Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60e06040 | 23397226 | 168 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Bridgehub
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 9999999 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {EnumerableMap} from "@openzeppelin/contracts-v4/utils/structs/EnumerableMap.sol";
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol";
import {IBridgehub, L2TransactionRequestDirect, L2TransactionRequestTwoBridgesInner, L2TransactionRequestTwoBridgesOuter} from "./IBridgehub.sol";
import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol";
import {IL1AssetRouter} from "../bridge/asset-router/IL1AssetRouter.sol";
import {IL1BaseTokenAssetHandler} from "../bridge/interfaces/IL1BaseTokenAssetHandler.sol";
import {IChainTypeManager} from "../state-transition/IChainTypeManager.sol";
import {ReentrancyGuard} from "../common/ReentrancyGuard.sol";
import {DataEncoding} from "../common/libraries/DataEncoding.sol";
import {IZKChain} from "../state-transition/chain-interfaces/IZKChain.sol";
import {BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS, ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER, TWO_BRIDGES_MAGIC_VALUE} from "../common/Config.sol";
import {BridgehubL2TransactionRequest, L2Log, L2Message, TxStatus} from "../common/Messaging.sol";
import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol";
import {IMessageRoot} from "./IMessageRoot.sol";
import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol";
import {AlreadyCurrentSL, ChainIdAlreadyPresent, ChainNotLegacy, ChainNotPresentInCTM, NotChainAssetHandler, NotCurrentSL, NotInGatewayMode, NotL1, NotRelayedSender, SLNotWhitelisted, SecondBridgeAddressTooLow} from "./L1BridgehubErrors.sol";
import {AssetHandlerNotRegistered, AssetIdAlreadyRegistered, AssetIdNotSupported, BridgeHubAlreadyRegistered, CTMAlreadyRegistered, CTMNotRegistered, ChainIdAlreadyExists, ChainIdCantBeCurrentChain, ChainIdMismatch, ChainIdNotRegistered, ChainIdTooBig, EmptyAssetId, IncorrectBridgeHubAddress, MigrationPaused, MsgValueMismatch, NoCTMForAssetId, SettlementLayersMustSettleOnL1, SharedBridgeNotSet, Unauthorized, WrongMagicValue, ZKChainLimitReached, ZeroAddress, ZeroChainId} from "../common/L1ContractErrors.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev The Bridgehub contract serves as the primary entry point for L1->L2 communication,
/// facilitating interactions between end user and bridges.
/// It also manages state transition managers, base tokens, and chain registrations.
contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, PausableUpgradeable {
using EnumerableMap for EnumerableMap.UintToAddressMap;
/// @notice the asset id of Eth. This is only used on L1.
bytes32 internal immutable ETH_TOKEN_ASSET_ID;
/// @notice The chain id of L1. This contract can be deployed on multiple layers, but this value is still equal to the
/// L1 that is at the most base layer.
uint256 public immutable L1_CHAIN_ID;
/// @notice The total number of ZK chains can be created/connected to this CTM.
/// This is the temporary security measure.
uint256 public immutable MAX_NUMBER_OF_ZK_CHAINS;
/// @notice all the ether and ERC20 tokens are held by NativeVaultToken managed by the asset router.
address public assetRouter;
/// @notice ChainTypeManagers that are registered, and ZKchains that use these CTMs can use this bridgehub as settlement layer.
mapping(address chainTypeManager => bool) public chainTypeManagerIsRegistered;
/// @notice we store registered tokens (for arbitrary base token)
mapping(address baseToken => bool) internal __DEPRECATED_tokenIsRegistered;
/// @notice chainID => ChainTypeManager contract address, CTM that is managing rules for a given ZKchain.
mapping(uint256 chainId => address) public chainTypeManager;
/// @notice chainID => baseToken contract address, token that is used as 'base token' by a given child chain.
// slither-disable-next-line uninitialized-state
mapping(uint256 chainId => address) internal __DEPRECATED_baseToken;
/// @dev used to manage non critical updates
address public admin;
/// @dev used to accept the admin role
address private pendingAdmin;
/// @notice The map from chainId => zkChain contract
EnumerableMap.UintToAddressMap internal zkChainMap;
/// @notice The contract that stores the cross-chain message root for each chain and the aggregated root.
/// @dev Note that the message root does not contain messages from the chain it is deployed on. It may
/// be added later on if needed.
IMessageRoot public override messageRoot;
/// @notice Mapping from chain id to encoding of the base token used for deposits / withdrawals
mapping(uint256 chainId => bytes32) public baseTokenAssetId;
/// @notice The deployment tracker for the state transition managers.
/// @dev The L1 address of the ctm deployer is provided.
ICTMDeploymentTracker public l1CtmDeployer;
/// @dev asset info used to identify chains in the Shared Bridge
mapping(bytes32 ctmAssetId => address ctmAddress) public ctmAssetIdToAddress;
/// @dev ctmAddress to ctmAssetId
mapping(address ctmAddress => bytes32 ctmAssetId) public ctmAssetIdFromAddress;
/// @dev used to indicate the currently active settlement layer for a given chainId
mapping(uint256 chainId => uint256 activeSettlementLayerChainId) public settlementLayer;
/// @notice shows whether the given chain can be used as a settlement layer.
/// @dev the Gateway will be one of the possible settlement layers. The L1 is also a settlement layer.
/// @dev Sync layer chain is expected to have .. as the base token.
mapping(uint256 chainId => bool isWhitelistedSettlementLayer) public whitelistedSettlementLayers;
/// @notice we store registered assetIds (for arbitrary base token)
mapping(bytes32 baseTokenAssetId => bool) public assetIdIsRegistered;
/// @notice used to pause the migrations of chains. Used for stopping migrations during upgrades.
bool public migrationPaused;
/// @notice the chain asset handler used for chain migration.
address public chainAssetHandler;
modifier onlyOwnerOrAdmin() {
if (msg.sender != admin && msg.sender != owner()) {
revert Unauthorized(msg.sender);
}
_;
}
modifier onlyL1() {
if (L1_CHAIN_ID != block.chainid) {
revert NotL1(L1_CHAIN_ID, block.chainid);
}
_;
}
modifier onlySettlementLayerRelayedSender() {
/// There is no sender for the wrapping, we use a virtual address.
if (msg.sender != SETTLEMENT_LAYER_RELAY_SENDER) {
revert NotRelayedSender(msg.sender, SETTLEMENT_LAYER_RELAY_SENDER);
}
_;
}
modifier whenMigrationsNotPaused() {
if (migrationPaused) {
revert MigrationPaused();
}
_;
}
modifier onlyChainAssetHandler() {
if (msg.sender != chainAssetHandler) {
revert NotChainAssetHandler(msg.sender, chainAssetHandler);
}
_;
}
/// @notice to avoid parity hack
constructor(uint256 _l1ChainId, address _owner, uint256 _maxNumberOfZKChains) reentrancyGuardInitializer {
_disableInitializers();
L1_CHAIN_ID = _l1ChainId;
MAX_NUMBER_OF_ZK_CHAINS = _maxNumberOfZKChains;
// Note that this assumes that the bridgehub only accepts transactions on chains with ETH base token only.
// This is indeed true, since the only methods where this immutable is used are the ones with `onlyL1` modifier.
// We will change this with interop.
ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, ETH_TOKEN_ADDRESS);
_transferOwnership(_owner);
_initializeInner();
}
/// @notice used to initialize the contract
/// @notice this contract is also deployed on L2 as a system contract there the owner and the related functions will not be used
/// @param _owner the owner of the contract
function initialize(address _owner) external reentrancyGuardInitializer onlyL1 {
_transferOwnership(_owner);
_initializeInner();
}
/// @notice Used to initialize the contract on L1
function initializeV2() external initializer onlyL1 {
_initializeInner();
}
/// @notice Initializes the contract
function _initializeInner() internal {
assetIdIsRegistered[ETH_TOKEN_ASSET_ID] = true;
whitelistedSettlementLayers[L1_CHAIN_ID] = true;
}
//// Initialization and registration
/// @inheritdoc IBridgehub
/// @dev Please note, if the owner wants to enforce the admin change it must execute both `setPendingAdmin` and
/// `acceptAdmin` atomically. Otherwise `admin` can set different pending admin and so fail to accept the admin rights.
function setPendingAdmin(address _newPendingAdmin) external onlyOwnerOrAdmin {
if (_newPendingAdmin == address(0)) {
revert ZeroAddress();
}
// Save previous value into the stack to put it into the event later
address oldPendingAdmin = pendingAdmin;
// Change pending admin
pendingAdmin = _newPendingAdmin;
emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);
}
/// @inheritdoc IBridgehub
function acceptAdmin() external {
address currentPendingAdmin = pendingAdmin;
// Only proposed by current admin address can claim the admin rights
if (msg.sender != currentPendingAdmin) {
revert Unauthorized(msg.sender);
}
address previousAdmin = admin;
admin = currentPendingAdmin;
delete pendingAdmin;
emit NewPendingAdmin(currentPendingAdmin, address(0));
emit NewAdmin(previousAdmin, currentPendingAdmin);
}
/// @notice To set the addresses of some of the ecosystem contracts, only Owner. Not done in initialize, as
/// the order of deployment is Bridgehub, other contracts, and then we call this.
/// @param _assetRouter the shared bridge address
/// @param _l1CtmDeployer the ctm deployment tracker address. Note, that the address of the L1 CTM deployer is provided.
/// @param _messageRoot the message root address
function setAddresses(
address _assetRouter,
ICTMDeploymentTracker _l1CtmDeployer,
IMessageRoot _messageRoot,
address _chainAssetHandler
) external onlyOwner {
assetRouter = _assetRouter;
l1CtmDeployer = _l1CtmDeployer;
messageRoot = _messageRoot;
chainAssetHandler = _chainAssetHandler;
}
/// @notice Used to set the chain asset handler address.
/// @dev Called during v29 upgrade.
/// @param _chainAssetHandler the chain asset handler address
function setChainAssetHandler(address _chainAssetHandler) external onlyOwner {
chainAssetHandler = _chainAssetHandler;
}
/// @notice Used to set the legacy chain data for the upgrade.
/// @param _chainId The chainId of the legacy chain we are migrating.
function registerLegacyChain(uint256 _chainId) external override onlyL1 {
address ctm = chainTypeManager[_chainId];
if (ctm == address(0)) {
revert ChainNotLegacy();
}
if (zkChainMap.contains(_chainId)) {
revert ChainIdAlreadyPresent();
}
// From now on, since `zkChainMap` did not contain the chain, we assume
// that the chain is a legacy chain in the process of migration, i.e.
// its stored `baseTokenAssetId`, etc.
address token = __DEPRECATED_baseToken[_chainId];
if (token == address(0)) {
revert ChainNotLegacy();
}
bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, token);
baseTokenAssetId[_chainId] = assetId;
assetIdIsRegistered[assetId] = true;
address chainAddress = IChainTypeManager(ctm).getZKChainLegacy(_chainId);
if (chainAddress == address(0)) {
revert ChainNotPresentInCTM();
}
_registerNewZKChain(_chainId, chainAddress, false);
messageRoot.addNewChain(_chainId);
settlementLayer[_chainId] = block.chainid;
}
//// Registry
/// @notice Chain Type Manager can be any contract with the appropriate interface/functionality
/// @param _chainTypeManager the state transition manager address to be added
function addChainTypeManager(address _chainTypeManager) external onlyOwner {
if (_chainTypeManager == address(0)) {
revert ZeroAddress();
}
if (chainTypeManagerIsRegistered[_chainTypeManager]) {
revert CTMAlreadyRegistered();
}
chainTypeManagerIsRegistered[_chainTypeManager] = true;
emit ChainTypeManagerAdded(_chainTypeManager);
}
/// @notice Chain Type Manager can be any contract with the appropriate interface/functionality
/// @notice this stops new Chains from using the CTM, old chains are not affected
/// @param _chainTypeManager the state transition manager address to be removed
function removeChainTypeManager(address _chainTypeManager) external onlyOwner {
if (_chainTypeManager == address(0)) {
revert ZeroAddress();
}
if (!chainTypeManagerIsRegistered[_chainTypeManager]) {
revert CTMNotRegistered();
}
chainTypeManagerIsRegistered[_chainTypeManager] = false;
emit ChainTypeManagerRemoved(_chainTypeManager);
}
/// @notice asset id can represent any token contract with the appropriate interface/functionality
/// @param _baseTokenAssetId asset id of base token to be registered
function addTokenAssetId(bytes32 _baseTokenAssetId) external onlyOwnerOrAdmin {
if (assetIdIsRegistered[_baseTokenAssetId]) {
revert AssetIdAlreadyRegistered();
}
assetIdIsRegistered[_baseTokenAssetId] = true;
emit BaseTokenAssetIdRegistered(_baseTokenAssetId);
}
/// @notice Used to register a chain as a settlement layer.
/// @param _newSettlementLayerChainId the chainId of the chain
/// @param _isWhitelisted whether the chain is a whitelisted settlement layer
function registerSettlementLayer(
uint256 _newSettlementLayerChainId,
bool _isWhitelisted
) external onlyOwner onlyL1 {
if (settlementLayer[_newSettlementLayerChainId] != block.chainid) {
revert SettlementLayersMustSettleOnL1();
}
whitelistedSettlementLayers[_newSettlementLayerChainId] = _isWhitelisted;
emit SettlementLayerRegistered(_newSettlementLayerChainId, _isWhitelisted);
}
/// @dev Used to set the assetAddress for a given assetInfo.
/// @param _additionalData the additional data to identify the asset
/// @param _assetAddress the asset handler address
function setCTMAssetAddress(bytes32 _additionalData, address _assetAddress) external {
// It is a simplified version of the logic used by the AssetRouter to manage asset handlers.
// CTM's assetId is `keccak256(abi.encode(L1_CHAIN_ID, l1CtmDeployer, ctmAddress))`.
// And the l1CtmDeployer is considered the deployment tracker for the CTM asset.
//
// The l1CtmDeployer will call this method to set the asset handler address for the assetId.
// If the chain is not the same as L1, we assume that it is done via L1->L2 communication and so we unalias the sender.
//
// For simpler handling we allow anyone to call this method. It is okay, since during bridging operations
// it is double checked that `assetId` is indeed derived from the `l1CtmDeployer`.
// TODO(EVM-703): This logic should be revised once interchain communication is implemented.
address sender = L1_CHAIN_ID == block.chainid ? msg.sender : AddressAliasHelper.undoL1ToL2Alias(msg.sender);
// This method can be accessed by l1CtmDeployer only
if (sender != address(l1CtmDeployer)) {
revert Unauthorized(sender);
}
if (!chainTypeManagerIsRegistered[_assetAddress]) {
revert CTMNotRegistered();
}
bytes32 ctmAssetId = DataEncoding.encodeAssetId(L1_CHAIN_ID, _additionalData, sender);
ctmAssetIdToAddress[ctmAssetId] = _assetAddress;
ctmAssetIdFromAddress[_assetAddress] = ctmAssetId;
emit AssetRegistered(ctmAssetId, _assetAddress, _additionalData, msg.sender);
}
/*//////////////////////////////////////////////////////////////
Chain Registration
//////////////////////////////////////////////////////////////*/
/// @notice register new chain. New chains can be only registered on Bridgehub deployed on L1. Later they can be moved to any other layer.
/// @notice for Eth the baseToken address is 1
/// @param _chainId the chainId of the chain
/// @param _chainTypeManager the state transition manager address
/// @param _baseTokenAssetId the base token asset id of the chain
/// @param _salt the salt for the chainId, currently not used
/// @param _admin the admin of the chain
/// @param _initData the fixed initialization data for the chain
/// @param _factoryDeps the factory dependencies for the chain's deployment
function createNewChain(
uint256 _chainId,
address _chainTypeManager,
bytes32 _baseTokenAssetId,
// solhint-disable-next-line no-unused-vars
uint256 _salt,
address _admin,
bytes calldata _initData,
bytes[] calldata _factoryDeps
) external onlyOwnerOrAdmin nonReentrant whenNotPaused onlyL1 returns (uint256) {
_validateChainParams({_chainId: _chainId, _assetId: _baseTokenAssetId, _chainTypeManager: _chainTypeManager});
chainTypeManager[_chainId] = _chainTypeManager;
baseTokenAssetId[_chainId] = _baseTokenAssetId;
settlementLayer[_chainId] = block.chainid;
address chainAddress = IChainTypeManager(_chainTypeManager).createNewChain({
_chainId: _chainId,
_baseTokenAssetId: _baseTokenAssetId,
_admin: _admin,
_initData: _initData,
_factoryDeps: _factoryDeps
});
_registerNewZKChain(_chainId, chainAddress, true);
messageRoot.addNewChain(_chainId);
emit NewChain(_chainId, _chainTypeManager, _admin);
return _chainId;
}
/// @notice This function is used to register a new zkChain in the system.
/// @notice see external counterpart for full natspec.
function _registerNewZKChain(uint256 _chainId, address _zkChain, bool _checkMaxNumberOfZKChains) internal {
// slither-disable-next-line unused-return
zkChainMap.set(_chainId, _zkChain);
if (_checkMaxNumberOfZKChains && zkChainMap.length() > MAX_NUMBER_OF_ZK_CHAINS) {
revert ZKChainLimitReached();
}
}
/*//////////////////////////////////////////////////////////////
Getters
//////////////////////////////////////////////////////////////*/
/// @notice baseToken function, which takes chainId as input, reads assetHandler from AR, and tokenAddress from AH
function baseToken(uint256 _chainId) public view returns (address) {
bytes32 baseTokenAssetId = baseTokenAssetId[_chainId];
address assetHandlerAddress = IAssetRouterBase(assetRouter).assetHandlerAddress(baseTokenAssetId);
// It is possible that the asset handler is not deployed for a chain on the current layer.
// In this case we throw an error.
if (assetHandlerAddress == address(0)) {
revert AssetHandlerNotRegistered(baseTokenAssetId);
}
return IL1BaseTokenAssetHandler(assetHandlerAddress).tokenAddress(baseTokenAssetId);
}
/// @notice Returns all the registered zkChain addresses
function getAllZKChains() public view override returns (address[] memory chainAddresses) {
uint256[] memory keys = zkChainMap.keys();
chainAddresses = new address[](keys.length);
uint256 keysLength = keys.length;
for (uint256 i = 0; i < keysLength; ++i) {
chainAddresses[i] = zkChainMap.get(keys[i]);
}
}
/// @notice Returns all the registered zkChain chainIDs
function getAllZKChainChainIDs() public view override returns (uint256[] memory) {
return zkChainMap.keys();
}
/// @notice Returns the address of the ZK chain with the corresponding chainID
/// @param _chainId the chainId of the chain
/// @return chainAddress the address of the ZK chain
function getZKChain(uint256 _chainId) public view override returns (address chainAddress) {
// slither-disable-next-line unused-return
(, chainAddress) = zkChainMap.tryGet(_chainId);
}
function ctmAssetIdFromChainId(uint256 _chainId) public view override returns (bytes32) {
address ctmAddress = chainTypeManager[_chainId];
if (ctmAddress == address(0)) {
revert ChainIdNotRegistered(_chainId);
}
return ctmAssetIdFromAddress[ctmAddress];
}
/*//////////////////////////////////////////////////////////////
Mailbox forwarder
//////////////////////////////////////////////////////////////*/
/// @notice the mailbox is called directly after the assetRouter received the deposit
/// this assumes that either ether is the base token or
/// the msg.sender has approved mintValue allowance for the nativeTokenVault.
/// This means this is not ideal for contract calls, as the contract would have to handle token allowance of the base Token.
/// In case allowance is provided to the Asset Router, then it will be transferred to NTV.
function requestL2TransactionDirect(
L2TransactionRequestDirect calldata _request
) external payable override nonReentrant whenNotPaused onlyL1 returns (bytes32 canonicalTxHash) {
// Note: If the ZK chain with corresponding `chainId` is not yet created,
// the transaction will revert on `bridgehubRequestL2Transaction` as call to zero address.
{
bytes32 tokenAssetId = baseTokenAssetId[_request.chainId];
if (tokenAssetId == ETH_TOKEN_ASSET_ID) {
if (msg.value != _request.mintValue) {
revert MsgValueMismatch(_request.mintValue, msg.value);
}
} else {
if (msg.value != 0) {
revert MsgValueMismatch(0, msg.value);
}
}
// slither-disable-next-line arbitrary-send-eth
IL1AssetRouter(assetRouter).bridgehubDepositBaseToken{value: msg.value}(
_request.chainId,
tokenAssetId,
msg.sender,
_request.mintValue
);
}
canonicalTxHash = _sendRequest(
_request.chainId,
_request.refundRecipient,
BridgehubL2TransactionRequest({
sender: msg.sender,
contractL2: _request.l2Contract,
mintValue: _request.mintValue,
l2Value: _request.l2Value,
l2Calldata: _request.l2Calldata,
l2GasLimit: _request.l2GasLimit,
l2GasPerPubdataByteLimit: _request.l2GasPerPubdataByteLimit,
factoryDeps: _request.factoryDeps,
refundRecipient: address(0)
})
);
}
/// @notice After depositing funds to the assetRouter, the secondBridge is called
/// to return the actual L2 message which is sent to the Mailbox.
/// This assumes that either ether is the base token or
/// the msg.sender has approved the nativeTokenVault with the mintValue,
/// and also the necessary approvals are given for the second bridge.
/// In case allowance is provided to the Shared Bridge, then it will be transferred to NTV.
/// @notice The logic of this bridge is to allow easy depositing for bridges.
/// Each contract that handles the users ERC20 tokens needs approvals from the user, this contract allows
/// the user to approve for each token only its respective bridge
/// @notice This function is great for contract calls to L2, the secondBridge can be any contract.
/// @param _request the request for the L2 transaction
function requestL2TransactionTwoBridges(
L2TransactionRequestTwoBridgesOuter calldata _request
) external payable override nonReentrant whenNotPaused onlyL1 returns (bytes32 canonicalTxHash) {
if (_request.secondBridgeAddress <= BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS) {
revert SecondBridgeAddressTooLow(_request.secondBridgeAddress, BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS);
}
{
bytes32 tokenAssetId = baseTokenAssetId[_request.chainId];
uint256 baseTokenMsgValue;
if (tokenAssetId == ETH_TOKEN_ASSET_ID) {
if (msg.value != _request.mintValue + _request.secondBridgeValue) {
revert MsgValueMismatch(_request.mintValue + _request.secondBridgeValue, msg.value);
}
baseTokenMsgValue = _request.mintValue;
} else {
if (msg.value != _request.secondBridgeValue) {
revert MsgValueMismatch(_request.secondBridgeValue, msg.value);
}
baseTokenMsgValue = 0;
}
// slither-disable-next-line arbitrary-send-eth
IL1AssetRouter(assetRouter).bridgehubDepositBaseToken{value: baseTokenMsgValue}(
_request.chainId,
tokenAssetId,
msg.sender,
_request.mintValue
);
}
// slither-disable-next-line arbitrary-send-eth
L2TransactionRequestTwoBridgesInner memory outputRequest = IL1AssetRouter(_request.secondBridgeAddress)
.bridgehubDeposit{value: _request.secondBridgeValue}(
_request.chainId,
msg.sender,
_request.l2Value,
_request.secondBridgeCalldata
);
if (outputRequest.magicValue != TWO_BRIDGES_MAGIC_VALUE) {
revert WrongMagicValue(uint256(TWO_BRIDGES_MAGIC_VALUE), uint256(outputRequest.magicValue));
}
canonicalTxHash = _sendRequest(
_request.chainId,
_request.refundRecipient,
BridgehubL2TransactionRequest({
sender: _request.secondBridgeAddress,
contractL2: outputRequest.l2Contract,
mintValue: _request.mintValue,
l2Value: _request.l2Value,
l2Calldata: outputRequest.l2Calldata,
l2GasLimit: _request.l2GasLimit,
l2GasPerPubdataByteLimit: _request.l2GasPerPubdataByteLimit,
factoryDeps: outputRequest.factoryDeps,
refundRecipient: address(0)
})
);
IL1AssetRouter(_request.secondBridgeAddress).bridgehubConfirmL2Transaction(
_request.chainId,
outputRequest.txDataHash,
canonicalTxHash
);
}
/// @notice This function is used to send a request to the ZK chain.
/// @param _chainId the chainId of the chain
/// @param _refundRecipient the refund recipient
/// @param _request the request
/// @return canonicalTxHash the canonical transaction hash
function _sendRequest(
uint256 _chainId,
address _refundRecipient,
BridgehubL2TransactionRequest memory _request
) internal returns (bytes32 canonicalTxHash) {
address refundRecipient = AddressAliasHelper.actualRefundRecipient(_refundRecipient, msg.sender);
_request.refundRecipient = refundRecipient;
address zkChain = zkChainMap.get(_chainId);
canonicalTxHash = IZKChain(zkChain).bridgehubRequestL2Transaction(_request);
}
/// @notice Used to forward a transaction on the gateway to the chains mailbox (from L1).
/// @param _chainId the chainId of the chain
/// @param _canonicalTxHash the canonical transaction hash
/// @param _expirationTimestamp the expiration timestamp for the transaction
function forwardTransactionOnGateway(
uint256 _chainId,
bytes32 _canonicalTxHash,
uint64 _expirationTimestamp
) external override onlySettlementLayerRelayedSender {
if (L1_CHAIN_ID == block.chainid) {
revert NotInGatewayMode();
}
address zkChain = zkChainMap.get(_chainId);
IZKChain(zkChain).bridgehubRequestL2TransactionOnGateway(_canonicalTxHash, _expirationTimestamp);
}
/// @notice forwards function call to Mailbox based on ChainId
/// @param _chainId The chain ID of the ZK chain where to prove L2 message inclusion.
/// @param _batchNumber The executed L2 batch number in which the message appeared
/// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message
/// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent
/// @param _proof Merkle proof for inclusion of L2 log that was sent with the message
/// @return Whether the proof is valid
function proveL2MessageInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view override returns (bool) {
address zkChain = zkChainMap.get(_chainId);
return IZKChain(zkChain).proveL2MessageInclusion(_batchNumber, _index, _message, _proof);
}
/// @notice forwards function call to Mailbox based on ChainId
/// @param _chainId The chain ID of the ZK chain where to prove L2 log inclusion.
/// @param _batchNumber The executed L2 batch number in which the log appeared
/// @param _index The position of the l2log in the L2 logs Merkle tree
/// @param _log Information about the sent log
/// @param _proof Merkle proof for inclusion of the L2 log
/// @return Whether the proof is correct and L2 log is included in batch
function proveL2LogInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Log calldata _log,
bytes32[] calldata _proof
) external view override returns (bool) {
address zkChain = zkChainMap.get(_chainId);
return IZKChain(zkChain).proveL2LogInclusion(_batchNumber, _index, _log, _proof);
}
/// @notice forwards function call to Mailbox based on ChainId
/// @param _chainId The chain ID of the ZK chain where to prove L1->L2 tx status.
/// @param _l2TxHash The L2 canonical transaction hash
/// @param _l2BatchNumber The L2 batch number where the transaction was processed
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent
/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction
/// @param _status The execution status of the L1 -> L2 transaction (true - success & 0 - fail)
/// @return Whether the proof is correct and the transaction was actually executed with provided status
/// NOTE: It may return `false` for incorrect proof, but it doesn't mean that the L1 -> L2 transaction has an opposite status!
function proveL1ToL2TransactionStatus(
uint256 _chainId,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view override returns (bool) {
address zkChain = zkChainMap.get(_chainId);
return
IZKChain(zkChain).proveL1ToL2TransactionStatus({
_l2TxHash: _l2TxHash,
_l2BatchNumber: _l2BatchNumber,
_l2MessageIndex: _l2MessageIndex,
_l2TxNumberInBatch: _l2TxNumberInBatch,
_merkleProof: _merkleProof,
_status: _status
});
}
/// @notice forwards function call to Mailbox based on ChainId
function l2TransactionBaseCost(
uint256 _chainId,
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256) {
address zkChain = zkChainMap.get(_chainId);
return IZKChain(zkChain).l2TransactionBaseCost(_gasPrice, _l2GasLimit, _l2GasPerPubdataByteLimit);
}
/*//////////////////////////////////////////////////////////////
Chain migration
//////////////////////////////////////////////////////////////*/
/// @notice IL1AssetHandler interface, used to migrate (transfer) a chain to the settlement layer.
/// @param _chainId The chain ID of the migrating chain.
/// @param _newSettlementLayerChainId The chain ID of the new settlement layer.
/// @return zkChain The address of the ZK chain.
/// @return ctm The address of the CTM of the chain.
function forwardedBridgeBurnSetSettlementLayer(
uint256 _chainId,
uint256 _newSettlementLayerChainId
) external onlyChainAssetHandler returns (address zkChain, address ctm) {
if (!whitelistedSettlementLayers[_newSettlementLayerChainId]) {
revert SLNotWhitelisted();
}
if (settlementLayer[_chainId] != block.chainid) {
revert NotCurrentSL(settlementLayer[_chainId], block.chainid);
}
settlementLayer[_chainId] = _newSettlementLayerChainId;
if (whitelistedSettlementLayers[_chainId]) {
revert SettlementLayersMustSettleOnL1();
}
zkChain = zkChainMap.get(_chainId);
ctm = chainTypeManager[_chainId];
}
/// @notice IL1AssetHandler interface, used to migrate (transfer) a chain to the settlement layer.
/// @param _assetId The asset ID of the chain.
/// @param _chainId The chain ID of the ZK chain.
/// @param _baseTokenAssetId The asset ID of the base token.
/// @return zkChain The address of the ZK chain.
/// @return ctm The address of the CTM of the chain.
function forwardedBridgeMint(
bytes32 _assetId,
uint256 _chainId,
bytes32 _baseTokenAssetId
) external onlyChainAssetHandler returns (address zkChain, address ctm) {
ctm = ctmAssetIdToAddress[_assetId];
if (ctm == address(0)) {
revert NoCTMForAssetId(_assetId);
}
if (settlementLayer[_chainId] == block.chainid) {
revert AlreadyCurrentSL(block.chainid);
}
settlementLayer[_chainId] = block.chainid;
chainTypeManager[_chainId] = ctm;
baseTokenAssetId[_chainId] = _baseTokenAssetId;
// To keep `assetIdIsRegistered` consistent, we'll also automatically register the base token.
// It is assumed that if the bridging happened, the token was approved on L1 already.
assetIdIsRegistered[_baseTokenAssetId] = true;
zkChain = getZKChain(_chainId);
}
/// @notice Used to recover a failed migration.
/// @param _chainId The chain ID of the chain.
/// @return zkChain The address of the ZK chain.
/// @return ctm The address of the CTM of the chain.
function forwardedBridgeRecoverFailedTransfer(
uint256 _chainId
) external onlyChainAssetHandler returns (address zkChain, address ctm) {
settlementLayer[_chainId] = block.chainid;
zkChain = getZKChain(_chainId);
ctm = chainTypeManager[_chainId];
}
/*////////////////////////////////////////////////////////////
Chain registration
//////////////////////////////////////////////////////////////*/
/// @notice This function is used to register a new zkChain in the system.
/// @param _chainId The chain ID of the ZK chain
/// @param _zkChain The address of the ZK chain's DiamondProxy contract.
/// @param _checkMaxNumberOfZKChains Whether to check that the limit for the number
/// of chains has not been crossed.
/// @dev Providing `_checkMaxNumberOfZKChains = false` may be preferable in cases
/// where we want to guarantee that a chain can be added. These include:
/// - Migration of a chain from the mapping in the old CTM
/// - Migration of a chain to a new settlement layer
function registerNewZKChain(
uint256 _chainId,
address _zkChain,
bool _checkMaxNumberOfZKChains
) public onlyChainAssetHandler {
_registerNewZKChain(_chainId, _zkChain, _checkMaxNumberOfZKChains);
}
/// @dev Registers an already deployed chain with the bridgehub
/// @param _chainId The chain Id of the chain
/// @param _zkChain Address of the zkChain
function registerAlreadyDeployedZKChain(uint256 _chainId, address _zkChain) external onlyOwner onlyL1 {
if (_zkChain == address(0)) {
revert ZeroAddress();
}
if (zkChainMap.contains(_chainId)) {
revert ChainIdAlreadyExists();
}
if (IZKChain(_zkChain).getChainId() != _chainId) {
revert ChainIdMismatch();
}
address ctm = IZKChain(_zkChain).getChainTypeManager();
address chainAdmin = IZKChain(_zkChain).getAdmin();
bytes32 chainBaseTokenAssetId = IZKChain(_zkChain).getBaseTokenAssetId();
address bridgeHub = IZKChain(_zkChain).getBridgehub();
if (bridgeHub != address(this)) {
revert IncorrectBridgeHubAddress(bridgeHub);
}
_validateChainParams({_chainId: _chainId, _assetId: chainBaseTokenAssetId, _chainTypeManager: ctm});
chainTypeManager[_chainId] = ctm;
baseTokenAssetId[_chainId] = chainBaseTokenAssetId;
settlementLayer[_chainId] = block.chainid;
_registerNewZKChain(_chainId, _zkChain, true);
messageRoot.addNewChain(_chainId);
emit NewChain(_chainId, ctm, chainAdmin);
}
function _validateChainParams(uint256 _chainId, bytes32 _assetId, address _chainTypeManager) internal view {
if (_chainId == 0) {
revert ZeroChainId();
}
if (_chainId > type(uint48).max) {
revert ChainIdTooBig();
}
if (_chainId == block.chainid) {
revert ChainIdCantBeCurrentChain();
}
if (_chainTypeManager == address(0)) {
revert ZeroAddress();
}
if (_assetId == bytes32(0)) {
revert EmptyAssetId();
}
if (!chainTypeManagerIsRegistered[_chainTypeManager]) {
revert CTMNotRegistered();
}
if (!assetIdIsRegistered[_assetId]) {
revert AssetIdNotSupported(_assetId);
}
if (assetRouter == address(0)) {
revert SharedBridgeNotSet();
}
if (chainTypeManager[_chainId] != address(0)) {
revert BridgeHubAlreadyRegistered();
}
}
/*//////////////////////////////////////////////////////////////
PAUSE
//////////////////////////////////////////////////////////////*/
/// @notice Pauses all functions marked with the `whenNotPaused` modifier.
function pause() external onlyOwner {
_pause();
}
/// @notice Unpauses the contract, allowing all functions marked with the `whenNotPaused` modifier to be called again.
function unpause() external onlyOwner {
_unpause();
}
/// @notice Pauses migration functions.
/// @dev Remove this with V30, the functionality was moved to the ChainAssetHandler in V29.
function pauseMigration() external onlyOwner {
migrationPaused = true;
}
/// @notice Unpauses migration functions.
function unpauseMigration() external onlyOwner {
migrationPaused = false;
}
/*//////////////////////////////////////////////////////////////
Legacy functions
//////////////////////////////////////////////////////////////*/
/// @notice return the ZK chain contract for a chainId
function getHyperchain(uint256 _chainId) public view returns (address) {
return getZKChain(_chainId);
}
/// @notice return the asset router
function sharedBridge() public view returns (address) {
return assetRouter;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// 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.21;
import {L2Log, L2Message, TxStatus} from "../common/Messaging.sol";
import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol";
import {IMessageRoot} from "./IMessageRoot.sol";
struct L2TransactionRequestDirect {
uint256 chainId;
uint256 mintValue;
address l2Contract;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
struct L2TransactionRequestTwoBridgesOuter {
uint256 chainId;
uint256 mintValue;
uint256 l2Value;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
address refundRecipient;
address secondBridgeAddress;
uint256 secondBridgeValue;
bytes secondBridgeCalldata;
}
struct L2TransactionRequestTwoBridgesInner {
bytes32 magicValue;
address l2Contract;
bytes l2Calldata;
bytes[] factoryDeps;
bytes32 txDataHash;
}
struct BridgehubMintCTMAssetData {
uint256 chainId;
bytes32 baseTokenAssetId;
bytes ctmData;
bytes chainData;
}
struct BridgehubBurnCTMAssetData {
uint256 chainId;
bytes ctmData;
bytes chainData;
}
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IBridgehub {
/// @notice pendingAdmin is changed
/// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
/// @notice Admin changed
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/// @notice CTM asset registered
event AssetRegistered(
bytes32 indexed assetInfo,
address indexed _assetAddress,
bytes32 indexed additionalData,
address sender
);
event SettlementLayerRegistered(uint256 indexed chainId, bool indexed isWhitelisted);
/// @notice Starts the transfer of admin rights. Only the current admin or owner can propose a new pending one.
/// @notice New admin can accept admin rights by calling `acceptAdmin` function.
/// @param _newPendingAdmin Address of the new admin
function setPendingAdmin(address _newPendingAdmin) external;
/// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
function acceptAdmin() external;
/// Getters
function chainTypeManagerIsRegistered(address _chainTypeManager) external view returns (bool);
function chainTypeManager(uint256 _chainId) external view returns (address);
function assetIdIsRegistered(bytes32 _baseTokenAssetId) external view returns (bool);
function baseToken(uint256 _chainId) external view returns (address);
function baseTokenAssetId(uint256 _chainId) external view returns (bytes32);
function messageRoot() external view returns (IMessageRoot);
function getZKChain(uint256 _chainId) external view returns (address);
function getAllZKChains() external view returns (address[] memory);
function getAllZKChainChainIDs() external view returns (uint256[] memory);
function migrationPaused() external view returns (bool);
function admin() external view returns (address);
function assetRouter() external view returns (address);
/// Mailbox forwarder
function proveL2MessageInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
function proveL2LogInclusion(
uint256 _chainId,
uint256 _batchNumber,
uint256 _index,
L2Log memory _log,
bytes32[] calldata _proof
) external view returns (bool);
function proveL1ToL2TransactionStatus(
uint256 _chainId,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view returns (bool);
function requestL2TransactionDirect(
L2TransactionRequestDirect calldata _request
) external payable returns (bytes32 canonicalTxHash);
function requestL2TransactionTwoBridges(
L2TransactionRequestTwoBridgesOuter calldata _request
) external payable returns (bytes32 canonicalTxHash);
function l2TransactionBaseCost(
uint256 _chainId,
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
//// Registry
function createNewChain(
uint256 _chainId,
address _chainTypeManager,
bytes32 _baseTokenAssetId,
uint256 _salt,
address _admin,
bytes calldata _initData,
bytes[] calldata _factoryDeps
) external returns (uint256 chainId);
function addChainTypeManager(address _chainTypeManager) external;
function removeChainTypeManager(address _chainTypeManager) external;
function addTokenAssetId(bytes32 _baseTokenAssetId) external;
function setAddresses(
address _sharedBridge,
ICTMDeploymentTracker _l1CtmDeployer,
IMessageRoot _messageRoot,
address _chainAssetHandler
) external;
function setChainAssetHandler(address _chainAssetHandler) external;
event NewChain(uint256 indexed chainId, address chainTypeManager, address indexed chainGovernance);
event ChainTypeManagerAdded(address indexed chainTypeManager);
event ChainTypeManagerRemoved(address indexed chainTypeManager);
event BaseTokenAssetIdRegistered(bytes32 indexed assetId);
function whitelistedSettlementLayers(uint256 _chainId) external view returns (bool);
function registerSettlementLayer(uint256 _newSettlementLayerChainId, bool _isWhitelisted) external;
function settlementLayer(uint256 _chainId) external view returns (uint256);
// function finalizeMigrationToGateway(
// uint256 _chainId,
// address _baseToken,
// address _sharedBridge,
// address _admin,
// uint256 _expectedProtocolVersion,
// ZKChainCommitment calldata _commitment,
// bytes calldata _diamondCut
// ) external;
function forwardTransactionOnGateway(
uint256 _chainId,
bytes32 _canonicalTxHash,
uint64 _expirationTimestamp
) external;
function ctmAssetIdFromChainId(uint256 _chainId) external view returns (bytes32);
function ctmAssetIdFromAddress(address _ctmAddress) external view returns (bytes32);
function l1CtmDeployer() external view returns (ICTMDeploymentTracker);
function ctmAssetIdToAddress(bytes32 _assetInfo) external view returns (address);
function setCTMAssetAddress(bytes32 _additionalData, address _assetAddress) external;
function L1_CHAIN_ID() external view returns (uint256);
function chainAssetHandler() external view returns (address);
function registerAlreadyDeployedZKChain(uint256 _chainId, address _hyperchain) external;
function registerLegacyChain(uint256 _chainId) external;
function pauseMigration() external;
function unpauseMigration() external;
function forwardedBridgeBurnSetSettlementLayer(
uint256 _chainId,
uint256 _newSettlementLayerChainId
) external returns (address zkChain, address ctm);
function forwardedBridgeMint(
bytes32 _assetId,
uint256 _chainId,
bytes32 _baseTokenAssetId
) external returns (address zkChain, address ctm);
function registerNewZKChain(uint256 _chainId, address _zkChain, bool _checkMaxNumberOfZKChains) external;
function forwardedBridgeRecoverFailedTransfer(uint256 _chainId) external returns (address zkChain, address ctm);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IBridgehub} from "../../bridgehub/IBridgehub.sol";
/// @dev The encoding version used for legacy txs.
bytes1 constant LEGACY_ENCODING_VERSION = 0x00;
/// @dev The encoding version used for new txs.
bytes1 constant NEW_ENCODING_VERSION = 0x01;
/// @dev The encoding version used for txs that set the asset handler on the counterpart contract.
bytes1 constant SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION = 0x02;
/// @title L1 Bridge contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IAssetRouterBase {
event BridgehubDepositBaseTokenInitiated(
uint256 indexed chainId,
address indexed from,
bytes32 assetId,
uint256 amount
);
event BridgehubDepositInitiated(
uint256 indexed chainId,
bytes32 indexed txDataHash,
address indexed from,
bytes32 assetId,
bytes bridgeMintCalldata
);
event BridgehubWithdrawalInitiated(
uint256 chainId,
address indexed sender,
bytes32 indexed assetId,
bytes32 assetDataHash // Todo: What's the point of emitting hash?
);
event AssetDeploymentTrackerRegistered(
bytes32 indexed assetId,
bytes32 indexed additionalData,
address assetDeploymentTracker
);
event AssetHandlerRegistered(bytes32 indexed assetId, address indexed _assetHandlerAddress);
event DepositFinalizedAssetRouter(uint256 indexed chainId, bytes32 indexed assetId, bytes assetData);
function BRIDGE_HUB() external view returns (IBridgehub);
function L1_CHAIN_ID() external view returns (uint256);
/// @notice Sets the asset handler address for a specified asset ID on the chain of the asset deployment tracker.
/// @dev The caller of this function is encoded within the `assetId`, therefore, it should be invoked by the asset deployment tracker contract.
/// @dev No access control on the caller, as msg.sender is encoded in the assetId.
/// @dev Typically, for most tokens, ADT is the native token vault. However, custom tokens may have their own specific asset deployment trackers.
/// @dev `setAssetHandlerAddressOnCounterpart` should be called on L1 to set asset handlers on L2 chains for a specific asset ID.
/// @param _assetRegistrationData The asset data which may include the asset address and any additional required data or encodings.
/// @param _assetHandlerAddress The address of the asset handler to be set for the provided asset.
function setAssetHandlerAddressThisChain(bytes32 _assetRegistrationData, address _assetHandlerAddress) external;
function assetHandlerAddress(bytes32 _assetId) external view returns (address);
/// @notice Finalize the withdrawal and release funds.
/// @param _chainId The chain ID of the transaction to check.
/// @param _assetId The bridged asset ID.
/// @param _transferData The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @dev We have both the legacy finalizeWithdrawal and the new finalizeDeposit functions,
/// finalizeDeposit uses the new format. On the L2 we have finalizeDeposit with new and old formats both.
function finalizeDeposit(uint256 _chainId, bytes32 _assetId, bytes memory _transferData) 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.21;
import {IL1Nullifier} from "../interfaces/IL1Nullifier.sol";
import {INativeTokenVault} from "../ntv/INativeTokenVault.sol";
import {IAssetRouterBase} from "./IAssetRouterBase.sol";
import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehub.sol";
import {IL1SharedBridgeLegacy} from "../interfaces/IL1SharedBridgeLegacy.sol";
import {IL1ERC20Bridge} from "../interfaces/IL1ERC20Bridge.sol";
/// @title L1 Bridge contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy {
event BridgehubMintData(bytes bridgeMintData);
event BridgehubDepositFinalized(
uint256 indexed chainId,
bytes32 indexed txDataHash,
bytes32 indexed l2DepositTxHash
);
event ClaimedFailedDepositAssetRouter(uint256 indexed chainId, bytes32 indexed assetId, bytes assetData);
event AssetDeploymentTrackerSet(
bytes32 indexed assetId,
address indexed assetDeploymentTracker,
bytes32 indexed additionalData
);
event LegacyDepositInitiated(
uint256 indexed chainId,
bytes32 indexed l2DepositTxHash,
address indexed from,
address to,
address l1Token,
uint256 amount
);
/// @notice Initiates a deposit by locking funds on the contract and sending the request
/// of processing an L2 transaction where tokens would be minted.
/// @dev If the token is bridged for the first time, the L2 token contract will be deployed. Note however, that the
/// newly-deployed token does not support any custom logic, i.e. rebase tokens' functionality is not supported.
/// @param _originalCaller The `msg.sender` address from the external call that initiated current one.
/// @param _l2Receiver The account address that should receive funds on L2.
/// @param _l1Token The L1 token address which is deposited.
/// @param _amount The total amount of tokens to be bridged.
/// @param _l2TxGasLimit The L2 gas limit to be used in the corresponding L2 transaction.
/// @param _l2TxGasPerPubdataByte The gasPerPubdataByteLimit to be used in the corresponding L2 transaction.
/// @param _refundRecipient The address on L2 that will receive the refund for the transaction.
/// @dev If the L2 deposit finalization transaction fails, the `_refundRecipient` will receive the `_l2Value`.
/// Please note, the contract may change the refund recipient's address to eliminate sending funds to addresses
/// out of control.
/// - If `_refundRecipient` is a contract on L1, the refund will be sent to the aliased `_refundRecipient`.
/// - If `_refundRecipient` is set to `address(0)` and the sender has NO deployed bytecode on L1, the refund will
/// be sent to the `msg.sender` address.
/// - If `_refundRecipient` is set to `address(0)` and the sender has deployed bytecode on L1, the refund will be
/// sent to the aliased `msg.sender` address.
/// @dev The address aliasing of L1 contracts as refund recipient on L2 is necessary to guarantee that the funds
/// are controllable through the Mailbox, since the Mailbox applies address aliasing to the from address for the
/// L2 tx if the L1 msg.sender is a contract. Without address aliasing for L1 contracts as refund recipients they
/// would not be able to make proper L2 tx requests through the Mailbox to use or withdraw the funds from L2, and
/// the funds would be lost.
/// @return txHash The L2 transaction hash of deposit finalization.
function depositLegacyErc20Bridge(
address _originalCaller,
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte,
address _refundRecipient
) external payable returns (bytes32 txHash);
function L1_NULLIFIER() external view returns (IL1Nullifier);
function L1_WETH_TOKEN() external view returns (address);
function ETH_TOKEN_ASSET_ID() external view returns (bytes32);
function nativeTokenVault() external view returns (INativeTokenVault);
function setAssetDeploymentTracker(bytes32 _assetRegistrationData, address _assetDeploymentTracker) external;
function setNativeTokenVault(INativeTokenVault _nativeTokenVault) external;
function setL1Erc20Bridge(IL1ERC20Bridge _legacyBridge) external;
/// @notice Withdraw funds from the initiated deposit, that failed when finalizing on L2.
/// @param _chainId The ZK chain id to which the deposit was initiated.
/// @param _depositSender The address of the entity that initiated the deposit.
/// @param _assetId The unique identifier of the deposited L1 token.
/// @param _assetData The encoded transfer data, which includes both the deposit amount and the address of the L2 receiver. Might include extra information.
/// @dev Processes claims of failed deposit, whether they originated from the legacy bridge or the current system.
function bridgeRecoverFailedTransfer(
uint256 _chainId,
address _depositSender,
bytes32 _assetId,
bytes calldata _assetData
) external;
/// @dev Withdraw funds from the initiated deposit, that failed when finalizing on L2.
/// @param _chainId The ZK chain id to which deposit was initiated.
/// @param _depositSender The address of the entity that initiated the deposit.
/// @param _assetId The unique identifier of the deposited L1 token.
/// @param _assetData The encoded transfer data, which includes both the deposit amount and the address of the L2 receiver. Might include extra information.
/// @param _l2TxHash The L2 transaction hash of the failed deposit finalization.
/// @param _l2BatchNumber The L2 batch number where the deposit finalization was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent.
/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction with deposit finalization.
/// @dev Processes claims of failed deposit, whether they originated from the legacy bridge or the current system.
function bridgeRecoverFailedTransfer(
uint256 _chainId,
address _depositSender,
bytes32 _assetId,
bytes memory _assetData,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
/// @notice Transfers funds to Native Token Vault, if the asset is registered with it. Does nothing for ETH or non-registered tokens.
/// @dev assetId is not the padded address, but the correct encoded id (NTV stores respective format for IDs)
/// @param _amount The asset amount to be transferred to native token vault.
/// @param _originalCaller The `msg.sender` address from the external call that initiated current one.
function transferFundsToNTV(bytes32 _assetId, uint256 _amount, address _originalCaller) external returns (bool);
/// @notice Finalize the withdrawal and release funds
/// @param _chainId The chain ID of the transaction to check
/// @param _l2BatchNumber The L2 batch number where the withdrawal was processed
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent
/// @param _message The L2 withdraw data, stored in an L2 -> L1 message
/// @param _merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization
function finalizeWithdrawal(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
/// @notice Initiates a transfer transaction within Bridgehub, used by `requestL2TransactionTwoBridges`.
/// @param _chainId The chain ID of the ZK chain to which deposit.
/// @param _originalCaller The `msg.sender` address from the external call that initiated current one.
/// @param _value The `msg.value` on the target chain tx.
/// @param _data The calldata for the second bridge deposit.
/// @return request The data used by the bridgehub to create L2 transaction request to specific ZK chain.
/// @dev Data has the following abi encoding for legacy deposits:
/// address _l1Token,
/// uint256 _amount,
/// address _l2Receiver
/// for new deposits:
/// bytes32 _assetId,
/// bytes _transferData
function bridgehubDeposit(
uint256 _chainId,
address _originalCaller,
uint256 _value,
bytes calldata _data
) external payable returns (L2TransactionRequestTwoBridgesInner memory request);
/// @notice Generates a calldata for calling the deposit finalization on the L2 native token contract.
// / @param _chainId The chain ID of the ZK chain to which deposit.
/// @param _sender The address of the deposit initiator.
/// @param _assetId The deposited asset ID.
/// @param _assetData The encoded data, which is used by the asset handler to determine L2 recipient and amount. Might include extra information.
/// @return Returns calldata used on ZK chain.
function getDepositCalldata(
address _sender,
bytes32 _assetId,
bytes memory _assetData
) external view returns (bytes memory);
/// @notice Allows bridgehub to acquire mintValue for L1->L2 transactions.
/// @dev If the corresponding L2 transaction fails, refunds are issued to a refund recipient on L2.
/// @param _chainId The chain ID of the ZK chain to which deposit.
/// @param _assetId The deposited asset ID.
/// @param _originalCaller The `msg.sender` address from the external call that initiated current one.
/// @param _amount The total amount of tokens to be bridged.
function bridgehubDepositBaseToken(
uint256 _chainId,
bytes32 _assetId,
address _originalCaller,
uint256 _amount
) external payable;
/// @notice Routes the confirmation to nullifier for backward compatibility.
/// @notice Confirms the acceptance of a transaction by the Mailbox, as part of the L2 transaction process within Bridgehub.
/// This function is utilized by `requestL2TransactionTwoBridges` to validate the execution of a transaction.
/// @param _chainId The chain ID of the ZK chain to which confirm the deposit.
/// @param _txDataHash The keccak256 hash of 0x01 || abi.encode(bytes32, bytes) to identify deposits.
/// @param _txHash The hash of the L1->L2 transaction to confirm the deposit.
function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external;
function isWithdrawalFinalized(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex
) external view returns (bool);
}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @title L1 Base Token Asset Handler contract interface /// @author Matter Labs /// @custom:security-contact [email protected] /// @notice Used for any asset handler and called by the L1AssetRouter interface IL1BaseTokenAssetHandler { /// @notice Used to get the token address of an assetId function tokenAddress(bytes32 _assetId) external view returns (address); }
// 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.21;
import {Diamond} from "./libraries/Diamond.sol";
import {L2CanonicalTransaction} from "../common/Messaging.sol";
import {FeeParams} from "./chain-deps/ZKChainStorage.sol";
// import {IBridgehub} from "../bridgehub/IBridgehub.sol";
/// @notice Struct that holds all data needed for initializing CTM Proxy.
/// @dev We use struct instead of raw parameters in `initialize` function to prevent "Stack too deep" error
/// @param owner The address who can manage non-critical updates in the contract
/// @param validatorTimelock The address that serves as consensus, i.e. can submit blocks to be processed
/// @param chainCreationParams The struct that contains the fields that define how a new chain should be created
/// @param protocolVersion The initial protocol version on the newly deployed chain
/// @param serverNotifier The address that serves as server notifier
// solhint-disable-next-line gas-struct-packing
struct ChainTypeManagerInitializeData {
address owner;
address validatorTimelock;
ChainCreationParams chainCreationParams;
uint256 protocolVersion;
address serverNotifier;
}
/// @notice The struct that contains the fields that define how a new chain should be created
/// within this CTM.
/// @param genesisUpgrade The address that is used in the diamond cut initialize address on chain creation
/// @param genesisBatchHash Batch hash of the genesis (initial) batch
/// @param genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for the genesis batch
/// @param genesisBatchCommitment The zk-proof commitment for the genesis batch
/// @param diamondCut The diamond cut for the first upgrade transaction on the newly deployed chain
// solhint-disable-next-line gas-struct-packing
struct ChainCreationParams {
address genesisUpgrade;
bytes32 genesisBatchHash;
uint64 genesisIndexRepeatedStorageChanges;
bytes32 genesisBatchCommitment;
Diamond.DiamondCutData diamondCut;
bytes forceDeploymentsData;
}
interface IChainTypeManager {
/// @dev Emitted when a new ZKChain is added
event NewZKChain(uint256 indexed _chainId, address indexed _zkChainContract);
/// @dev emitted when an chain registers and a GenesisUpgrade happens
event GenesisUpgrade(
address indexed _zkChain,
L2CanonicalTransaction _l2Transaction,
uint256 indexed _protocolVersion
);
/// @notice pendingAdmin is changed
/// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
/// @notice Admin changed
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/// @notice ValidatorTimelock changed
event NewValidatorTimelock(address indexed oldValidatorTimelock, address indexed newValidatorTimelock);
/// @notice ValidatorTimelockPostV29 changed
event NewValidatorTimelockPostV29(
address indexed oldValidatorTimelockPostV29,
address indexed newvalidatorTimelockPostV29
);
/// @notice ServerNotifier changed
event NewServerNotifier(address indexed oldServerNotifier, address indexed newServerNotifier);
/// @notice chain creation parameters changed
event NewChainCreationParams(
address genesisUpgrade,
bytes32 genesisBatchHash,
uint64 genesisIndexRepeatedStorageChanges,
bytes32 genesisBatchCommitment,
Diamond.DiamondCutData newInitialCut,
bytes32 newInitialCutHash,
bytes forceDeploymentsData,
bytes32 forceDeploymentHash
);
/// @notice New UpgradeCutHash
event NewUpgradeCutHash(uint256 indexed protocolVersion, bytes32 indexed upgradeCutHash);
/// @notice New UpgradeCutData
event NewUpgradeCutData(uint256 indexed protocolVersion, Diamond.DiamondCutData diamondCutData);
/// @notice New ProtocolVersion
event NewProtocolVersion(uint256 indexed oldProtocolVersion, uint256 indexed newProtocolVersion);
/// @notice Updated ProtocolVersion deadline
event UpdateProtocolVersionDeadline(uint256 indexed protocolVersion, uint256 deadline);
function BRIDGE_HUB() external view returns (address);
function setPendingAdmin(address _newPendingAdmin) external;
function acceptAdmin() external;
function getZKChain(uint256 _chainId) external view returns (address);
function getHyperchain(uint256 _chainId) external view returns (address);
function getZKChainLegacy(uint256 _chainId) external view returns (address);
function storedBatchZero() external view returns (bytes32);
function initialCutHash() external view returns (bytes32);
function l1GenesisUpgrade() external view returns (address);
function upgradeCutHash(uint256 _protocolVersion) external view returns (bytes32);
function protocolVersion() external view returns (uint256);
function protocolVersionDeadline(uint256 _protocolVersion) external view returns (uint256);
function protocolVersionIsActive(uint256 _protocolVersion) external view returns (bool);
function getProtocolVersion(uint256 _chainId) external view returns (uint256);
function initialize(ChainTypeManagerInitializeData calldata _initializeData) external;
function setLegacyValidatorTimelock(address _validatorTimelock) external;
function setValidatorTimelockPostV29(address _validatorTimelockPostV29) external;
function setChainCreationParams(ChainCreationParams calldata _chainCreationParams) external;
function getChainAdmin(uint256 _chainId) external view returns (address);
function createNewChain(
uint256 _chainId,
bytes32 _baseTokenAssetId,
address _admin,
bytes calldata _initData,
bytes[] calldata _factoryDeps
) external returns (address);
function setNewVersionUpgrade(
Diamond.DiamondCutData calldata _cutData,
uint256 _oldProtocolVersion,
uint256 _oldProtocolVersionDeadline,
uint256 _newProtocolVersion
) external;
function setUpgradeDiamondCut(Diamond.DiamondCutData calldata _cutData, uint256 _oldProtocolVersion) external;
function executeUpgrade(uint256 _chainId, Diamond.DiamondCutData calldata _diamondCut) external;
function setPriorityTxMaxGasLimit(uint256 _chainId, uint256 _maxGasLimit) external;
function freezeChain(uint256 _chainId) external;
function unfreezeChain(uint256 _chainId) external;
function setTokenMultiplier(uint256 _chainId, uint128 _nominator, uint128 _denominator) external;
function changeFeeParams(uint256 _chainId, FeeParams calldata _newFeeParams) external;
function setValidator(uint256 _chainId, address _validator, bool _active) external;
function setPorterAvailability(uint256 _chainId, bool _zkPorterIsAvailable) external;
function upgradeChainFromVersion(
uint256 _chainId,
uint256 _oldProtocolVersion,
Diamond.DiamondCutData calldata _diamondCut
) external;
function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
function forwardedBridgeBurn(
uint256 _chainId,
bytes calldata _data
) external returns (bytes memory _bridgeMintData);
function forwardedBridgeMint(uint256 _chainId, bytes calldata _data) external returns (address);
function forwardedBridgeRecoverFailedTransfer(
uint256 _chainId,
bytes32 _assetInfo,
address _depositSender,
bytes calldata _ctmData
) 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.21;
import {NotInitializedReentrancyGuard, Reentrancy, SlotOccupied} from "./L1ContractErrors.sol";
/**
* @custom:security-contact [email protected]
* @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].
*
* _Since v2.5.0:_ this module is now much more gas efficient, given net gas
* metering changes introduced in the Istanbul hardfork.
*/
abstract contract ReentrancyGuard {
/// @dev Address of lock flag variable.
/// @dev Flag is placed at random memory location to not interfere with Storage contract.
// keccak256("ReentrancyGuard") - 1;
uint256 private constant LOCK_FLAG_ADDRESS = 0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4;
// solhint-disable-next-line max-line-length
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/security/ReentrancyGuard.sol
// 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;
modifier reentrancyGuardInitializer() {
_initializeReentrancyGuard();
_;
}
function _initializeReentrancyGuard() private {
uint256 lockSlotOldValue;
// Storing an initial non-zero value makes deployment a bit more
// expensive but in exchange every call to nonReentrant
// will be cheaper.
assembly {
lockSlotOldValue := sload(LOCK_FLAG_ADDRESS)
sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
}
// Check that storage slot for reentrancy guard is empty to rule out possibility of slot conflict
if (lockSlotOldValue != 0) {
revert SlotOccupied();
}
}
/**
* @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 make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
uint256 _status;
assembly {
_status := sload(LOCK_FLAG_ADDRESS)
}
if (_status == 0) {
revert NotInitializedReentrancyGuard();
}
// On the first call to nonReentrant, _NOT_ENTERED will be true
if (_status != _NOT_ENTERED) {
revert Reentrancy();
}
// Any calls to nonReentrant after this point will fail
assembly {
sstore(LOCK_FLAG_ADDRESS, _ENTERED)
}
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
assembly {
sstore(LOCK_FLAG_ADDRESS, _NOT_ENTERED)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {L2_NATIVE_TOKEN_VAULT_ADDR} from "../l2-helpers/L2ContractAddresses.sol";
import {LEGACY_ENCODING_VERSION, NEW_ENCODING_VERSION} from "../../bridge/asset-router/IAssetRouterBase.sol";
import {INativeTokenVault} from "../../bridge/ntv/INativeTokenVault.sol";
import {IncorrectTokenAddressFromNTV, InvalidNTVBurnData, UnsupportedEncodingVersion} from "../L1ContractErrors.sol";
/**
* @author Matter Labs
* @custom:security-contact [email protected]
* @notice Helper library for transfer data encoding and decoding to reduce possibility of errors.
*/
library DataEncoding {
/// @notice Abi.encodes the data required for bridgeBurn for NativeTokenVault.
/// @param _amount The amount of token to be transferred.
/// @param _remoteReceiver The address which to receive tokens on remote chain.
/// @param _maybeTokenAddress The helper field that should be either equal to 0 (in this case
/// it is assumed that the token has been registered within NativeTokenVault already) or it
/// can be equal to the address of the token on the current chain. Providing non-zero address
/// allows it to be automatically registered in case it is not yet a part of NativeTokenVault.
/// @return The encoded bridgeBurn data
function encodeBridgeBurnData(
uint256 _amount,
address _remoteReceiver,
address _maybeTokenAddress
) internal pure returns (bytes memory) {
return abi.encode(_amount, _remoteReceiver, _maybeTokenAddress);
}
/// @notice Function decoding bridgeBurn data previously encoded with this library.
/// @param _data The encoded data for bridgeBurn
/// @return amount The amount of token to be transferred.
/// @return receiver The address which to receive tokens on remote chain.
/// @return maybeTokenAddress The helper field that should be either equal to 0 (in this case
/// it is assumed that the token has been registered within NativeTokenVault already) or it
/// can be equal to the address of the token on the current chain. Providing non-zero address
/// allows it to be automatically registered in case it is not yet a part of NativeTokenVault.
function decodeBridgeBurnData(
bytes memory _data
) internal pure returns (uint256 amount, address receiver, address maybeTokenAddress) {
if (_data.length != 96) {
// For better error handling
revert InvalidNTVBurnData();
}
(amount, receiver, maybeTokenAddress) = abi.decode(_data, (uint256, address, address));
}
/// @notice Abi.encodes the data required for bridgeMint on remote chain.
/// @param _originalCaller The address which initiated the transfer.
/// @param _remoteReceiver The address which to receive tokens on remote chain.
/// @param _originToken The transferred token address.
/// @param _amount The amount of token to be transferred.
/// @param _erc20Metadata The transferred token metadata.
/// @return The encoded bridgeMint data
function encodeBridgeMintData(
address _originalCaller,
address _remoteReceiver,
address _originToken,
uint256 _amount,
bytes memory _erc20Metadata
) internal pure returns (bytes memory) {
// solhint-disable-next-line func-named-parameters
return abi.encode(_originalCaller, _remoteReceiver, _originToken, _amount, _erc20Metadata);
}
/// @notice Function decoding transfer data previously encoded with this library.
/// @param _bridgeMintData The encoded bridgeMint data
/// @return _originalCaller The address which initiated the transfer.
/// @return _remoteReceiver The address which to receive tokens on remote chain.
/// @return _parsedOriginToken The transferred token address.
/// @return _amount The amount of token to be transferred.
/// @return _erc20Metadata The transferred token metadata.
function decodeBridgeMintData(
bytes memory _bridgeMintData
)
internal
pure
returns (
address _originalCaller,
address _remoteReceiver,
address _parsedOriginToken,
uint256 _amount,
bytes memory _erc20Metadata
)
{
(_originalCaller, _remoteReceiver, _parsedOriginToken, _amount, _erc20Metadata) = abi.decode(
_bridgeMintData,
(address, address, address, uint256, bytes)
);
}
/// @notice Encodes the asset data by combining chain id, asset deployment tracker and asset data.
/// @param _chainId The id of the chain token is native to.
/// @param _assetData The asset data that has to be encoded.
/// @param _sender The asset deployment tracker address.
/// @return The encoded asset data.
function encodeAssetId(uint256 _chainId, bytes32 _assetData, address _sender) internal pure returns (bytes32) {
return keccak256(abi.encode(_chainId, _sender, _assetData));
}
/// @notice Encodes the asset data by combining chain id, asset deployment tracker and asset data.
/// @param _chainId The id of the chain token is native to.
/// @param _tokenAddress The address of token that has to be encoded (asset data is the address itself).
/// @param _sender The asset deployment tracker address.
/// @return The encoded asset data.
function encodeAssetId(uint256 _chainId, address _tokenAddress, address _sender) internal pure returns (bytes32) {
return keccak256(abi.encode(_chainId, _sender, _tokenAddress));
}
/// @notice Encodes the asset data by combining chain id, NTV as asset deployment tracker and asset data.
/// @param _chainId The id of the chain token is native to.
/// @param _assetData The asset data that has to be encoded.
/// @return The encoded asset data.
function encodeNTVAssetId(uint256 _chainId, bytes32 _assetData) internal pure returns (bytes32) {
return keccak256(abi.encode(_chainId, L2_NATIVE_TOKEN_VAULT_ADDR, _assetData));
}
/// @notice Encodes the asset data by combining chain id, NTV as asset deployment tracker and token address.
/// @param _chainId The id of the chain token is native to.
/// @param _tokenAddress The address of token that has to be encoded (asset data is the address itself).
/// @return The encoded asset data.
function encodeNTVAssetId(uint256 _chainId, address _tokenAddress) internal pure returns (bytes32) {
return keccak256(abi.encode(_chainId, L2_NATIVE_TOKEN_VAULT_ADDR, _tokenAddress));
}
/// @dev Encodes the transaction data hash using either the latest encoding standard or the legacy standard.
/// @param _encodingVersion EncodingVersion.
/// @param _originalCaller The address of the entity that initiated the deposit.
/// @param _assetId The unique identifier of the deposited L1 token.
/// @param _nativeTokenVault The address of the token, only used if the encoding version is legacy.
/// @param _transferData The encoded transfer data, which includes the deposit amount, the address of the L2 receiver, and potentially the token address.
/// @return txDataHash The resulting encoded transaction data hash.
function encodeTxDataHash(
bytes1 _encodingVersion,
address _originalCaller,
bytes32 _assetId,
address _nativeTokenVault,
bytes memory _transferData
) internal view returns (bytes32 txDataHash) {
if (_encodingVersion == LEGACY_ENCODING_VERSION) {
address tokenAddress = INativeTokenVault(_nativeTokenVault).tokenAddress(_assetId);
// This is a double check to ensure that the used token for the legacy encoding is correct.
// This revert should never be emitted and in real life and should only serve as a guard in
// case of inconsistent state of Native Token Vault.
bytes32 expectedAssetId = encodeNTVAssetId(block.chainid, tokenAddress);
if (_assetId != expectedAssetId) {
revert IncorrectTokenAddressFromNTV(_assetId, tokenAddress);
}
(uint256 depositAmount, , ) = decodeBridgeBurnData(_transferData);
txDataHash = keccak256(abi.encode(_originalCaller, tokenAddress, depositAmount));
} else if (_encodingVersion == NEW_ENCODING_VERSION) {
// Similarly to calldata, the txDataHash is collision-resistant.
// In the legacy data hash, the first encoded variable was the address, which is padded with zeros during `abi.encode`.
txDataHash = keccak256(
bytes.concat(_encodingVersion, abi.encode(_originalCaller, _assetId, _transferData))
);
} else {
revert UnsupportedEncodingVersion();
}
}
/// @notice Decodes the token data by combining chain id, asset deployment tracker and asset data.
function decodeTokenData(
bytes calldata _tokenData
) internal pure returns (uint256 chainId, bytes memory name, bytes memory symbol, bytes memory decimals) {
bytes1 encodingVersion = _tokenData[0];
if (encodingVersion == LEGACY_ENCODING_VERSION) {
(name, symbol, decimals) = abi.decode(_tokenData, (bytes, bytes, bytes));
} else if (encodingVersion == NEW_ENCODING_VERSION) {
return abi.decode(_tokenData[1:], (uint256, bytes, bytes, bytes));
} else {
revert UnsupportedEncodingVersion();
}
}
/// @notice Encodes the token data by combining chain id, and its metadata.
/// @dev Note that all the metadata of the token is expected to be ABI encoded.
/// @param _chainId The id of the chain token is native to.
/// @param _name The name of the token.
/// @param _symbol The symbol of the token.
/// @param _decimals The decimals of the token.
/// @return The encoded token data.
function encodeTokenData(
uint256 _chainId,
bytes memory _name,
bytes memory _symbol,
bytes memory _decimals
) internal pure returns (bytes memory) {
return bytes.concat(NEW_ENCODING_VERSION, abi.encode(_chainId, _name, _symbol, _decimals));
}
}// 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.21;
import {IAdmin} from "./IAdmin.sol";
import {IExecutor} from "./IExecutor.sol";
import {IGetters} from "./IGetters.sol";
import {IMailbox} from "./IMailbox.sol";
import {Diamond} from "../libraries/Diamond.sol";
interface IZKChain is IAdmin, IExecutor, IGetters, IMailbox {
// We need this structure for the server for now
event ProposeTransparentUpgrade(
Diamond.DiamondCutData diamondCut,
uint256 indexed proposalId,
bytes32 proposalSalt
);
}// 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.21;
/// @dev `keccak256("")`
bytes32 constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
/// @dev Bytes in raw L2 log
/// @dev Equal to the bytes size of the tuple - (uint8 ShardId, bool isService, uint16 txNumberInBatch, address sender,
/// bytes32 key, bytes32 value)
uint256 constant L2_TO_L1_LOG_SERIALIZE_SIZE = 88;
/// @dev The maximum length of the bytes array with L2 -> L1 logs
uint256 constant MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES = 4 + L2_TO_L1_LOG_SERIALIZE_SIZE * 512;
/// @dev The value of default leaf hash for L2 -> 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;
bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0);
/// @dev Denotes the type of the ZKsync transaction that came from L1.
uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255;
/// @dev Denotes the type of the ZKsync transaction that is used for system upgrades.
uint256 constant SYSTEM_UPGRADE_L2_TX_TYPE = 254;
/// @dev The maximal allowed difference between protocol minor versions in an upgrade. The 100 gap is needed
/// in case a protocol version has been tested on testnet, but then not launched on mainnet, e.g.
/// due to a bug found.
/// We are allowed to jump at most 100 minor versions at a time. The major version is always expected to be 0.
uint256 constant MAX_ALLOWED_MINOR_VERSION_DELTA = 100;
/// @dev The amount of time in seconds the validator has to process the priority transaction
/// NOTE: The constant is set to zero for the Alpha release period
uint256 constant PRIORITY_EXPIRATION = 0 days;
// @dev The chainId of Ethereum Mainnet
uint256 constant MAINNET_CHAIN_ID = 1;
/// @dev Timestamp - seconds since unix epoch. This value will be used on the mainnet.
uint256 constant MAINNET_COMMIT_TIMESTAMP_NOT_OLDER = 3 days;
/// @dev Timestamp - seconds since unix epoch. This value will be used on testnets.
uint256 constant TESTNET_COMMIT_TIMESTAMP_NOT_OLDER = 30 days;
/// @dev Maximum available error between real commit batch timestamp and analog used in the verifier (in seconds)
/// @dev Must be used cause miner's `block.timestamp` value can differ on some small value (as we know - 12 seconds)
uint256 constant COMMIT_TIMESTAMP_APPROXIMATION_DELTA = 1 hours;
/// @dev Shift to apply to verify public input before verifying.
uint256 constant PUBLIC_INPUT_SHIFT = 32;
/// @dev The maximum number of L2 gas that a user can request for an L2 transaction
uint256 constant MAX_GAS_PER_TRANSACTION = 80_000_000;
/// @dev Even though the price for 1 byte of pubdata is 16 L1 gas, we have a slightly increased
/// value.
uint256 constant L1_GAS_PER_PUBDATA_BYTE = 17;
/// @dev The intrinsic cost of the L1->l2 transaction in computational L2 gas
uint256 constant L1_TX_INTRINSIC_L2_GAS = 167_157;
/// @dev The intrinsic cost of the L1->l2 transaction in pubdata
uint256 constant L1_TX_INTRINSIC_PUBDATA = 88;
/// @dev The minimal base price for L1 transaction
uint256 constant L1_TX_MIN_L2_GAS_BASE = 173_484;
/// @dev The number of L2 gas the transaction starts costing more with each 544 bytes of encoding
uint256 constant L1_TX_DELTA_544_ENCODING_BYTES = 1656;
/// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency
uint256 constant L1_TX_DELTA_FACTORY_DEPS_L2_GAS = 2473;
/// @dev The number of L2 gas an L1->L2 transaction gains with each new factory dependency
uint256 constant L1_TX_DELTA_FACTORY_DEPS_PUBDATA = 64;
/// @dev The number of pubdata an L1->L2 transaction requires with each new factory dependency
uint256 constant MAX_NEW_FACTORY_DEPS = 64;
/// @dev The L2 gasPricePerPubdata required to be used in bridges.
uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = 800;
/// @dev The mask which should be applied to the packed batch and L2 block timestamp in order
/// to obtain the L2 block timestamp. Applying this mask is equivalent to calculating modulo 2**128
uint256 constant PACKED_L2_BLOCK_TIMESTAMP_MASK = 0xffffffffffffffffffffffffffffffff;
/// @dev Address of the point evaluation precompile used for EIP-4844 blob verification.
address constant POINT_EVALUATION_PRECOMPILE_ADDR = address(0x0A);
/// @dev The overhead for a transaction slot in L2 gas.
/// It is roughly equal to 80kk/MAX_TRANSACTIONS_IN_BATCH, i.e. how many gas would an L1->L2 transaction
/// need to pay to compensate for the batch being closed.
/// @dev It is expected that the L1 contracts will enforce that the L2 gas price will be high enough to compensate
/// the operator in case the batch is closed because of tx slots filling up.
uint256 constant TX_SLOT_OVERHEAD_L2_GAS = 10000;
/// @dev The overhead for each byte of the bootloader memory that the encoding of the transaction.
/// It is roughly equal to 80kk/BOOTLOADER_MEMORY_FOR_TXS, i.e. how many gas would an L1->L2 transaction
/// need to pay to compensate for the batch being closed.
/// @dev It is expected that the L1 contracts will enforce that the L2 gas price will be high enough to compensate
/// the operator in case the batch is closed because of the memory for transactions being filled up.
uint256 constant MEMORY_OVERHEAD_GAS = 10;
/// @dev The maximum gas limit for a priority transaction in L2.
uint256 constant PRIORITY_TX_MAX_GAS_LIMIT = 72_000_000;
/// @dev the address used to identify eth as the base token for chains.
address constant ETH_TOKEN_ADDRESS = address(1);
/// @dev the value returned in bridgehubDeposit in the TwoBridges function.
bytes32 constant TWO_BRIDGES_MAGIC_VALUE = bytes32(uint256(keccak256("TWO_BRIDGES_MAGIC_VALUE")) - 1);
/// @dev https://eips.ethereum.org/EIPS/eip-1352
address constant BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS = address(uint160(type(uint16).max));
/// @dev the maximum number of supported chains, this is an arbitrary limit.
/// @dev Note, that in case of a malicious Bridgehub admin, the total number of chains
/// can be up to 2 times higher. This may be possible, in case the old ChainTypeManager
/// had `100` chains and these were migrated to the Bridgehub only after `MAX_NUMBER_OF_ZK_CHAINS`
/// were added to the bridgehub via creation of new chains.
uint256 constant MAX_NUMBER_OF_ZK_CHAINS = 100;
/// @dev Used as the `msg.sender` for transactions that relayed via a settlement layer.
address constant SETTLEMENT_LAYER_RELAY_SENDER = address(uint160(0x1111111111111111111111111111111111111111));
/// @dev The metadata version that is supported by the ZK Chains to prove that an L2->L1 log was included in a batch.
uint256 constant SUPPORTED_PROOF_METADATA_VERSION = 1;
/// @dev The virtual address of the L1 settlement layer.
address constant L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS = address(
uint160(uint256(keccak256("L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS")) - 1)
);
struct PriorityTreeCommitment {
uint256 nextLeafIndex;
uint256 startIndex;
uint256 unprocessedIndex;
bytes32[] sides;
}
// Info that allows to restore a chain.
struct ZKChainCommitment {
/// @notice Total number of executed batches i.e. batches[totalBatchesExecuted] points at the latest executed batch
/// (batch 0 is genesis)
uint256 totalBatchesExecuted;
/// @notice Total number of proved batches i.e. batches[totalBatchesProved] points at the latest proved batch
uint256 totalBatchesVerified;
/// @notice Total number of committed batches i.e. batches[totalBatchesCommitted] points at the latest committed
/// batch
uint256 totalBatchesCommitted;
/// @notice The hash of the L2 system contracts ugpgrade transaction.
/// @dev It is non zero if the migration happens while the upgrade is not yet finalized.
bytes32 l2SystemContractsUpgradeTxHash;
/// @notice The batch when the system contracts upgrade transaction was executed.
/// @dev It is non-zero if the migration happens while the batch where the upgrade tx was present
/// has not been finalized (executed) yet.
uint256 l2SystemContractsUpgradeBatchNumber;
/// @notice The hashes of the batches that are needed to keep the blockchain working.
/// @dev The length of the array is equal to the `totalBatchesCommitted - totalBatchesExecuted + 1`, i.e. we need
/// to store all the unexecuted batches' hashes + 1 latest executed one.
bytes32[] batchHashes;
/// @notice Commitment to the priority merkle tree.
PriorityTreeCommitment priorityTree;
/// @notice Whether a chain is a permanent rollup.
bool isPermanentRollup;
/// @notice The precommitment to the transactions of the latest batch.
bytes32 precommitmentForTheLatestBatch;
}
/// @dev Used as the `msg.sender` for system service transactions.
address constant SERVICE_TRANSACTION_SENDER = address(uint160(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF));
/// @dev To avoid higher costs the writes, we avoid making the slot zero.
/// This ensures that the cost of writes is always 5k and avoids the 20k initial write from the non-zero value.
bytes32 constant DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH = bytes32(uint256(1));
/// @dev The length of a packed transaction precommitment in bytes. It consists of two parts: 32-byte tx hash and 1-byte status (0 or 1).
uint256 constant PACKED_L2_PRECOMMITMENT_LENGTH = 33;// 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.21;
/// @dev The enum that represents the transaction execution status
/// @param Failure The transaction execution failed
/// @param Success The transaction execution succeeded
enum TxStatus {
Failure,
Success
}
/// @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 txNumberInBatch The L2 transaction number in a Batch, 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 L2Log {
uint8 l2ShardId;
bool isService;
uint16 txNumberInBatch;
address sender;
bytes32 key;
bytes32 value;
}
/// @dev An arbitrary length message passed from L2
/// @notice Under the hood it is `L2Log` sent from the special system L2 contract
/// @param txNumberInBatch The L2 transaction number in a Batch, in which the message was sent
/// @param sender The address of the L2 account from which the message was passed
/// @param data An arbitrary length message
struct L2Message {
uint16 txNumberInBatch;
address sender;
bytes data;
}
/// @dev Internal structure that contains the parameters for the writePriorityOp
/// internal function.
/// @param txId The id of the priority transaction.
/// @param l2GasPrice The gas price for the l2 priority operation.
/// @param expirationTimestamp The timestamp by which the priority operation must be processed by the operator.
/// @param request The external calldata request for the priority operation.
struct WritePriorityOpParams {
uint256 txId;
uint256 l2GasPrice;
uint64 expirationTimestamp;
BridgehubL2TransactionRequest request;
}
/// @dev Structure that includes all fields of the L2 transaction
/// @dev The hash of this structure is the "canonical L2 transaction hash" and can
/// be used as a unique identifier of a tx
/// @param txType The tx type number, depending on which the L2 transaction can be
/// interpreted differently
/// @param from The sender's address. `uint256` type for possible address format changes
/// and maintaining backward compatibility
/// @param to The recipient's address. `uint256` type for possible address format changes
/// and maintaining backward compatibility
/// @param gasLimit The L2 gas limit for L2 transaction. Analog to the `gasLimit` on an
/// L1 transactions
/// @param gasPerPubdataByteLimit Maximum number of L2 gas that will cost one byte of pubdata
/// (every piece of data that will be stored on L1 as calldata)
/// @param maxFeePerGas The absolute maximum sender willing to pay per unit of L2 gas to get
/// the transaction included in a Batch. Analog to the EIP-1559 `maxFeePerGas` on an L1 transactions
/// @param maxPriorityFeePerGas The additional fee that is paid directly to the validator
/// to incentivize them to include the transaction in a Batch. Analog to the EIP-1559
/// `maxPriorityFeePerGas` on an L1 transactions
/// @param paymaster The address of the EIP-4337 paymaster, that will pay fees for the
/// transaction. `uint256` type for possible address format changes and maintaining backward compatibility
/// @param nonce The nonce of the transaction. For L1->L2 transactions it is the priority
/// operation Id
/// @param value The value to pass with the transaction
/// @param reserved The fixed-length fields for usage in a future extension of transaction
/// formats
/// @param data The calldata that is transmitted for the transaction call
/// @param signature An abstract set of bytes that are used for transaction authorization
/// @param factoryDeps The set of L2 bytecode hashes whose preimages were shown on L1
/// @param paymasterInput The arbitrary-length data that is used as a calldata to the paymaster pre-call
/// @param reservedDynamic The arbitrary-length field for usage in a future extension of transaction formats
struct L2CanonicalTransaction {
uint256 txType;
uint256 from;
uint256 to;
uint256 gasLimit;
uint256 gasPerPubdataByteLimit;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
uint256 paymaster;
uint256 nonce;
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. 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;
bytes data;
bytes signature;
uint256[] factoryDeps;
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;
}
/// @param sender The sender's address.
/// @param contractAddressL2 The address of the contract on L2 to call.
/// @param valueToMint The amount of base token that should be minted on L2 as the result of this transaction.
/// @param l2Value The msg.value of the L2 transaction.
/// @param l2Calldata The calldata for the L2 transaction.
/// @param l2GasLimit The limit of the L2 gas for the L2 transaction
/// @param l2GasPerPubdataByteLimit The price for a single pubdata byte in L2 gas.
/// @param factoryDeps The array of L2 bytecodes that the tx depends on.
/// @param refundRecipient The recipient of the refund for the transaction on L2. If the transaction fails, then
/// this address will receive the `l2Value`.
// solhint-disable-next-line gas-struct-packing
struct BridgehubL2TransactionRequest {
address sender;
address contractL2;
uint256 mintValue;
uint256 l2Value;
bytes l2Calldata;
uint256 l2GasLimit;
uint256 l2GasPerPubdataByteLimit;
bytes[] factoryDeps;
address refundRecipient;
}
/// @dev The structure that contains the parameters for the message root
/// @param chainId The chain id of the dependency chain
/// @param blockOrBatchNumber The block number or the batch number where the message root was created
/// For proof based interop it is block number. For commit based interop it is batch number.
/// @param sides The sides of the dynamic incremental merkle tree emitted in the L2ToL1Messenger for precommit based interop
/// For proof and commit based interop, the sides contain a single root.
struct InteropRoot {
uint256 chainId;
uint256 blockOrBatchNumber;
// We are double overloading this. The sides of the dynamic incremental merkle tree normally contains the root, as well as the sides of the tree.
// Second overloading: if the length is 1, we are importing a chainBatchRoot/messageRoot instead of sides.
bytes32[] sides;
}// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 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.21;
library AddressAliasHelper {
uint160 private constant offset = uint160(0x1111000000000000000000000000000000001111);
/// @notice Utility function converts the address that submitted a tx
/// to the inbox on L1 to the msg.sender viewed on L2
/// @param l1Address the address in the L1 that triggered the tx to L2
/// @return l2Address L2 address as viewed in msg.sender
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + offset);
}
}
/// @notice Utility function that converts the msg.sender viewed on L2 to the
/// address that submitted a tx to the inbox on L1
/// @param l2Address L2 address as viewed in msg.sender
/// @return l1Address the address in the L1 that triggered the tx to L2
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
unchecked {
l1Address = address(uint160(l2Address) - offset);
}
}
/// @notice Utility function used to calculate the correct refund recipient
/// @param _refundRecipient the address that should receive the refund
/// @param _originalCaller the address that triggered the tx to L2
/// @return _recipient the corrected address that should receive the refund
function actualRefundRecipient(
address _refundRecipient,
address _originalCaller
) internal view returns (address _recipient) {
if (_refundRecipient == address(0)) {
// If the `_refundRecipient` is not provided, we use the `_originalCaller` as the recipient.
// solhint-disable avoid-tx-origin
// slither-disable-next-line tx-origin
_recipient = _originalCaller == tx.origin
? _originalCaller
: AddressAliasHelper.applyL1ToL2Alias(_originalCaller);
// solhint-enable avoid-tx-origin
} else if (_refundRecipient.code.length > 0) {
// If the `_refundRecipient` is a smart contract, we apply the L1 to L2 alias to prevent foot guns.
_recipient = AddressAliasHelper.applyL1ToL2Alias(_refundRecipient);
} else {
_recipient = _refundRecipient;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IBridgehub} from "./IBridgehub.sol";
/**
* @author Matter Labs
* @notice MessageRoot contract is responsible for storing and aggregating the roots of the batches from different chains into the MessageRoot.
* @custom:security-contact [email protected]
*/
interface IMessageRoot {
function BRIDGE_HUB() external view returns (IBridgehub);
function addNewChain(uint256 _chainId) external;
function addChainBatchRoot(uint256 _chainId, uint256 _batchNumber, bytes32 _chainBatchRoot) external;
function historicalRoot(uint256 _blockNumber) external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IBridgehub, L2TransactionRequestTwoBridgesInner} from "./IBridgehub.sol";
import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol";
import {IL1AssetDeploymentTracker} from "../bridge/interfaces/IL1AssetDeploymentTracker.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface ICTMDeploymentTracker is IL1AssetDeploymentTracker {
function bridgehubDeposit(
uint256 _chainId,
address _originalCaller,
uint256 _l2Value,
bytes calldata _data
) external payable returns (L2TransactionRequestTwoBridgesInner memory request);
function BRIDGE_HUB() external view returns (IBridgehub);
function L1_ASSET_ROUTER() external view returns (IAssetRouterBase);
function registerCTMAssetOnL1(address _ctmAddress) external;
function calculateAssetId(address _l1CTM) external view returns (bytes32);
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; // 0x587df426 error AlreadyCurrentSL(uint256 blockChainId); // 0x65e8a019 error ChainExists(); // 0xff514c10 error ChainIdAlreadyPresent(); // 0x5de72107 error ChainNotLegacy(); // 0x4bd4ae07 error ChainNotPresentInCTM(); // 0xeab895aa error HyperchainNotRegistered(); // 0x48857c1d error IncorrectChainAssetId(bytes32 assetId, bytes32 assetIdFromChainId); // 0xf5e39c1f error IncorrectSender(address prevMsgSender, address chainAdmin); // 0x913183d8 error MessageRootNotRegistered(); // 0x7f4316f3 error NoEthAllowed(); // 0xf306a770 error NotAssetRouter(address msgSender, address sharedBridge); // 0x8beee3a3 error NotChainAssetHandler(address sender, address chainAssetHandler); // 0xc0ca9182 error NotCurrentSL(uint256 settlementLayerChainId, uint256 blockChainId); // 0x472477e2 error NotInGatewayMode(); // 0xecb34449 error NotL1(uint256 l1ChainId, uint256 blockChainId); // 0x8eb4fc01 error NotL2(); // 0x23295f0e error NotOwner(address sender, address owner); // 0x693cd3dc error NotOwnerViaRouter(address msgSender, address originalCaller); // 0xa2ac02a0 error NotRelayedSender(address msgSender, address settlementLayerRelaySender); // 0x527b87c7 error OnlyBridgehub(address msgSender, address bridgehub); // 0x2d396674 error OnlyBridgehubOrChainAssetHandler(address sender, address bridgehub, address chainAssetHandler); // 0x73fe6c1b error OnlyChain(address msgSender, address zkChainAddress); // 0xb78dbaa7 error SecondBridgeAddressTooLow(address secondBridgeAddress, address minSecondBridgeAddress); // 0x90c7cbf1 error SLNotWhitelisted(); // 0x36917565 error SLHasDifferentCTM(); // 0x92626457 error WrongCounterPart(address addressOnCounterPart, address l2BridgehubAddress);
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
// 0x5ecf2d7a
error AccessToFallbackDenied(address target, address invoker);
// 0x3995f750
error AccessToFunctionDenied(address target, bytes4 selector, address invoker);
// 0x0dfb42bf
error AddressAlreadySet(address addr);
// 0x86bb51b8
error AddressHasNoCode(address);
// 0x1f73225f
error AddressMismatch(address expected, address supplied);
// 0x2a5989a0
error AlreadyPermanentRollup();
// 0x0bfcef28
error AlreadyWhitelisted(address);
// 0x5e85ae73
error AmountMustBeGreaterThanZero();
// 0xfde974f4
error AssetHandlerDoesNotExist(bytes32 assetId);
// 0x64107968
error AssetHandlerNotRegistered(bytes32 assetId);
// 0xfe919e28
error AssetIdAlreadyRegistered();
// 0x1294e9e1
error AssetIdMismatch(bytes32 expected, bytes32 supplied);
// 0x04a0b7e9
error AssetIdNotSupported(bytes32 assetId);
// 0x11832de8
error AssetRouterAllowanceNotZero();
// 0x6ef9a972
error BaseTokenGasPriceDenominatorNotSet();
// 0x55ad3fd3
error BatchHashMismatch(bytes32 expected, bytes32 actual);
// 0x2078a6a0
error BatchNotExecuted(uint256 batchNumber);
// 0xbd4455ff
error BatchNumberMismatch(uint256 expectedBatchNumber, uint256 providedBatchNumber);
// 0x6cf12312
error BridgeHubAlreadyRegistered();
// 0xdb538614
error BridgeMintNotImplemented();
// 0xaa5f6180
error BurningNativeWETHNotSupported();
// 0xccdd18d2
error BytecodeAlreadyPublished(bytes32 bytecodeHash);
// 0x25d8333c
error CallerNotTimerAdmin();
// 0x3331e9c0
error CallNotAllowed(bytes call);
// 0xe85392f9
error CanOnlyProcessOneBatch();
// 0x00c6ead2
error CantExecuteUnprovenBatches();
// 0xe18cb383
error CantRevertExecutedBatch();
// 0x78d2ed02
error ChainAlreadyLive();
// 0x24591d89
error ChainIdAlreadyExists();
// 0x717a1656
error ChainIdCantBeCurrentChain();
// 0xa179f8c9
error ChainIdMismatch();
// 0x23f3c357
error ChainIdNotRegistered(uint256 chainId);
// 0x8f620a06
error ChainIdTooBig();
// 0xec273439
error CTMAlreadyRegistered();
// 0xc630ef3c
error CTMNotRegistered();
// 0x907f8e51
error DeadlineNotYetPassed();
// 0xf2885eb3
error DefaultAdminTransferNotAllowed();
// 0xf7a01e4d
error DelegateCallFailed(bytes returnData);
// 0x0a8ed92c
error DenominatorIsZero();
// 0xb4f54111
error DeployFailed();
// 0x138ee1a3
error DeployingBridgedTokenForNativeToken();
// 0xc7c9660f
error DepositDoesNotExist();
// 0xad2fa98e
error DepositExists();
// 0x0e7ee319
error DiamondAlreadyFrozen();
// 0xa7151b9a
error DiamondNotFrozen();
// 0x7138356f
error EmptyAddress();
// 0x2d4d012f
error EmptyAssetId();
// 0x1c25715b
error EmptyBytes32();
// 0x99d8fec9
error EmptyData();
// 0x95b66fe9
error EmptyDeposit();
// 0x84286507
error EmptyPrecommitData(uint256 batchNumber);
// 0x456f8f7a
error EmptyProofLength();
// 0x627e0872
error ETHDepositNotSupported();
// 0xac4a3f98
error FacetExists(bytes4 selector, address);
// 0xc91cf3b1
error GasPerPubdataMismatch();
// 0x6d4a7df8
error GenesisBatchCommitmentZero();
// 0x7940c83f
error GenesisBatchHashZero();
// 0xb4fc6835
error GenesisIndexStorageZero();
// 0x3a1a8589
error GenesisUpgradeZero();
// 0xd356e6ba
error HashedLogIsDefault();
// 0x0b08d5be
error HashMismatch(bytes32 expected, bytes32 actual);
// 0xd7d93e1f
error IncorrectBatchBounds(
uint256 processFromExpected,
uint256 processToExpected,
uint256 processFromProvided,
uint256 processToProvided
);
// 0xdd381a4c
error IncorrectBridgeHubAddress(address bridgehub);
// 0x1929b7de
error IncorrectTokenAddressFromNTV(bytes32 assetId, address tokenAddress);
// 0x826fb11e
error InsufficientChainBalance();
// 0x9bf8b9aa
error InvalidBatchNumber(uint256 provided, uint256 expected);
// 0xcbd9d2e0
error InvalidCaller(address);
// 0x92daded2
error InvalidDAForPermanentRollup();
// 0x4fbe5dba
error InvalidDelay();
// 0xc1780bd6
error InvalidLogSender(address sender, uint256 logKey);
// 0xa1ec1876
error InvalidMessageRoot(bytes32 expectedMessageRoot, bytes32 providedMessageRoot);
// 0xde4c0b96
error InvalidNTVBurnData();
// 0xd8e9405c
error InvalidNumberOfBlobs(uint256 expected, uint256 numCommitments, uint256 numHashes);
// 0x99f6cc22
error InvalidPackedPrecommitmentLength(uint256 length);
// 0x09bde339
error InvalidProof();
// 0x48c5fa28
error InvalidProofLengthForFinalNode();
// 0x5428eae7
error InvalidProtocolVersion();
// 0x6f1cf752
error InvalidPubdataPricingMode();
// 0x12ba286f
error InvalidSelector(bytes4 func);
// 0xbe7193d4
error InvalidSystemLogsLength();
// 0x5f1aa154
error InvalidUpgradeTxn(UpgradeTxVerifyParam);
// 0xfb5c22e6
error L2TimestampTooBig();
// 0x97e1359e
error L2WithdrawalMessageWrongLength(uint256 messageLen);
// 0x8efef97a
error LegacyBridgeNotSet();
// 0x29963361
error LegacyBridgeUsesNonNativeToken();
// 0xfade089a
error LegacyEncodingUsedForNonL1Token();
// 0x767eed08
error LegacyMethodForNonL1Token();
// 0xe37d2c02
error LengthIsNotDivisibleBy32(uint256 length);
// 0x1b6825bb
error LogAlreadyProcessed(uint8);
// 0x43e266b0
error MalformedBytecode(BytecodeError);
// 0xafbb7a4e
error MerkleIndexOrHeightMismatch();
// 0x9bb54c35
error MerkleIndexOutOfBounds();
// 0xc33e6128
error MerkleNothingToProve();
// 0x8e23ac1a
error MerklePathEmpty();
// 0x09aa9830
error MerklePathLengthMismatch(uint256 pathLength, uint256 expectedLength);
// 0x1c500385
error MerklePathOutOfBounds();
// 0x1b582fcf
error MerkleWrongIndex(uint256 index, uint256 maxNodeNumber);
// 0x485cfcaa
error MerkleWrongLength(uint256 newLeavesLength, uint256 leafNumber);
// 0x3312a450
error MigrationPaused();
// 0x4e98b356
error MigrationsNotPaused();
// 0xfa44b527
error MissingSystemLogs(uint256 expected, uint256 actual);
// 0x4a094431
error MsgValueMismatch(uint256 expectedMsgValue, uint256 providedMsgValue);
// 0xb385a3da
error MsgValueTooLow(uint256 required, uint256 provided);
// 0x8b7e144a
error NewDeadlineExceedsMaxDeadline();
// 0x6eef58d1
error NewDeadlineNotGreaterThanCurrent();
// 0x79cc2d22
error NoCallsProvided();
// 0xce63ce17
error NoCTMForAssetId(bytes32 assetId);
// 0xa6fef710
error NoFunctionsForDiamondCut();
// 0xcab098d8
error NoFundsTransferred();
// 0xb20b58ce
error NoLegacySharedBridge();
// 0xc21b1ab7
error NonEmptyCalldata();
// 0x536ec84b
error NonEmptyMsgValue();
// 0xd018e08e
error NonIncreasingTimestamp();
// 0x0105f9c0
error NonSequentialBatch();
// 0x0ac76f01
error NonSequentialVersion();
// 0xfa5cd00f
error NotAllowed(address addr);
// 0x64846fe4
error NotARestriction(address addr);
// 0xb49df1f2
error NotAZKChain(address addr);
// 0xdd7e3621
error NotInitializedReentrancyGuard();
// 0xdf17e316
error NotWhitelisted(address);
// 0xf3ed9dfa
error OnlyEraSupported();
// 0x6c167909
error OnlySelfAllowed();
// 0x1a21feed
error OperationExists();
// 0xeda2fbb1
error OperationMustBePending();
// 0xe1c1ff37
error OperationMustBeReady();
// 0xb926450e
error OriginChainIdNotFound();
// 0x688c63e5
error PrecommitmentMismatch(uint256 batchNumber, bytes32 expected, bytes32 found);
// 0x9b48e060
error PreviousOperationNotExecuted();
// 0xd5a99014
error PriorityOperationsRollingHashMismatch();
// 0x1a4d284a
error PriorityTxPubdataExceedsMaxPubDataPerBatch();
// 0xa461f651
error ProtocolIdMismatch(uint256 expectedProtocolVersion, uint256 providedProtocolId);
// 0x64f94ec2
error ProtocolIdNotGreater();
// 0x959f26fb
error PubdataGreaterThanLimit(uint256 limit, uint256 length);
// 0x63c36549
error QueueIsEmpty();
// 0xab143c06
error Reentrancy();
// 0x667d17de
error RemoveFunctionFacetAddressNotZero(address facet);
// 0xa2d4b16c
error RemoveFunctionFacetAddressZero();
// 0xf6fd7071
error RemovingPermanentRestriction();
// 0x3580370c
error ReplaceFunctionFacetAddressZero();
// 0xf126e113
error RestrictionWasAlreadyPresent(address restriction);
// 0x52e22c98
error RestrictionWasNotPresent(address restriction);
// 0x9a67c1cb
error RevertedBatchNotAfterNewLastBatch();
// 0xfe0aa4f2
error RoleAccessDenied(address chainAddress, bytes32 role, address account);
// 0xd3b6535b
error SelectorsMustAllHaveSameFreezability();
// 0x02181a13
error SettlementLayersMustSettleOnL1();
// 0x856d5b77
error SharedBridgeNotSet();
// 0x7774d2f9
error SharedBridgeValueNotSet(SharedBridgeKey);
// 0xdf3a8fdd
error SlotOccupied();
// 0xae43b424
error SystemLogsSizeTooBig();
// 0x08753982
error TimeNotReached(uint256 expectedTimestamp, uint256 actualTimestamp);
// 0x7a4902ad
error TimerAlreadyStarted();
// 0x2d50c33b
error TimestampError();
// 0xa51fa558
error TokenIsLegacy();
// 0x1850b46b
error TokenNotLegacy();
// 0x06439c6b
error TokenNotSupported(address token);
// 0x23830e28
error TokensWithFeesNotSupported();
// 0x8e3ce3cb
error TooHighDeploymentNonce();
// 0x76da24b9
error TooManyFactoryDeps();
// 0xf0b4e88f
error TooMuchGas();
// 0x00c5a6a9
error TransactionNotAllowed();
// 0x4c991078
error TxHashMismatch();
// 0x2e311df8
error TxnBodyGasLimitNotEnoughGas();
// 0xfcb9b2e1
error UnallowedImplementation(bytes32 implementationHash);
// 0x8e4a23d6
error Unauthorized(address caller);
// 0xe52478c7
error UndefinedDiamondCutAction();
// 0x6aa39880
error UnexpectedSystemLog(uint256 logKey);
// 0xc352bb73
error UnknownVerifierType();
// 0xf3dd1b9c
error UnsupportedCommitBatchEncoding(uint8 version);
// 0x084a1449
error UnsupportedEncodingVersion();
// 0x14d2ed8a
error UnsupportedExecuteBatchEncoding(uint8 version);
// 0xf338f830
error UnsupportedProofBatchEncoding(uint8 version);
// 0xf093c2e5
error UpgradeBatchNumberIsNotZero();
// 0x47b3b145
error ValidateTxnNotEnoughGas();
// 0x626ade30
error ValueMismatch(uint256 expected, uint256 actual);
// 0xe1022469
error VerifiedBatchesExceedsCommittedBatches();
// 0xae899454
error WithdrawalAlreadyFinalized();
// 0x750b219c
error WithdrawFailed();
// 0xf20c5c2a
error WrappedBaseTokenAlreadyRegistered();
// 0x15e8e429
error WrongMagicValue(uint256 expectedMagicValue, uint256 providedMagicValue);
// 0xd92e233d
error ZeroAddress();
// 0xc84885d4
error ZeroChainId();
// 0x601b6882
error ZKChainLimitReached();
enum SharedBridgeKey {
PostUpgradeFirstBatch,
LegacyBridgeFirstBatch,
LegacyBridgeLastDepositBatch,
LegacyBridgeLastDepositTxn
}
enum BytecodeError {
Version,
NumberOfWords,
Length,
WordsMustBeOdd
}
enum UpgradeTxVerifyParam {
From,
To,
Paymaster,
Value,
MaxFeePerGas,
MaxPriorityFeePerGas,
Reserved0,
Reserved1,
Reserved2,
Reserved3,
Signature,
PaymasterInput,
ReservedDynamic
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IBridgehub} from "../../bridgehub/IBridgehub.sol";
import {IL1NativeTokenVault} from "../ntv/IL1NativeTokenVault.sol";
import {IL1ERC20Bridge} from "./IL1ERC20Bridge.sol";
/// @param chainId The chain ID of the transaction to check.
/// @param l2BatchNumber The L2 batch number where the withdrawal was processed.
/// @param l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param l2sender The address of the message sender on L2 (base token system contract address or asset handler)
/// @param l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent.
/// @param message The L2 withdraw data, stored in an L2 -> L1 message.
/// @param merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization.
struct FinalizeL1DepositParams {
uint256 chainId;
uint256 l2BatchNumber;
uint256 l2MessageIndex;
address l2Sender;
uint16 l2TxNumberInBatch;
bytes message;
bytes32[] merkleProof;
}
/// @title L1 Bridge contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IL1Nullifier {
event BridgehubDepositFinalized(
uint256 indexed chainId,
bytes32 indexed txDataHash,
bytes32 indexed l2DepositTxHash
);
function isWithdrawalFinalized(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex
) external view returns (bool);
function claimFailedDepositLegacyErc20Bridge(
address _depositSender,
address _l1Token,
uint256 _amount,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function claimFailedDeposit(
uint256 _chainId,
address _depositSender,
address _l1Token,
uint256 _amount,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function finalizeDeposit(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external;
function BRIDGE_HUB() external view returns (IBridgehub);
function legacyBridge() external view returns (IL1ERC20Bridge);
function depositHappened(uint256 _chainId, bytes32 _l2TxHash) external view returns (bytes32);
function bridgehubConfirmL2TransactionForwarded(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external;
function l1NativeTokenVault() external view returns (IL1NativeTokenVault);
function setL1NativeTokenVault(IL1NativeTokenVault _nativeTokenVault) external;
function setL1AssetRouter(address _l1AssetRouter) external;
function chainBalance(uint256 _chainId, address _token) external view returns (uint256);
function l2BridgeAddress(uint256 _chainId) external view returns (address);
function transferTokenToNTV(address _token) external;
function nullifyChainBalanceByNTV(uint256 _chainId, address _token) external;
/// @dev Withdraw funds from the initiated deposit, that failed when finalizing on L2.
/// @param _chainId The ZK chain id to which deposit was initiated.
/// @param _depositSender The address of the entity that initiated the deposit.
/// @param _assetId The unique identifier of the deposited L1 token.
/// @param _assetData The encoded transfer data, which includes both the deposit amount and the address of the L2 receiver. Might include extra information.
/// @param _l2TxHash The L2 transaction hash of the failed deposit finalization.
/// @param _l2BatchNumber The L2 batch number where the deposit finalization was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent.
/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction with deposit finalization.
/// @dev Processes claims of failed deposit, whether they originated from the legacy bridge or the current system.
function bridgeRecoverFailedTransfer(
uint256 _chainId,
address _depositSender,
bytes32 _assetId,
bytes memory _assetData,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
/// @notice Legacy function to finalize withdrawal via the same
/// interface as the old L1SharedBridge.
/// @dev Note, that we need to keep this interface, since the `L2AssetRouter`
/// will continue returning the previous address as the `l1SharedBridge`. The value
/// returned by it is used in the SDK for finalizing withdrawals.
/// @param _chainId The chain ID of the transaction to check
/// @param _l2BatchNumber The L2 batch number where the withdrawal was processed
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent
/// @param _message The L2 withdraw data, stored in an L2 -> L1 message
/// @param _merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization
function finalizeWithdrawal(
uint256 _chainId,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IAssetRouterBase} from "../asset-router/IAssetRouterBase.sol";
/// @title Base Native token vault contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice The NTV is an Asset Handler for the L1AssetRouter to handle native tokens
interface INativeTokenVault {
event BridgedTokenBeaconUpdated(address bridgedTokenBeacon, bytes32 bridgedTokenProxyBytecodeHash);
/// @notice The Weth token address
function WETH_TOKEN() external view returns (address);
/// @notice The AssetRouter contract
function ASSET_ROUTER() external view returns (IAssetRouterBase);
/// @notice The chain ID of the L1 chain
function L1_CHAIN_ID() external view returns (uint256);
/// @notice Returns the chain ID of the origin chain for a given asset ID
function originChainId(bytes32 assetId) external view returns (uint256);
/// @notice Registers tokens within the NTV.
/// @dev The goal is to allow bridging native tokens automatically, by registering them on the fly.
/// @notice Allows the bridge to register a token address for the vault.
/// @notice No access control is ok, since the bridging of tokens should be permissionless. This requires permissionless registration.
function registerToken(address _l1Token) external;
/// @notice Ensures that the native token is registered with the NTV.
/// @dev This function is used to ensure that the token is registered with the NTV.
function ensureTokenIsRegistered(address _nativeToken) external returns (bytes32);
/// @notice Used to get the the ERC20 data for a token
function getERC20Getters(address _token, uint256 _originChainId) external view returns (bytes memory);
/// @notice Used to get the token address of an assetId
function tokenAddress(bytes32 assetId) external view returns (address);
/// @notice Used to get the assetId of a token
function assetId(address token) external view returns (bytes32);
/// @notice Used to get the expected bridged token address corresponding to its native counterpart
function calculateCreate2TokenAddress(uint256 _originChainId, address _originToken) external view returns (address);
/// @notice Tries to register a token from the provided `_burnData` and reverts if it is not possible.
function tryRegisterTokenFromBurnData(bytes calldata _burnData, bytes32 _expectedAssetId) external;
}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @title L1 Bridge contract interface /// @author Matter Labs /// @custom:security-contact [email protected] interface IL1SharedBridgeLegacy { function l2BridgeAddress(uint256 _chainId) external view returns (address); }
// 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.21;
import {IL1Nullifier} from "./IL1Nullifier.sol";
import {IL1NativeTokenVault} from "../ntv/IL1NativeTokenVault.sol";
import {IL1AssetRouter} from "../asset-router/IL1AssetRouter.sol";
/// @title L1 Bridge contract legacy interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice Legacy Bridge interface before ZK chain migration, used for backward compatibility with ZKsync Era
interface IL1ERC20Bridge {
event DepositInitiated(
bytes32 indexed l2DepositTxHash,
address indexed from,
address indexed to,
address l1Token,
uint256 amount
);
event WithdrawalFinalized(address indexed to, address indexed l1Token, uint256 amount);
event ClaimedFailedDeposit(address indexed to, address indexed l1Token, uint256 amount);
function isWithdrawalFinalized(uint256 _l2BatchNumber, uint256 _l2MessageIndex) external view returns (bool);
function deposit(
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte,
address _refundRecipient
) external payable returns (bytes32 txHash);
function deposit(
address _l2Receiver,
address _l1Token,
uint256 _amount,
uint256 _l2TxGasLimit,
uint256 _l2TxGasPerPubdataByte
) external payable returns (bytes32 txHash);
function claimFailedDeposit(
address _depositSender,
address _l1Token,
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof
) external;
function finalizeWithdrawal(
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
function l2TokenAddress(address _l1Token) external view returns (address);
function L1_NULLIFIER() external view returns (IL1Nullifier);
function L1_ASSET_ROUTER() external view returns (IL1AssetRouter);
function L1_NATIVE_TOKEN_VAULT() external view returns (IL1NativeTokenVault);
function l2TokenBeacon() external view returns (address);
function l2Bridge() external view returns (address);
function depositAmount(
address _account,
address _l1Token,
bytes32 _depositL2TxHash
) external view returns (uint256 amount);
}// 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.21;
import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol";
import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
import {AddressHasNoCode, DelegateCallFailed, FacetExists, NoFunctionsForDiamondCut, NonEmptyCalldata, RemoveFunctionFacetAddressNotZero, RemoveFunctionFacetAddressZero, ReplaceFunctionFacetAddressZero, SelectorsMustAllHaveSameFreezability, UndefinedDiamondCutAction} from "../../common/L1ContractErrors.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice The helper library for managing the EIP-2535 diamond proxy.
library Diamond {
using UncheckedMath for uint256;
using SafeCast for uint256;
/// @dev Magic value that should be returned by diamond cut initialize contracts.
/// @dev Used to distinguish calls to contracts that were supposed to be used as diamond initializer from other contracts.
bytes32 internal constant DIAMOND_INIT_SUCCESS_RETURN_VALUE =
0x33774e659306e47509050e97cb651e731180a42d458212294d30751925c551a2; // keccak256("diamond.zksync.init") - 1
/// @dev Storage position of `DiamondStorage` structure.
bytes32 private constant DIAMOND_STORAGE_POSITION =
0xc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131b; // keccak256("diamond.standard.diamond.storage") - 1;
event DiamondCut(FacetCut[] facetCuts, address initAddress, bytes initCalldata);
/// @dev Utility struct that contains associated facet & meta information of selector
/// @param facetAddress address of the facet which is connected with selector
/// @param selectorPosition index in `FacetToSelectors.selectors` array, where is selector stored
/// @param isFreezable denotes whether the selector can be frozen.
struct SelectorToFacet {
address facetAddress;
uint16 selectorPosition;
bool isFreezable;
}
/// @dev Utility struct that contains associated selectors & meta information of facet
/// @param selectors list of all selectors that belong to the facet
/// @param facetPosition index in `DiamondStorage.facets` array, where is facet stored
struct FacetToSelectors {
bytes4[] selectors;
uint16 facetPosition;
}
/// @notice The structure that holds all diamond proxy associated parameters
/// @dev According to the EIP-2535 should be stored on a special storage key - `DIAMOND_STORAGE_POSITION`
/// @param selectorToFacet A mapping from the selector to the facet address and its meta information
/// @param facetToSelectors A mapping from facet address to its selectors with meta information
/// @param facets The array of all unique facet addresses that belong to the diamond proxy
/// @param isFrozen Denotes whether the diamond proxy is frozen and all freezable facets are not accessible
struct DiamondStorage {
mapping(bytes4 selector => SelectorToFacet selectorInfo) selectorToFacet;
mapping(address facetAddress => FacetToSelectors facetInfo) facetToSelectors;
address[] facets;
bool isFrozen;
}
/// @dev Parameters for diamond changes that touch one of the facets
/// @param facet The address of facet that's affected by the cut
/// @param action The action that is made on the facet
/// @param isFreezable Denotes whether the facet & all their selectors can be frozen
/// @param selectors An array of unique selectors that belongs to the facet address
// solhint-disable-next-line gas-struct-packing
struct FacetCut {
address facet;
Action action;
bool isFreezable;
bytes4[] selectors;
}
/// @dev Structure of the diamond proxy changes
/// @param facetCuts The set of changes (adding/removing/replacement) of implementation contracts
/// @param initAddress The address that's delegate called after setting up new facet changes
/// @param initCalldata Calldata for the delegate call to `initAddress`
struct DiamondCutData {
FacetCut[] facetCuts;
address initAddress;
bytes initCalldata;
}
/// @dev Type of change over diamond: add/replace/remove facets
enum Action {
Add,
Replace,
Remove
}
/// @return diamondStorage The pointer to the storage where all specific diamond proxy parameters stored
function getDiamondStorage() internal pure returns (DiamondStorage storage diamondStorage) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
diamondStorage.slot := position
}
}
/// @dev Add/replace/remove any number of selectors and optionally execute a function with delegatecall
/// @param _diamondCut Diamond's facet changes and the parameters to optional initialization delegatecall
function diamondCut(DiamondCutData memory _diamondCut) internal {
FacetCut[] memory facetCuts = _diamondCut.facetCuts;
address initAddress = _diamondCut.initAddress;
bytes memory initCalldata = _diamondCut.initCalldata;
uint256 facetCutsLength = facetCuts.length;
for (uint256 i = 0; i < facetCutsLength; i = i.uncheckedInc()) {
Action action = facetCuts[i].action;
address facet = facetCuts[i].facet;
bool isFacetFreezable = facetCuts[i].isFreezable;
bytes4[] memory selectors = facetCuts[i].selectors;
if (selectors.length == 0) {
revert NoFunctionsForDiamondCut();
}
if (action == Action.Add) {
_addFunctions(facet, selectors, isFacetFreezable);
} else if (action == Action.Replace) {
_replaceFunctions(facet, selectors, isFacetFreezable);
} else if (action == Action.Remove) {
_removeFunctions(facet, selectors);
} else {
revert UndefinedDiamondCutAction();
}
}
_initializeDiamondCut(initAddress, initCalldata);
emit DiamondCut(facetCuts, initAddress, initCalldata);
}
/// @dev Add new functions to the diamond proxy
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _addFunctions(address _facet, bytes4[] memory _selectors, bool _isFacetFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
// Facet with no code cannot be added.
// This check also verifies that the facet does not have zero address, since it is the
// address with which 0x00000000 selector is associated.
if (_facet.code.length == 0) {
revert AddressHasNoCode(_facet);
}
// Add facet to the list of facets if the facet address is new one
_saveFacetIfNew(_facet);
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
if (oldFacet.facetAddress != address(0)) {
revert FacetExists(selector, oldFacet.facetAddress);
}
_addOneFunction(_facet, selector, _isFacetFreezable);
}
}
/// @dev Change associated facets to already known function selectors
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _replaceFunctions(address _facet, bytes4[] memory _selectors, bool _isFacetFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
// Facet with no code cannot be added.
// This check also verifies that the facet does not have zero address, since it is the
// address with which 0x00000000 selector is associated.
if (_facet.code.length == 0) {
revert AddressHasNoCode(_facet);
}
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
// it is impossible to replace the facet with zero address
if (oldFacet.facetAddress == address(0)) {
revert ReplaceFunctionFacetAddressZero();
}
_removeOneFunction(oldFacet.facetAddress, selector);
// Add facet to the list of facets if the facet address is a new one
_saveFacetIfNew(_facet);
_addOneFunction(_facet, selector, _isFacetFreezable);
}
}
/// @dev Remove association with function and facet
/// NOTE: expect but NOT enforce that `_selectors` is NON-EMPTY array
function _removeFunctions(address _facet, bytes4[] memory _selectors) private {
DiamondStorage storage ds = getDiamondStorage();
// facet address must be zero
if (_facet != address(0)) {
revert RemoveFunctionFacetAddressNotZero(_facet);
}
uint256 selectorsLength = _selectors.length;
for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) {
bytes4 selector = _selectors[i];
SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
// Can't delete a non-existent facet
if (oldFacet.facetAddress == address(0)) {
revert RemoveFunctionFacetAddressZero();
}
_removeOneFunction(oldFacet.facetAddress, selector);
}
}
/// @dev Add address to the list of known facets if it is not on the list yet
/// NOTE: should be called ONLY before adding a new selector associated with the address
function _saveFacetIfNew(address _facet) private {
DiamondStorage storage ds = getDiamondStorage();
uint256 selectorsLength = ds.facetToSelectors[_facet].selectors.length;
// If there are no selectors associated with facet then save facet as new one
if (selectorsLength == 0) {
ds.facetToSelectors[_facet].facetPosition = ds.facets.length.toUint16();
ds.facets.push(_facet);
}
}
/// @dev Add one function to the already known facet
/// NOTE: It is expected but NOT enforced that:
/// - `_facet` is NON-ZERO address
/// - `_facet` is already stored address in `DiamondStorage.facets`
/// - `_selector` is NOT associated by another facet
function _addOneFunction(address _facet, bytes4 _selector, bool _isSelectorFreezable) private {
DiamondStorage storage ds = getDiamondStorage();
uint16 selectorPosition = (ds.facetToSelectors[_facet].selectors.length).toUint16();
// if selectorPosition is nonzero, it means it is not a new facet
// so the freezability of the first selector must be matched to _isSelectorFreezable
// so all the selectors in a facet will have the same freezability
if (selectorPosition != 0) {
bytes4 selector0 = ds.facetToSelectors[_facet].selectors[0];
if (_isSelectorFreezable != ds.selectorToFacet[selector0].isFreezable) {
revert SelectorsMustAllHaveSameFreezability();
}
}
ds.selectorToFacet[_selector] = SelectorToFacet({
facetAddress: _facet,
selectorPosition: selectorPosition,
isFreezable: _isSelectorFreezable
});
ds.facetToSelectors[_facet].selectors.push(_selector);
}
/// @dev Remove one associated function with facet
/// NOTE: It is expected but NOT enforced that `_facet` is NON-ZERO address
function _removeOneFunction(address _facet, bytes4 _selector) private {
DiamondStorage storage ds = getDiamondStorage();
// Get index of `FacetToSelectors.selectors` of the selector and last element of array
uint256 selectorPosition = ds.selectorToFacet[_selector].selectorPosition;
uint256 lastSelectorPosition = ds.facetToSelectors[_facet].selectors.length - 1;
// If the selector is not at the end of the array then move the last element to the selector position
if (selectorPosition != lastSelectorPosition) {
bytes4 lastSelector = ds.facetToSelectors[_facet].selectors[lastSelectorPosition];
ds.facetToSelectors[_facet].selectors[selectorPosition] = lastSelector;
ds.selectorToFacet[lastSelector].selectorPosition = selectorPosition.toUint16();
}
// Remove last element from the selectors array
ds.facetToSelectors[_facet].selectors.pop();
// Finally, clean up the association with facet
delete ds.selectorToFacet[_selector];
// If there are no selectors for facet then remove the facet from the list of known facets
if (lastSelectorPosition == 0) {
_removeFacet(_facet);
}
}
/// @dev remove facet from the list of known facets
/// NOTE: It is expected but NOT enforced that there are no selectors associated with `_facet`
function _removeFacet(address _facet) private {
DiamondStorage storage ds = getDiamondStorage();
// Get index of `DiamondStorage.facets` of the facet and last element of array
uint256 facetPosition = ds.facetToSelectors[_facet].facetPosition;
uint256 lastFacetPosition = ds.facets.length - 1;
// If the facet is not at the end of the array then move the last element to the facet position
if (facetPosition != lastFacetPosition) {
address lastFacet = ds.facets[lastFacetPosition];
ds.facets[facetPosition] = lastFacet;
ds.facetToSelectors[lastFacet].facetPosition = facetPosition.toUint16();
}
// Remove last element from the facets array
ds.facets.pop();
}
/// @dev Delegates call to the initialization address with provided calldata
/// @dev Used as a final step of diamond cut to execute the logic of the initialization for changed facets
function _initializeDiamondCut(address _init, bytes memory _calldata) private {
if (_init == address(0)) {
// Non-empty calldata for zero address
if (_calldata.length != 0) {
revert NonEmptyCalldata();
}
} else {
// Do not check whether `_init` is a contract since later we check that it returns data.
(bool success, bytes memory data) = _init.delegatecall(_calldata);
if (!success) {
// If the returndata is too small, we still want to produce some meaningful error
if (data.length < 4) {
revert DelegateCallFailed(data);
}
assembly {
revert(add(data, 0x20), mload(data))
}
}
// Check that called contract returns magic value to make sure that contract logic
// supposed to be used as diamond cut initializer.
if (data.length != 32) {
revert DelegateCallFailed(data);
}
if (abi.decode(data, (bytes32)) != DIAMOND_INIT_SUCCESS_RETURN_VALUE) {
revert DelegateCallFailed(data);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.sol";
import {PriorityTree} from "../../state-transition/libraries/PriorityTree.sol";
/// @notice Indicates whether an upgrade is initiated and if yes what type
/// @param None Upgrade is NOT initiated
/// @param Transparent Fully transparent upgrade is initiated, upgrade data is publicly known
/// @param Shadow Shadow upgrade is initiated, upgrade data is hidden
enum UpgradeState {
None,
Transparent,
Shadow
}
/// @dev Logically separated part of the storage structure, which is responsible for everything related to proxy
/// upgrades and diamond cuts
/// @param proposedUpgradeHash The hash of the current upgrade proposal, zero if there is no active proposal
/// @param state Indicates whether an upgrade is initiated and if yes what type
/// @param securityCouncil Address which has the permission to approve instant upgrades (expected to be a Gnosis
/// multisig)
/// @param approvedBySecurityCouncil Indicates whether the security council has approved the upgrade
/// @param proposedUpgradeTimestamp The timestamp when the upgrade was proposed, zero if there are no active proposals
/// @param currentProposalId The serial number of proposed upgrades, increments when proposing a new one
struct UpgradeStorage {
bytes32 proposedUpgradeHash;
UpgradeState state;
address securityCouncil;
bool approvedBySecurityCouncil;
uint40 proposedUpgradeTimestamp;
uint40 currentProposalId;
}
/// @notice The struct that describes whether users will be charged for pubdata for L1->L2 transactions.
/// @param Rollup The users are charged for pubdata & it is priced based on the gas price on Ethereum.
/// @param Validium The pubdata is considered free with regard to the L1 gas price.
enum PubdataPricingMode {
Rollup,
Validium
}
/// @notice The fee params for L1->L2 transactions for the network.
/// @param pubdataPricingMode How the users will charged for pubdata in L1->L2 transactions.
/// @param batchOverheadL1Gas The amount of L1 gas required to process the batch (except for the calldata).
/// @param maxPubdataPerBatch The maximal number of pubdata that can be emitted per batch.
/// @param priorityTxMaxPubdata The maximal amount of pubdata a priority transaction is allowed to publish.
/// It can be slightly less than maxPubdataPerBatch in order to have some margin for the bootloader execution.
/// @param minimalL2GasPrice The minimal L2 gas price to be used by L1->L2 transactions. It should represent
/// the price that a single unit of compute costs.
struct FeeParams {
PubdataPricingMode pubdataPricingMode;
uint32 batchOverheadL1Gas;
uint32 maxPubdataPerBatch;
uint32 maxL2GasPerBatch;
uint32 priorityTxMaxPubdata;
uint64 minimalL2GasPrice;
}
/// @dev storing all storage variables for ZK chain diamond facets
/// NOTE: It is used in a proxy, so it is possible to add new variables to the end
/// but NOT to modify already existing variables or change their order.
/// NOTE: variables prefixed with '__DEPRECATED_' are deprecated and shouldn't be used.
/// Their presence is maintained for compatibility and to prevent storage collision.
// solhint-disable-next-line gas-struct-packing
struct ZKChainStorage {
/// @dev Storage of variables needed for deprecated diamond cut facet
uint256[7] __DEPRECATED_diamondCutStorage;
/// @notice Address which will exercise critical changes to the Diamond Proxy (upgrades, freezing & unfreezing). Replaced by CTM
address __DEPRECATED_governor;
/// @notice Address that the governor proposed as one that will replace it
address __DEPRECATED_pendingGovernor;
/// @notice List of permitted validators
mapping(address validatorAddress => bool isValidator) validators;
/// @dev Verifier contract. Used to verify aggregated proof for batches
IVerifier verifier;
/// @notice Total number of executed batches i.e. batches[totalBatchesExecuted] points at the latest executed batch
/// (batch 0 is genesis)
uint256 totalBatchesExecuted;
/// @notice Total number of proved batches i.e. batches[totalBatchesProved] points at the latest proved batch
uint256 totalBatchesVerified;
/// @notice Total number of committed batches i.e. batches[totalBatchesCommitted] points at the latest committed
/// batch
uint256 totalBatchesCommitted;
/// @dev Stored hashed StoredBatch for batch number
mapping(uint256 batchNumber => bytes32 batchHash) storedBatchHashes;
/// @dev Stored root hashes of L2 -> L1 logs
mapping(uint256 batchNumber => bytes32 l2LogsRootHash) l2LogsRootHashes;
/// @dev Container that stores transactions requested from L1
PriorityQueue.Queue __DEPRECATED_priorityQueue;
/// @dev The smart contract that manages the list with permission to call contract functions
address __DEPRECATED_allowList;
VerifierParams __DEPRECATED_verifierParams;
/// @notice Bytecode hash of bootloader program.
/// @dev Used as an input to zkp-circuit.
bytes32 l2BootloaderBytecodeHash;
/// @notice Bytecode hash of default account (bytecode for EOA).
/// @dev Used as an input to zkp-circuit.
bytes32 l2DefaultAccountBytecodeHash;
/// @dev Indicates that the porter may be touched on L2 transactions.
/// @dev Used as an input to zkp-circuit.
bool zkPorterIsAvailable;
/// @dev The maximum number of the L2 gas that a user can request for L1 -> L2 transactions
/// @dev This is the maximum number of L2 gas that is available for the "body" of the transaction, i.e.
/// without overhead for proving the batch.
uint256 priorityTxMaxGasLimit;
/// @dev Storage of variables needed for upgrade facet
UpgradeStorage __DEPRECATED_upgrades;
/// @dev A mapping L2 batch number => message number => flag.
/// @dev The L2 -> L1 log is sent for every withdrawal, so this mapping is serving as
/// a flag to indicate that the message was already processed.
/// @dev Used to indicate that eth withdrawal was already processed
mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized)) isEthWithdrawalFinalized;
/// @dev The most recent withdrawal time and amount reset
uint256 __DEPRECATED_lastWithdrawalLimitReset;
/// @dev The accumulated withdrawn amount during the withdrawal limit window
uint256 __DEPRECATED_withdrawnAmountInWindow;
/// @dev A mapping user address => the total deposited amount by the user
mapping(address => uint256) __DEPRECATED_totalDepositedAmountPerUser;
/// @dev Stores the protocol version. Note, that the protocol version may not only encompass changes to the
/// smart contracts, but also to the node behavior.
uint256 protocolVersion;
/// @dev Hash of the system contract upgrade transaction. If 0, then no upgrade transaction needs to be done.
bytes32 l2SystemContractsUpgradeTxHash;
/// @dev Batch number where the upgrade transaction has happened. If 0, then no upgrade transaction has happened
/// yet.
uint256 l2SystemContractsUpgradeBatchNumber;
/// @dev Address which will exercise non-critical changes to the Diamond Proxy (changing validator set & unfreezing)
address admin;
/// @notice Address that the admin proposed as one that will replace admin role
address pendingAdmin;
/// @dev Fee params used to derive gasPrice for the L1->L2 transactions. For L2 transactions,
/// the bootloader gives enough freedom to the operator.
/// @dev The value is only for the L1 deployment of the ZK Chain, since payment for all the priority transactions is
/// charged at that level.
FeeParams feeParams;
/// @dev Address of the blob versioned hash getter smart contract used for EIP-4844 versioned hashes.
address __DEPRECATED_blobVersionedHashRetriever;
/// @dev The chainId of the chain
uint256 chainId;
/// @dev The address of the bridgehub
address bridgehub;
/// @dev The address of the ChainTypeManager
address chainTypeManager;
/// @dev The address of the baseToken contract. Eth is address(1)
address __DEPRECATED_baseToken;
/// @dev The address of the baseTokenbridge. Eth also uses the shared bridge
address __DEPRECATED_baseTokenBridge;
/// @notice gasPriceMultiplier for each baseToken, so that each L1->L2 transaction pays for its transaction on the destination
/// we multiply by the nominator, and divide by the denominator
uint128 baseTokenGasPriceMultiplierNominator;
uint128 baseTokenGasPriceMultiplierDenominator;
/// @dev The optional address of the contract that has to be used for transaction filtering/whitelisting
address transactionFilterer;
/// @dev The address of the l1DAValidator contract.
/// This contract is responsible for the verification of the correctness of the DA on L1.
address l1DAValidator;
/// @dev The address of the contract on L2 that is responsible for the data availability verification.
/// This contract sends `l2DAValidatorOutputHash` to L1 via L2->L1 system log and it will routed to the `l1DAValidator` contract.
address l2DAValidator;
/// @dev the Asset Id of the baseToken
bytes32 baseTokenAssetId;
/// @dev If this ZKchain settles on this chain, then this is zero. Otherwise it is the address of the ZKchain that is a
/// settlement layer for this ZKchain. (think about it as a 'forwarding' address for the chain that migrated away).
address settlementLayer;
/// @dev Priority tree, the new data structure for priority queue
PriorityTree.Tree priorityTree;
/// @dev Whether the chain is a permanent rollup. Note, that it only enforces the DA validator pair, but
/// it does not enforce any other parameters, e.g. `pubdataPricingMode`
bool isPermanentRollup;
/// @notice Bytecode hash of evm emulator.
/// @dev Used as an input to zkp-circuit.
bytes32 l2EvmEmulatorBytecodeHash;
/// @notice The precommitment for the latest uncommitted batch (i.e. totalBatchesCommitted + 1).
/// @dev Whenever the `totalBatchesCommitted` changes, this variable is reset to `DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH`
/// (the value of the constant can be found in Config.sol).
bytes32 precommitmentForTheLatestBatch;
}// 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.21;
import {IL2ToL1Messenger} from "./IL2ToL1Messenger.sol";
import {IL2InteropRootStorage} from "../interfaces/IL2InteropRootStorage.sol";
import {IMessageVerification} from "../../state-transition/chain-interfaces/IMessageVerification.sol";
/// @dev the offset for the system contracts
uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15
/// @dev The offset from which the built-in, but user space contracts are located.
uint160 constant USER_CONTRACTS_OFFSET = 0x10000; // 2^16
/// @dev The formal address of the initial program of the system: the bootloader
address constant L2_BOOTLOADER_ADDRESS = address(SYSTEM_CONTRACTS_OFFSET + 0x01);
/// @dev The address of the known code storage system contract
address constant L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x04);
/// @dev The address of the L2 deployer system contract.
address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x06);
/// @dev The special reserved L2 address. It is located in the system contracts space but doesn't have deployed
/// bytecode.
/// @dev The L2 deployer system contract allows changing bytecodes on any address if the `msg.sender` is this address.
/// @dev So, whenever the governor wants to redeploy system contracts, it just initiates the L1 upgrade call deployer
/// system contract
/// via the L1 -> L2 transaction with `sender == L2_FORCE_DEPLOYER_ADDR`. For more details see the
/// `diamond-initializers` contracts.
address constant L2_FORCE_DEPLOYER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x07);
/// @dev The address of the L2ToL1Messenger system contract
address constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x08);
/// @dev The address of the special smart contract that can send arbitrary length message as an L2 log
IL2ToL1Messenger constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT = IL2ToL1Messenger(
L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR
);
/// @dev The address of the eth token system contract
address constant L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0a);
/// @dev The address of the context system contract
address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0b);
/// @dev The address of the pubdata chunk publisher contract
address constant L2_PUBDATA_CHUNK_PUBLISHER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x11);
/// @dev The address used to execute complex upgragedes, also used for the genesis upgrade
address constant L2_COMPLEX_UPGRADER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0f);
/// @dev the address of the msg value system contract
address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09);
/// @dev The address of the create2 factory contract
address constant L2_CREATE2_FACTORY_ADDR = address(USER_CONTRACTS_OFFSET + 0x00);
/// @dev The address used to execute the genesis upgrade
address constant L2_GENESIS_UPGRADE_ADDR = address(USER_CONTRACTS_OFFSET + 0x01);
/// @dev The genesis upgrade address is reused for all version specific upgrades
address constant L2_VERSION_SPECIFIC_UPGRADER_ADDR = L2_GENESIS_UPGRADE_ADDR;
/// @dev The address of the L2 bridge hub system contract, used to start L1->L2 transactions
address constant L2_BRIDGEHUB_ADDR = address(USER_CONTRACTS_OFFSET + 0x02);
/// @dev the address of the l2 asset router.
address constant L2_ASSET_ROUTER_ADDR = address(USER_CONTRACTS_OFFSET + 0x03);
/// @dev An l2 system contract address, used in the assetId calculation for native assets.
/// This is needed for automatic bridging, i.e. without deploying the AssetHandler contract,
/// if the assetId can be calculated with this address then it is in fact an NTV asset
address constant L2_NATIVE_TOKEN_VAULT_ADDR = address(USER_CONTRACTS_OFFSET + 0x04);
/// @dev the address of the l2 asset router.
address constant L2_MESSAGE_ROOT_ADDR = address(USER_CONTRACTS_OFFSET + 0x05);
/// @dev The address of the SloadContract system contract, which provides a method to read values from arbitrary storage slots
address constant SLOAD_CONTRACT_ADDR = address(USER_CONTRACTS_OFFSET + 0x06);
/// @dev The address of the WETH implementation contract
address constant L2_WETH_IMPL_ADDR = address(USER_CONTRACTS_OFFSET + 0x07);
/// @dev The address of the L2 interop root storage system contract
IL2InteropRootStorage constant L2_INTEROP_ROOT_STORAGE = IL2InteropRootStorage(address(USER_CONTRACTS_OFFSET + 0x08));
/// @dev The address of the L2 message verification system contract
IMessageVerification constant L2_MESSAGE_VERIFICATION = IMessageVerification(address(USER_CONTRACTS_OFFSET + 0x09));
/// @dev The address of the L2 chain handler system contract
address constant L2_CHAIN_ASSET_HANDLER_ADDR = address(USER_CONTRACTS_OFFSET + 0x0a);// 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.21;
import {IZKChainBase} from "../chain-interfaces/IZKChainBase.sol";
import {Diamond} from "../libraries/Diamond.sol";
import {FeeParams, PubdataPricingMode} from "../chain-deps/ZKChainStorage.sol";
import {ZKChainCommitment} from "../../common/Config.sol";
/// @title The interface of the Admin Contract that controls access rights for contract management.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IAdmin is IZKChainBase {
/// @notice Starts the transfer of admin rights. Only the current admin can propose a new pending one.
/// @notice New admin can accept admin rights by calling `acceptAdmin` function.
/// @param _newPendingAdmin Address of the new admin
function setPendingAdmin(address _newPendingAdmin) external;
/// @notice Accepts transfer of admin rights. Only pending admin can accept the role.
function acceptAdmin() external;
/// @notice Change validator status (active or not active)
/// @param _validator Validator address
/// @param _active Active flag
function setValidator(address _validator, bool _active) external;
/// @notice Change zk porter availability
/// @param _zkPorterIsAvailable The availability of zk porter shard
function setPorterAvailability(bool _zkPorterIsAvailable) external;
/// @notice Change the max L2 gas limit for L1 -> L2 transactions
/// @param _newPriorityTxMaxGasLimit The maximum number of L2 gas that a user can request for L1 -> L2 transactions
function setPriorityTxMaxGasLimit(uint256 _newPriorityTxMaxGasLimit) external;
/// @notice Change the fee params for L1->L2 transactions
/// @param _newFeeParams The new fee params
function changeFeeParams(FeeParams calldata _newFeeParams) external;
/// @notice Change the token multiplier for L1->L2 transactions
function setTokenMultiplier(uint128 _nominator, uint128 _denominator) external;
/// @notice Change the pubdata pricing mode before the first batch is processed
/// @param _pricingMode The new pubdata pricing mode
function setPubdataPricingMode(PubdataPricingMode _pricingMode) external;
/// @notice Set the transaction filterer
function setTransactionFilterer(address _transactionFilterer) external;
/// @notice Allow EVM emulation on chain
function allowEvmEmulation() external returns (bytes32 canonicalTxHash);
/// @notice Perform the upgrade from the current protocol version with the corresponding upgrade data
/// @param _protocolVersion The current protocol version from which upgrade is executed
/// @param _cutData The diamond cut parameters that is executed in the upgrade
function upgradeChainFromVersion(uint256 _protocolVersion, Diamond.DiamondCutData calldata _cutData) external;
/// @notice Executes a proposed governor upgrade
/// @dev Only the ChainTypeManager contract can execute the upgrade
/// @param _diamondCut The diamond cut parameters to be executed
function executeUpgrade(Diamond.DiamondCutData calldata _diamondCut) external;
/// @notice Instantly pause the functionality of all freezable facets & their selectors
/// @dev Only the governance mechanism may freeze Diamond Proxy
function freezeDiamond() external;
/// @notice Unpause the functionality of all freezable facets & their selectors
/// @dev Only the CTM can unfreeze Diamond Proxy
function unfreezeDiamond() external;
function genesisUpgrade(
address _l1GenesisUpgrade,
address _ctmDeployer,
bytes calldata _forceDeploymentData,
bytes[] calldata _factoryDeps
) external;
/// @notice Returns address of the RollupDAManager of the ZK Chain.
function getRollupDAManager() external view returns (address);
/// @notice Set the L1 DA validator address as well as the L2 DA validator address.
/// @dev While in principle it is possible that updating only one of the addresses is needed,
/// usually these should work in pair and L1 validator typically expects a specific input from the L2 Validator.
/// That's why we change those together to prevent admins of chains from shooting themselves in the foot.
/// @param _l1DAValidator The address of the L1 DA validator
/// @param _l2DAValidator The address of the L2 DA validator
function setDAValidatorPair(address _l1DAValidator, address _l2DAValidator) external;
/// @notice Makes the chain as permanent rollup.
/// @dev This is a security feature needed for chains that should be
/// trusted to keep their data available even if the chain admin becomes malicious
/// and tries to set the DA validator pair to something which does not publish DA to Ethereum.
/// @dev DANGEROUS: once activated, there is no way back!
function makePermanentRollup() external;
/// @notice Porter availability status changes
event IsPorterAvailableStatusUpdate(bool isPorterAvailable);
/// @notice Validator's status changed
event ValidatorStatusUpdate(address indexed validatorAddress, bool isActive);
/// @notice pendingAdmin is changed
/// @dev Also emitted when new admin is accepted and in this case, `newPendingAdmin` would be zero address
event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin);
/// @notice Admin changed
event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
/// @notice Priority transaction max L2 gas limit changed
event NewPriorityTxMaxGasLimit(uint256 oldPriorityTxMaxGasLimit, uint256 newPriorityTxMaxGasLimit);
/// @notice Fee params for L1->L2 transactions changed
event NewFeeParams(FeeParams oldFeeParams, FeeParams newFeeParams);
/// @notice Validium mode status changed
event PubdataPricingModeUpdate(PubdataPricingMode validiumMode);
/// @notice The transaction filterer has been updated
event NewTransactionFilterer(address oldTransactionFilterer, address newTransactionFilterer);
/// @notice BaseToken multiplier for L1->L2 transactions changed
event NewBaseTokenMultiplier(
uint128 oldNominator,
uint128 oldDenominator,
uint128 newNominator,
uint128 newDenominator
);
/// @notice Emitted when an upgrade is executed.
event ExecuteUpgrade(Diamond.DiamondCutData diamondCut);
/// @notice Emitted when the migration to the new settlement layer is complete.
event MigrationComplete();
/// @notice Emitted when the contract is frozen.
event Freeze();
/// @notice Emitted when the contract is unfrozen.
event Unfreeze();
/// @notice The EVM emulator has been enabled
event EnableEvmEmulator();
/// @notice New pair of DA validators set
event NewL2DAValidator(address indexed oldL2DAValidator, address indexed newL2DAValidator);
event NewL1DAValidator(address indexed oldL1DAValidator, address indexed newL1DAValidator);
event BridgeMint(address indexed _account, uint256 _amount);
/// @dev Similar to IL1AssetHandler interface, used to send chains.
function forwardedBridgeBurn(
address _settlementLayer,
address _originalCaller,
bytes calldata _data
) external payable returns (bytes memory _bridgeMintData);
/// @dev Similar to IL1AssetHandler interface, used to claim failed chain transfers.
function forwardedBridgeRecoverFailedTransfer(
uint256 _chainId,
bytes32 _assetInfo,
address _originalCaller,
bytes calldata _chainData
) external payable;
/// @dev Similar to IL1AssetHandler interface, used to receive chains.
function forwardedBridgeMint(bytes calldata _data, bool _contractAlreadyDeployed) external payable;
function prepareChainCommitment() external view returns (ZKChainCommitment memory commitment);
}// 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.21;
import {IZKChainBase} from "./IZKChainBase.sol";
/// @dev Enum used by L2 System Contracts to differentiate logs.
enum SystemLogKey {
L2_TO_L1_LOGS_TREE_ROOT_KEY,
PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY,
CHAINED_PRIORITY_TXN_HASH_KEY,
NUMBER_OF_LAYER_1_TXS_KEY,
// Note, that it is important that `PREV_BATCH_HASH_KEY` has position
// `4` since it is the same as it was in the previous protocol version and
// it is the only one that is emitted before the system contracts are upgraded.
PREV_BATCH_HASH_KEY,
L2_DA_VALIDATOR_OUTPUT_HASH_KEY,
USED_L2_DA_VALIDATOR_ADDRESS_KEY,
MESSAGE_ROOT_ROLLING_HASH_KEY,
L2_TXS_STATUS_ROLLING_HASH_KEY,
EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY
}
struct LogProcessingOutput {
uint256 numberOfLayer1Txs;
bytes32 chainedPriorityTxsHash;
bytes32 previousBatchHash;
bytes32 pubdataHash;
bytes32 stateDiffHash;
bytes32 l2LogsTreeRoot;
uint256 packedBatchAndL2BlockTimestamp;
bytes32 l2DAValidatorOutputHash;
bytes32 l2TxsStatusRollingHash;
bytes32 dependencyRootsRollingHash;
}
/// @dev Maximal value that SystemLogKey variable can have.
uint256 constant MAX_LOG_KEY = uint256(type(SystemLogKey).max);
/// @dev Offset used to pull Address From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch)
uint256 constant L2_LOG_ADDRESS_OFFSET = 4;
/// @dev Offset used to pull Key From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch) + 20 (bytes for address)
uint256 constant L2_LOG_KEY_OFFSET = 24;
/// @dev Offset used to pull Value From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch) + 20 (bytes for address) + 32 (bytes for key)
uint256 constant L2_LOG_VALUE_OFFSET = 56;
/// @dev Max number of blobs currently supported
uint256 constant MAX_NUMBER_OF_BLOBS = 6;
/// @dev The number of blobs that must be present in the commitment to a batch.
/// It represents the maximal number of blobs that circuits can support and can be larger
/// than the maximal number of blobs supported by the contract (`MAX_NUMBER_OF_BLOBS`).
uint256 constant TOTAL_BLOBS_IN_COMMITMENT = 16;
/// @title The interface of the ZKsync Executor contract capable of processing events emitted in the ZKsync protocol.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IExecutor is IZKChainBase {
/// @notice Rollup batch stored data
/// @param batchNumber Rollup batch number
/// @param batchHash Hash of L2 batch
/// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more
/// @param numberOfLayer1Txs Number of priority operations to be processed
/// @param priorityOperationsHash Hash of all priority operations from this batch
/// @param l2LogsTreeRoot Root hash of tree that contains L2 -> L1 messages from this batch
/// @param timestamp Rollup batch timestamp, have the same format as Ethereum batch constant
/// @param commitment Verified input for the ZKsync circuit
// solhint-disable-next-line gas-struct-packing
struct StoredBatchInfo {
uint64 batchNumber;
bytes32 batchHash;
uint64 indexRepeatedStorageChanges;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 dependencyRootsRollingHash;
bytes32 l2LogsTreeRoot;
uint256 timestamp;
bytes32 commitment;
}
/// @notice Legacy StoredBatchInfo struct
/// @dev dependencyRootsRollingHash is not included in the struct
// solhint-disable-next-line gas-struct-packing
struct LegacyStoredBatchInfo {
uint64 batchNumber;
bytes32 batchHash;
uint64 indexRepeatedStorageChanges;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 l2LogsTreeRoot;
uint256 timestamp;
bytes32 commitment;
}
/// @notice Data needed to commit new batch
/// @param batchNumber Number of the committed batch
/// @param timestamp Unix timestamp denoting the start of the batch execution
/// @param indexRepeatedStorageChanges The serial number of the shortcut index that's used as a unique identifier for storage keys that were used twice or more
/// @param newStateRoot The state root of the full state tree
/// @param numberOfLayer1Txs Number of priority operations to be processed
/// @param priorityOperationsHash Hash of all priority operations from this batch
/// @param bootloaderHeapInitialContentsHash Hash of the initial contents of the bootloader heap. In practice it serves as the commitment to the transactions in the batch.
/// @param eventsQueueStateHash Hash of the events queue state. In practice it serves as the commitment to the events in the batch.
/// @param systemLogs concatenation of all L2 -> L1 system logs in the batch
/// @param operatorDAInput Packed pubdata commitments/data.
/// @dev pubdataCommitments format: This will always start with a 1 byte pubdataSource flag. Current allowed values are 0 (calldata) or 1 (blobs)
/// kzg: list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes) = 144 bytes
/// calldata: pubdataCommitments.length - 1 - 32 bytes of pubdata
/// and 32 bytes appended to serve as the blob commitment part for the aux output part of the batch commitment
/// @dev For 2 blobs we will be sending 288 bytes of calldata instead of the full amount for pubdata.
/// @dev When using calldata, we only need to send one blob commitment since the max number of bytes in calldata fits in a single blob and we can pull the
/// linear hash from the system logs
struct CommitBatchInfo {
uint64 batchNumber;
uint64 timestamp;
uint64 indexRepeatedStorageChanges;
bytes32 newStateRoot;
uint256 numberOfLayer1Txs;
bytes32 priorityOperationsHash;
bytes32 bootloaderHeapInitialContentsHash;
bytes32 eventsQueueStateHash;
bytes systemLogs;
bytes operatorDAInput;
}
/// @notice Container for a list of transaction statuses to precommit.
/// @param txs A packed array of individual transaction status commitments for the batch. Each is expected to be
/// of length 33 and have the following format: <32-byte tx hash, 1-byte status>. where status is either 0 (failed) or 1 (success).
/// @param untrustedLastL2BlockNumberHint The "hint" for what the last L2 block number that these txs represent is.
struct PrecommitInfo {
bytes packedTxsCommitments;
uint256 untrustedLastL2BlockNumberHint;
}
/// @notice Precommits the status of all L2 transactions for the next batch on the shared bridge.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _batchNumber The sequential batch number to precommit (must equal `s.totalBatchesCommitted + 1`).
/// @param _precommitData ABI‐encoded transaction status list for the precommit.
function precommitSharedBridge(address _chainAddress, uint256 _batchNumber, bytes calldata _precommitData) external;
/// @notice Function called by the operator to commit new batches. It is responsible for:
/// - Verifying the correctness of their timestamps.
/// - Processing their L2->L1 logs.
/// - Storing batch commitments.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processFrom The batch number from which the processing starts.
/// @param _processTo The batch number at which the processing ends.
/// @param _commitData The encoded data of the new batches to be committed.
function commitBatchesSharedBridge(
address _chainAddress,
uint256 _processFrom,
uint256 _processTo,
bytes calldata _commitData
) external;
/// @notice Batches commitment verification.
/// @dev Only verifies batch commitments without any other processing.
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processBatchFrom The batch number from which the verification starts.
/// @param _processBatchTo The batch number at which the verification ends.
/// @param _proofData The encoded data of the new batches to be verified.
function proveBatchesSharedBridge(
address _chainAddress,
uint256 _processBatchFrom,
uint256 _processBatchTo,
bytes calldata _proofData
) external;
/// @notice The function called by the operator to finalize (execute) batches. It is responsible for:
/// - Processing all pending operations (commpleting priority requests).
/// - Finalizing this batch (i.e. allowing to withdraw funds from the system)
/// @param _chainAddress The address of the DiamondProxy of the chain. Note, that it is not used in the implementation,
/// because it is expected to be equal to the `address(this)`, but it is kept here to maintain the same interface on both
/// `ValidatorTimelock` and `Executor` for easier and cheaper implementation of the timelock.
/// @param _processFrom The batch number from which the execution starts.
/// @param _processTo The batch number at which the execution ends.
/// @param _executeData The encoded data of the new batches to be executed.
function executeBatchesSharedBridge(
address _chainAddress,
uint256 _processFrom,
uint256 _processTo,
bytes calldata _executeData
) external;
/// @notice Reverts unexecuted batches
/// @param _chainAddress The address of the DiamondProxy of the chain.
/// @param _newLastBatch batch number after which batches should be reverted
/// @dev When the _newLastBatch is equal to the number of committed batches,
/// only the precommitment is erased.
/// NOTE: Doesn't delete the stored data about batches, but only decreases
/// counters that are responsible for the number of batches
function revertBatchesSharedBridge(address _chainAddress, uint256 _newLastBatch) external;
/// @notice Event emitted when a batch is committed
/// @param batchNumber Number of the batch committed
/// @param batchHash Hash of the L2 batch
/// @param commitment Calculated input for the ZKsync circuit
/// @dev It has the name "BlockCommit" and not "BatchCommit" due to backward compatibility considerations
event BlockCommit(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment);
/// @notice Event emitted when batches are verified
/// @param previousLastVerifiedBatch Batch number of the previous last verified batch
/// @param currentLastVerifiedBatch Batch number of the current last verified batch
/// @dev It has the name "BlocksVerification" and not "BatchesVerification" due to backward compatibility considerations
event BlocksVerification(uint256 indexed previousLastVerifiedBatch, uint256 indexed currentLastVerifiedBatch);
/// @notice Event emitted when a batch is executed
/// @param batchNumber Number of the batch executed
/// @param batchHash Hash of the L2 batch
/// @param commitment Verified input for the ZKsync circuit
/// @dev It has the name "BlockExecution" and not "BatchExecution" due to backward compatibility considerations
event BlockExecution(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment);
/// @notice Event emitted when batches are reverted
/// @param totalBatchesCommitted Total number of committed batches after the revert
/// @param totalBatchesVerified Total number of verified batches after the revert
/// @param totalBatchesExecuted Total number of executed batches
/// @dev It has the name "BlocksRevert" and not "BatchesRevert" due to backward compatibility considerations
event BlocksRevert(uint256 totalBatchesCommitted, uint256 totalBatchesVerified, uint256 totalBatchesExecuted);
/// @notice Emitted when a new precommitment is set for a batch.
/// @param batchNumber The batch number for which the precommitment was recorded.
/// @param untrustedLastL2BlockNumberHint The hint to what L2 block number the precommitment should correspond to. Note, that there are no
/// guarantees on its correctness, it is just a way for the server to make external nodes' indexing simpler.
/// @param precommitment The resulting rolling hash of all transaction statuses.
event BatchPrecommitmentSet(
uint256 indexed batchNumber,
uint256 indexed untrustedLastL2BlockNumberHint,
bytes32 precommitment
);
}// 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.21;
import {VerifierParams} from "../chain-interfaces/IVerifier.sol";
import {PubdataPricingMode} from "../chain-deps/ZKChainStorage.sol";
import {IZKChainBase} from "./IZKChainBase.sol";
/// @title The interface of the Getters Contract that implements functions for getting contract state from outside the blockchain.
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev Most of the methods simply return the values that correspond to the current diamond proxy and possibly
/// not to the ZK Chain as a whole. For example, if the chain is migrated to another settlement layer, the values returned
/// by this facet will correspond to the values stored on this chain and possilbly not the canonical state of the chain.
interface IGetters is IZKChainBase {
/*//////////////////////////////////////////////////////////////
CUSTOM GETTERS
//////////////////////////////////////////////////////////////*/
/// @return The address of the verifier smart contract
function getVerifier() external view returns (address);
/// @return The address of the current admin
function getAdmin() external view returns (address);
/// @return The address of the pending admin
function getPendingAdmin() external view returns (address);
/// @return The address of the bridgehub
function getBridgehub() external view returns (address);
/// @return The address of the state transition
function getChainTypeManager() external view returns (address);
/// @return The chain ID
function getChainId() external view returns (uint256);
/// @return The address of the base token
function getBaseToken() external view returns (address);
/// @return The address of the base token
function getBaseTokenAssetId() external view returns (bytes32);
/// @return The total number of batches that were committed
function getTotalBatchesCommitted() external view returns (uint256);
/// @return The total number of batches that were committed & verified
function getTotalBatchesVerified() external view returns (uint256);
/// @return The total number of batches that were committed & verified & executed
function getTotalBatchesExecuted() external view returns (uint256);
// @return Address of transaction filterer
function getTransactionFilterer() external view returns (address);
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs() external view returns (uint256);
/// @return The start index of the priority tree, i.e. the index of the first priority operation that
/// was included into the priority tree.
function getPriorityTreeStartIndex() external view returns (uint256);
/// @return The root hash of the priority tree
function getPriorityTreeRoot() external view returns (bytes32);
/// @return Whether the priority queue is active, i.e. whether new priority operations are appended to it.
/// Once the chain processes all the transactions that were present in the priority queue, all the L1->L2 related
/// operations will start to get done using the priority tree.
function isPriorityQueueActive() external view returns (bool);
/// @notice The function that returns the first unprocessed priority transaction.
/// @dev Returns zero if and only if no operations were processed from the queue.
/// @dev If all the transactions were processed, it will return the last processed index, so
/// in case exactly *unprocessed* transactions are needed, one should check that getPriorityQueueSize() is greater than 0.
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx() external view returns (uint256);
/// @return The number of priority operations currently in the queue
function getPriorityQueueSize() external view returns (uint256);
/// @return Whether the address has a validator access
function isValidator(address _address) external view returns (bool);
/// @return merkleRoot Merkle root of the tree with L2 logs for the selected batch
function l2LogsRootHash(uint256 _batchNumber) external view returns (bytes32 merkleRoot);
/// @notice For unfinalized (non executed) batches may change
/// @dev returns zero for non-committed batches
/// @return The hash of committed L2 batch.
function storedBatchHash(uint256 _batchNumber) external view returns (bytes32);
/// @return Bytecode hash of bootloader program.
function getL2BootloaderBytecodeHash() external view returns (bytes32);
/// @return Bytecode hash of default account (bytecode for EOA).
function getL2DefaultAccountBytecodeHash() external view returns (bytes32);
/// @return Bytecode hash of EVM emulator.
function getL2EvmEmulatorBytecodeHash() external view returns (bytes32);
/// @return Verifier parameters.
/// @dev This function is deprecated and will soon be removed.
function getVerifierParams() external view returns (VerifierParams memory);
/// @return Whether the diamond is frozen or not
function isDiamondStorageFrozen() external view returns (bool);
/// @return The current packed protocol version. To access human-readable version, use `getSemverProtocolVersion` function.
function getProtocolVersion() external view returns (uint256);
/// @return The tuple of (major, minor, patch) protocol version.
function getSemverProtocolVersion() external view returns (uint32, uint32, uint32);
/// @return The upgrade system contract transaction hash, 0 if the upgrade is not initialized
function getL2SystemContractsUpgradeTxHash() external view returns (bytes32);
/// @return The L2 batch number in which the upgrade transaction was processed.
/// @dev It is equal to 0 in the following two cases:
/// - No upgrade transaction has ever been processed.
/// - The upgrade transaction has been processed and the batch with such transaction has been
/// executed (i.e. finalized).
function getL2SystemContractsUpgradeBatchNumber() external view returns (uint256);
/// @return The maximum number of L2 gas that a user can request for L1 -> L2 transactions
function getPriorityTxMaxGasLimit() external view returns (uint256);
/// @return Whether a withdrawal has been finalized.
/// @param _l2BatchNumber The L2 batch number within which the withdrawal happened.
/// @param _l2MessageIndex The index of the L2->L1 message denoting the withdrawal.
function isEthWithdrawalFinalized(uint256 _l2BatchNumber, uint256 _l2MessageIndex) external view returns (bool);
/// @return The pubdata pricing mode.
function getPubdataPricingMode() external view returns (PubdataPricingMode);
/// @return the baseTokenGasPriceMultiplierNominator, used to compare the baseTokenPrice to ether for L1->L2 transactions
function baseTokenGasPriceMultiplierNominator() external view returns (uint128);
/// @return the baseTokenGasPriceMultiplierDenominator, used to compare the baseTokenPrice to ether for L1->L2 transactions
function baseTokenGasPriceMultiplierDenominator() external view returns (uint128);
/*//////////////////////////////////////////////////////////////
DIAMOND LOUPE
//////////////////////////////////////////////////////////////*/
/// @notice Faсet structure compatible with the EIP-2535 diamond loupe
/// @param addr The address of the facet contract
/// @param selectors The NON-sorted array with selectors associated with facet
struct Facet {
address addr;
bytes4[] selectors;
}
/// @return result All facet addresses and their function selectors
function facets() external view returns (Facet[] memory);
/// @return NON-sorted array with function selectors supported by a specific facet
function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory);
/// @return facets NON-sorted array of facet addresses supported on diamond
function facetAddresses() external view returns (address[] memory facets);
/// @return facet The facet address associated with a selector. Zero if the selector is not added to the diamond
function facetAddress(bytes4 _selector) external view returns (address facet);
/// @return Whether the selector can be frozen by the admin or always accessible
function isFunctionFreezable(bytes4 _selector) external view returns (bool);
/// @return isFreezable Whether the facet can be frozen by the admin or always accessible
function isFacetFreezable(address _facet) external view returns (bool isFreezable);
/// @return The address of the current settlement layer.
function getSettlementLayer() external view returns (address);
}// 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.21;
import {IMessageVerification} from "./IMessageVerification.sol";
import {IMailboxImpl} from "./IMailboxImpl.sol";
/// @title The interface of the ZKsync Mailbox contract that provides interfaces for L1 <-> L2 interaction.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMailbox is IMessageVerification, IMailboxImpl {}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @author Matter Labs /// @custom:security-contact [email protected] interface IL1AssetDeploymentTracker { function bridgeCheckCounterpartAddress( uint256 _chainId, bytes32 _assetId, address _originalCaller, address _assetHandlerAddressOnCounterpart ) external view; }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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.8.0/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
pragma solidity 0.8.28;
import {IL1Nullifier} from "../interfaces/IL1Nullifier.sol";
import {INativeTokenVault} from "./INativeTokenVault.sol";
import {IL1AssetDeploymentTracker} from "../interfaces/IL1AssetDeploymentTracker.sol";
/// @title L1 Native token vault contract interface
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @notice The NTV is an Asset Handler for the L1AssetRouter to handle native tokens
// is IL1AssetHandler, IL1BaseTokenAssetHandler {
interface IL1NativeTokenVault is INativeTokenVault, IL1AssetDeploymentTracker {
/// @notice The L1Nullifier contract
function L1_NULLIFIER() external view returns (IL1Nullifier);
/// @notice Returns the total number of specific tokens locked for some chain
function chainBalance(uint256 _chainId, bytes32 _assetId) external view returns (uint256);
/// @notice Registers ETH token
function registerEthToken() external;
event TokenBeaconUpdated(address indexed l2TokenBeacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// 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.21; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The library for unchecked math. */ library UncheckedMath { function uncheckedInc(uint256 _number) internal pure returns (uint256) { unchecked { return _number + 1; } } function uncheckedAdd(uint256 _lhs, uint256 _rhs) internal pure returns (uint256) { unchecked { return _lhs + _rhs; } } }
// 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.21;
/// @notice Part of the configuration parameters of ZKP circuits
struct VerifierParams {
bytes32 recursionNodeLevelVkHash;
bytes32 recursionLeafLevelVkHash;
bytes32 recursionCircuitsSetVksHash;
}
/// @title The interface of the Verifier contract, responsible for the zero knowledge proof verification.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IVerifier {
/// @dev Verifies a zk-SNARK proof.
/// @return A boolean value indicating whether the zk-SNARK proof is valid.
/// Note: The function may revert execution instead of returning false in some cases.
function verify(uint256[] calldata _publicInputs, uint256[] calldata _proof) external view returns (bool);
/// @notice Calculates a keccak256 hash of the runtime loaded verification keys.
/// @return vkHash The keccak256 hash of the loaded verification keys.
function verificationKeyHash() 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.21;
import {QueueIsEmpty} from "../../common/L1ContractErrors.sol";
/// @notice The structure that contains meta information of the L2 transaction that was requested from L1
/// @dev The weird size of fields was selected specifically to minimize the structure storage size
/// @param canonicalTxHash Hashed L2 transaction data that is needed to process it
/// @param expirationTimestamp Expiration timestamp for this request (must be satisfied before)
/// @param layer2Tip Additional payment to the validator as an incentive to perform the operation
struct PriorityOperation {
bytes32 canonicalTxHash;
uint64 expirationTimestamp;
uint192 layer2Tip;
}
/// @author Matter Labs
/// @custom:security-contact [email protected]
/// @dev The library provides the API to interact with the priority queue container
/// @dev Order of processing operations from queue - FIFO (Fist in - first out)
library PriorityQueue {
using PriorityQueue for Queue;
/// @notice Container that stores priority operations
/// @param data The inner mapping that saves priority operation by its index
/// @param head The pointer to the first unprocessed priority operation, equal to the tail if the queue is empty
/// @param tail The pointer to the free slot
struct Queue {
mapping(uint256 priorityOpId => PriorityOperation priorityOp) data;
uint256 tail;
uint256 head;
}
/// @notice Returns zero if and only if no operations were processed from the queue
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx(Queue storage _queue) internal view returns (uint256) {
return _queue.head;
}
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs(Queue storage _queue) internal view returns (uint256) {
return _queue.tail;
}
/// @return The total number of unprocessed priority operations in a priority queue
function getSize(Queue storage _queue) internal view returns (uint256) {
return uint256(_queue.tail - _queue.head);
}
/// @return Whether the priority queue contains no operations
function isEmpty(Queue storage _queue) internal view returns (bool) {
return _queue.tail == _queue.head;
}
/// @notice Add the priority operation to the end of the priority queue
function pushBack(Queue storage _queue, PriorityOperation memory _operation) internal {
// Save value into the stack to avoid double reading from the storage
uint256 tail = _queue.tail;
_queue.data[tail] = _operation;
_queue.tail = tail + 1;
}
/// @return The first unprocessed priority operation from the queue
function front(Queue storage _queue) internal view returns (PriorityOperation memory) {
// priority queue is empty
if (_queue.isEmpty()) {
revert QueueIsEmpty();
}
return _queue.data[_queue.head];
}
/// @notice Remove the first unprocessed priority operation from the queue
/// @return priorityOperation that was popped from the priority queue
function popFront(Queue storage _queue) internal returns (PriorityOperation memory priorityOperation) {
// priority queue is empty
if (_queue.isEmpty()) {
revert QueueIsEmpty();
}
// Save value into the stack to avoid double reading from the storage
uint256 head = _queue.head;
priorityOperation = _queue.data[head];
delete _queue.data[head];
_queue.head = head + 1;
}
}// 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.21;
import {DynamicIncrementalMerkle} from "../../common/libraries/DynamicIncrementalMerkle.sol";
import {Merkle} from "../../common/libraries/Merkle.sol";
import {PriorityTreeCommitment} from "../../common/Config.sol";
import {InvalidCommitment, InvalidNextLeafIndex, InvalidStartIndex, InvalidUnprocessedIndex, NotHistoricalRoot} from "../L1StateTransitionErrors.sol";
struct PriorityOpsBatchInfo {
bytes32[] leftPath;
bytes32[] rightPath;
bytes32[] itemHashes;
}
bytes32 constant ZERO_LEAF_HASH = keccak256("");
library PriorityTree {
using PriorityTree for Tree;
using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree;
struct Tree {
uint256 startIndex; // priority tree started accepting priority ops from this index
uint256 unprocessedIndex; // relative to `startIndex`
mapping(bytes32 => bool) historicalRoots;
DynamicIncrementalMerkle.Bytes32PushTree tree;
}
/// @notice Returns zero if and only if no operations were processed from the tree
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.unprocessedIndex;
}
/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.tree._nextLeafIndex;
}
/// @return The total number of unprocessed priority operations in a priority queue
function getSize(Tree storage _tree) internal view returns (uint256) {
return _tree.tree._nextLeafIndex - _tree.unprocessedIndex;
}
/// @notice Add the priority operation to the end of the priority queue
function push(Tree storage _tree, bytes32 _hash) internal {
(, bytes32 newRoot) = _tree.tree.push(_hash);
_tree.historicalRoots[newRoot] = true;
}
/// @notice Set up the tree
function setup(Tree storage _tree, uint256 _startIndex) internal {
bytes32 initialRoot = _tree.tree.setup(ZERO_LEAF_HASH);
_tree.historicalRoots[initialRoot] = true;
_tree.startIndex = _startIndex;
}
/// @return Returns the tree root.
function getRoot(Tree storage _tree) internal view returns (bytes32) {
return _tree.tree.root();
}
/// @param _root The root to check.
/// @return Returns true if the root is a historical root.
function isHistoricalRoot(Tree storage _tree, bytes32 _root) internal view returns (bool) {
return _tree.historicalRoots[_root];
}
/// @notice Process the priority operations of a batch.
/// @dev Note, that the function below only checks that a certain segment of items is present in the tree.
/// It does not check that e.g. there are no zero items inside the provided `itemHashes`, so in theory proofs
/// that include non-existing priority operations could be created. This function relies on the fact
/// that the `itemHashes` of `_priorityOpsData` are hashes of valid priority transactions.
/// This fact is ensured by the fact the rolling hash of those is sent to the Executor by the bootloader
/// and so assuming that zero knowledge proofs are correct, so is the structure of the `itemHashes`.
function processBatch(Tree storage _tree, PriorityOpsBatchInfo memory _priorityOpsData) internal {
if (_priorityOpsData.itemHashes.length > 0) {
bytes32 expectedRoot = Merkle.calculateRootPaths(
_priorityOpsData.leftPath,
_priorityOpsData.rightPath,
_tree.unprocessedIndex,
_priorityOpsData.itemHashes
);
if (!_tree.historicalRoots[expectedRoot]) {
revert NotHistoricalRoot(expectedRoot);
}
_tree.unprocessedIndex += _priorityOpsData.itemHashes.length;
}
}
/// @notice Allows to skip a certain number of operations.
/// @param _lastUnprocessed The new expected id of the unprocessed transaction.
/// @dev It is used when the corresponding transactions have been processed by priority queue.
function skipUntil(Tree storage _tree, uint256 _lastUnprocessed) internal {
if (_tree.startIndex > _lastUnprocessed) {
// Nothing to do, return
return;
}
uint256 newUnprocessedIndex = _lastUnprocessed - _tree.startIndex;
if (newUnprocessedIndex <= _tree.unprocessedIndex) {
// These transactions were already processed, skip.
return;
}
_tree.unprocessedIndex = newUnprocessedIndex;
}
/// @notice Initialize a chain from a commitment.
function initFromCommitment(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal {
uint256 height = _commitment.sides.length; // Height, including the root node.
if (height == 0) {
revert InvalidCommitment();
}
_tree.startIndex = _commitment.startIndex;
_tree.unprocessedIndex = _commitment.unprocessedIndex;
_tree.tree._nextLeafIndex = _commitment.nextLeafIndex;
_tree.tree._sides = _commitment.sides;
bytes32 zero = ZERO_LEAF_HASH;
_tree.tree._zeros = new bytes32[](height);
for (uint256 i; i < height; ++i) {
_tree.tree._zeros[i] = zero;
zero = Merkle.efficientHash(zero, zero);
}
_tree.historicalRoots[_tree.tree.root()] = true;
}
/// @notice Reinitialize the tree from a commitment on L1.
function l1Reinit(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal {
if (_tree.startIndex != _commitment.startIndex) {
revert InvalidStartIndex(_tree.startIndex, _commitment.startIndex);
}
if (_tree.unprocessedIndex > _commitment.unprocessedIndex) {
revert InvalidUnprocessedIndex(_tree.unprocessedIndex, _commitment.unprocessedIndex);
}
if (_tree.tree._nextLeafIndex < _commitment.nextLeafIndex) {
revert InvalidNextLeafIndex(_tree.tree._nextLeafIndex, _commitment.nextLeafIndex);
}
_tree.unprocessedIndex = _commitment.unprocessedIndex;
}
/// @notice Reinitialize the tree from a commitment on GW.
function checkGWReinit(Tree storage _tree, PriorityTreeCommitment memory _commitment) internal view {
if (_tree.startIndex != _commitment.startIndex) {
revert InvalidStartIndex(_tree.startIndex, _commitment.startIndex);
}
if (_tree.unprocessedIndex > _commitment.unprocessedIndex) {
revert InvalidUnprocessedIndex(_tree.unprocessedIndex, _commitment.unprocessedIndex);
}
if (_tree.tree._nextLeafIndex > _commitment.nextLeafIndex) {
revert InvalidNextLeafIndex(_tree.tree._nextLeafIndex, _commitment.nextLeafIndex);
}
}
/// @notice Returns the commitment to the priority tree.
function getCommitment(Tree storage _tree) internal view returns (PriorityTreeCommitment memory commitment) {
commitment.nextLeafIndex = _tree.tree._nextLeafIndex;
commitment.startIndex = _tree.startIndex;
commitment.unprocessedIndex = _tree.unprocessedIndex;
commitment.sides = _tree.tree._sides;
}
}// 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.
* @dev by default ZkSync can send fixed-length messages on L1.
* A fixed length message has 4 parameters `senderAddress`, `isService`, `key`, `value`,
* the first one is taken from the context, the other three are chosen by the sender.
* @dev To send a variable-length message we use this trick:
* - This system contract accepts an arbitrary length message and sends a fixed length message with
* parameters `senderAddress == this`, `isService == true`, `key == msg.sender`, `value == keccak256(message)`.
* - The contract on L1 accepts all sent messages and if the message came from this system contract
* it requires the preimage of `value` to be provided.
*/
interface IL2ToL1Messenger {
// 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);
/// @notice Sends an arbitrary length message to L1.
/// @param _message The variable length message to be sent to L1.
/// @return Returns the keccak256 hashed value of the message.
function sendToL1(bytes calldata _message) external returns (bytes32);
/// @notice Sends L2ToL1Log.
/// @param _isService The `isService` flag.
/// @param _key The `key` part of the L2Log.
/// @param _value The `value` part of the L2Log.
/// @dev Can be called only by a system contract.
function sendL2ToL1Log(bool _isService, bytes32 _key, bytes32 _value) external returns (uint256 logIdInMerkleTree);
/// @notice This function is expected to be called only by the KnownCodesStorage system contract
function requestBytecodeL1Publication(bytes32 _bytecodeHash) external;
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /** * @author Matter Labs * @custom:security-contact [email protected] * @notice The interface of the L2 InteropRootStorage contract, * responsible for storing the message roots of other chains on the L2. */ interface IL2InteropRootStorage { /// @notice Mapping of chain ID to block or batch number to message root. function interopRoots(uint256 chainId, uint256 blockOrBatchNumber) 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.21;
import {L2Log, L2Message} from "../../common/Messaging.sol";
/// @title The interface of the ZKsync MessageVerification contract that can be used to prove L2 message inclusion.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMessageVerification {
/// @notice Prove that a specific arbitrary-length message was sent in a specific L2 batch/block number.
/// @param _chainId The chain id of the L2 where the message comes from.
/// @param _blockOrBatchNumber The executed L2 batch/block number in which the message appeared.
/// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent.
/// @param _proof Merkle proof for inclusion of L2 log that was sent with the message.
/// @return Boolean specifying whether the proof is valid.
function proveL2MessageInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that a specific L2 log was sent in a specific L2 batch.
/// @param _chainId The chain id of the L2 where the log comes from.
/// @param _blockOrBatchNumber The executed L2 batch/block number in which the log appeared.
/// @param _index The position of the l2log in the L2 logs Merkle tree.
/// @param _log Information about the sent log.
/// @param _proof Merkle proof for inclusion of the L2 log.
/// @return Whether the proof is correct and L2 log is included in batch.
function proveL2LogInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _index,
L2Log calldata _log,
bytes32[] calldata _proof
) external view returns (bool);
/// @dev Proves that a certain leaf was included as part of the log merkle tree.
/// @dev Warning: this function does not enforce any additional checks on the structure
/// of the leaf. This means that it can accept intermediate nodes of the Merkle tree as a `_leaf` as
/// well as the default "empty" leaves. It is the responsibility of the caller to ensure that the
/// `_leaf` is a hash of a valid leaf.
/// @param _chainId The chain id of the L2 where the leaf comes from.
/// @param _blockOrBatchNumber The batch/block number of the leaf to be proven.
/// @param _leafProofMask The leaf proof mask.
/// @param _leaf The leaf to be proven.
/// @param _proof The proof.
function proveL2LeafInclusionShared(
uint256 _chainId,
uint256 _blockOrBatchNumber,
uint256 _leafProofMask,
bytes32 _leaf,
bytes32[] calldata _proof
) 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.21; /// @title The interface of the ZKsync contract, responsible for the main ZKsync logic. /// @author Matter Labs /// @custom:security-contact [email protected] interface IZKChainBase { /// @return Returns facet name. function getName() external view returns (string memory); }
// 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.21;
import {IZKChainBase} from "./IZKChainBase.sol";
import {BridgehubL2TransactionRequest, L2CanonicalTransaction, L2Log, L2Message, TxStatus} from "../../common/Messaging.sol";
/// @title The interface of the ZKsync Mailbox contract that provides functions for L1 <-> L2 interaction.
/// @author Matter Labs
/// @custom:security-contact [email protected]
interface IMailboxImpl is IZKChainBase {
/// @notice Prove that a specific arbitrary-length message was sent in a specific L2 batch number.
/// @param _batchNumber The executed L2 batch number in which the message appeared.
/// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent.
/// @param _proof Merkle proof for inclusion of L2 log that was sent with the message.
/// @return Boolean specifying whether the proof is valid.
function proveL2MessageInclusion(
uint256 _batchNumber,
uint256 _index,
L2Message calldata _message,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that a specific L2 log was sent in a specific L2 batch.
/// @param _batchNumber The executed L2 batch number in which the log appeared.
/// @param _index The position of the l2log in the L2 logs Merkle tree.
/// @param _log Information about the sent log.
/// @param _proof Merkle proof for inclusion of the L2 log.
/// @return Whether the proof is correct and L2 log is included in batch.
function proveL2LogInclusion(
uint256 _batchNumber,
uint256 _index,
L2Log calldata _log,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice Prove that the L1 -> L2 transaction was processed with the specified status.
/// @param _l2TxHash The L2 canonical transaction hash.
/// @param _l2BatchNumber The L2 batch number where the transaction was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent.
/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction.
/// @param _status The execution status of the L1 -> L2 transaction (true - success & 0 - fail).
/// @return Whether the proof is correct and the transaction was actually executed with provided status.
/// NOTE: It may return `false` for incorrect proof, but it doesn't mean that the L1 -> L2 transaction has an opposite status!
function proveL1ToL2TransactionStatus(
bytes32 _l2TxHash,
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes32[] calldata _merkleProof,
TxStatus _status
) external view returns (bool);
/// @notice Finalize the withdrawal and release funds.
/// @param _l2BatchNumber The L2 batch number where the withdrawal was processed.
/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message.
/// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent.
/// @param _message The L2 withdraw data, stored in an L2 -> L1 message.
/// @param _merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization.
function finalizeEthWithdrawal(
uint256 _l2BatchNumber,
uint256 _l2MessageIndex,
uint16 _l2TxNumberInBatch,
bytes calldata _message,
bytes32[] calldata _merkleProof
) external;
/// @notice Request execution of L2 transaction from L1.
/// @param _contractL2 The L2 receiver address.
/// @param _l2Value `msg.value` of L2 transaction.
/// @param _calldata The input of the L2 transaction.
/// @param _l2GasLimit Maximum amount of L2 gas that transaction can consume during execution on L2.
/// @param _l2GasPerPubdataByteLimit The maximum amount L2 gas that the operator may charge the user for single byte of pubdata.
/// @param _factoryDeps An array of L2 bytecodes that will be marked as known on L2.
/// @param _refundRecipient The address on L2 that will receive the refund for the transaction.
/// @dev If the L2 deposit finalization transaction fails, the `_refundRecipient` will receive the `_l2Value`.
/// Please note, the contract may change the refund recipient's address to eliminate sending funds to addresses out of control.
/// - If `_refundRecipient` is a contract on L1, the refund will be sent to the aliased `_refundRecipient`.
/// - If `_refundRecipient` is set to `address(0)` and the sender has NO deployed bytecode on L1, the refund will be sent to the `msg.sender` address.
/// - If `_refundRecipient` is set to `address(0)` and the sender has deployed bytecode on L1, the refund will be sent to the aliased `msg.sender` address.
/// @dev The address aliasing of L1 contracts as refund recipient on L2 is necessary to guarantee that the funds are controllable,
/// since address aliasing to the from address for the L2 tx will be applied if the L1 `msg.sender` is a contract.
/// Without address aliasing for L1 contracts as refund recipients they would not be able to make proper L2 tx requests
/// through the Mailbox to use or withdraw the funds from L2, and the funds would be lost.
/// @return canonicalTxHash The hash of the requested L2 transaction. This hash can be used to follow the transaction status.
function requestL2Transaction(
address _contractL2,
uint256 _l2Value,
bytes calldata _calldata,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit,
bytes[] calldata _factoryDeps,
address _refundRecipient
) external payable returns (bytes32 canonicalTxHash);
/// @notice Request execution of L2 transaction through the Bridgehub.
/// @dev Only accessible from L1, this is getting checked in the Bridgehub.
/// @param _request the request for the L2 transaction.
function bridgehubRequestL2Transaction(
BridgehubL2TransactionRequest calldata _request
) external returns (bytes32 canonicalTxHash);
/// @notice The chain's mailbox receives the tx from the Bridgehub on Gateway.
/// @param _canonicalTxHash the canonical transaction hash.
/// @param _expirationTimestamp the expiration timestamp for the transaction.
function bridgehubRequestL2TransactionOnGateway(bytes32 _canonicalTxHash, uint64 _expirationTimestamp) external;
/// @notice Request execution of service L2 transaction from L1.
/// @dev Used for chain configuration. Can be called only by DiamondProxy itself.
/// @param _contractL2 The L2 receiver address.
/// @param _l2Calldata The input of the L2 transaction.
function requestL2ServiceTransaction(
address _contractL2,
bytes calldata _l2Calldata
) external returns (bytes32 canonicalTxHash);
/// @dev On L1 we have to forward to the Gateway's mailbox which sends to the Bridgehub on the Gateway.
/// @param _chainId the chainId of the chain.
/// @param _canonicalTxHash the canonical transaction hash.
/// @param _expirationTimestamp the expiration timestamp.
function requestL2TransactionToGatewayMailbox(
uint256 _chainId,
bytes32 _canonicalTxHash,
uint64 _expirationTimestamp
) external returns (bytes32 canonicalTxHash);
/// @notice Estimates the cost in Ether of requesting execution of an L2 transaction from L1.
/// @param _gasPrice expected L1 gas price at which the user requests the transaction execution.
/// @param _l2GasLimit Maximum amount of L2 gas that transaction can consume during execution on L2.
/// @param _l2GasPerPubdataByteLimit The maximum amount of L2 gas that the operator may charge the user for a single byte of pubdata.
/// @return The estimated ETH spent on L2 gas for the transaction.
function l2TransactionBaseCost(
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external view returns (uint256);
/// @dev Proves that a certain leaf was included as part of the log merkle tree.
/// @dev Warning: this function does not enforce any additional checks on the structure
/// of the leaf. This means that it can accept intermediate nodes of the Merkle tree as a `_leaf` as
/// well as the default "empty" leaves. It is the responsibility of the caller to ensure that the
/// `_leaf` is a hash of a valid leaf.
/// @param _batchNumber The batch number of the leaf to be proven.
/// @param _leafProofMask The leaf proof mask.
/// @param _leaf The leaf to be proven.
/// @param _proof The proof.
function proveL2LeafInclusion(
uint256 _batchNumber,
uint256 _leafProofMask,
bytes32 _leaf,
bytes32[] calldata _proof
) external view returns (bool);
/// @notice New priority request event. Emitted when a request is placed into the priority queue.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
/// @param expirationTimestamp Timestamp up to which priority request should be processed.
/// @param transaction The whole transaction structure that is requested to be executed on L2.
/// @param factoryDeps An array of bytecodes that were shown in the L1 public data.
/// Will be marked as known bytecodes in L2.
event NewPriorityRequest(
uint256 txId,
bytes32 txHash,
uint64 expirationTimestamp,
L2CanonicalTransaction transaction,
bytes[] factoryDeps
);
/// @notice Indexed new priority request event. Emitted when a request is placed into the priority queue.
/// @dev We define a new event similar to NewPriorityRequest, as modifying it could break existing indexers.
/// The indexed txId and txHash helps to simplify external node implementation for fast finality.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
event NewPriorityRequestId(uint256 indexed txId, bytes32 indexed txHash);
/// @notice New relayed priority request event. It is emitted on a chain that is deployed
/// on top of the gateway when it receives a request relayed via the Bridgehub.
/// @dev IMPORTANT: this event most likely will be removed in the future, so
/// no one should rely on it for indexing purposes.
/// @param txId Serial number of the priority operation.
/// @param txHash keccak256 hash of encoded transaction representation.
/// @param expirationTimestamp Timestamp up to which priority request should be processed.
event NewRelayedPriorityTransaction(uint256 txId, bytes32 txHash, uint64 expirationTimestamp);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Merkle} from "./Merkle.sol";
import {Arrays} from "@openzeppelin/contracts-v4/utils/Arrays.sol";
/**
* @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures.
*
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
* stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}.
*
* A tree is defined by the following parameters:
*
* * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth.
* * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree.
* * Hashing function: A cryptographic hash function used to produce internal nodes.
*
* This is a fork of OpenZeppelin's [`MerkleTree`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9af280dc4b45ee5bda96ba47ff829b407eaab67e/contracts/utils/structs/MerkleTree.sol)
* library, with the changes to support dynamic tree growth (doubling the size when full).
*/
library DynamicIncrementalMerkle {
/**
* @dev A complete `bytes32` Merkle tree.
*
* The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup.
*
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
* lead to unexpected behavior.
*
* NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to
* store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or
* {Checkpoints}).
*
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
*/
struct Bytes32PushTree {
uint256 _nextLeafIndex;
bytes32[] _sides;
bytes32[] _zeros;
}
/**
* @dev Initialize a {Bytes32PushTree} using {Hashes-Keccak256} to hash internal nodes.
* The capacity of the tree (i.e. number of leaves) is set to `2**levels`.
*
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
* empty leaves. It should be a value that is not expected to be part of the tree.
*/
function setup(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) {
self._nextLeafIndex = 0;
self._zeros.push(zero);
self._sides.push(bytes32(0));
return bytes32(0);
}
/**
* @dev Resets the tree to a blank state.
* Calling this function on MerkleTree that was already setup and used will reset it to a blank state.
* @param zero The value that represents an empty leaf.
* @return initialRoot The initial root of the tree.
*/
function reset(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) {
self._nextLeafIndex = 0;
uint256 length = self._zeros.length;
for (uint256 i = length; 0 < i; --i) {
self._zeros.pop();
}
length = self._sides.length;
for (uint256 i = length; 0 < i; --i) {
self._sides.pop();
}
self._zeros.push(zero);
self._sides.push(bytes32(0));
return bytes32(0);
}
/**
* @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the
* tree, and the resulting root.
*
* Hashing the leaf before calling this function is recommended as a protection against
* second pre-image attacks.
*/
function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) {
// Cache read
uint256 levels = self._zeros.length - 1;
// Get leaf index
// solhint-disable-next-line gas-increment-by-one
index = self._nextLeafIndex++;
// Check if tree is full.
if (index == 1 << levels) {
bytes32 zero = self._zeros[levels];
bytes32 newZero = Merkle.efficientHash(zero, zero);
self._zeros.push(newZero);
self._sides.push(bytes32(0));
++levels;
}
// Rebuild branch from leaf to root
uint256 currentIndex = index;
bytes32 currentLevelHash = leaf;
bool updatedSides = false;
for (uint32 i = 0; i < levels; ++i) {
// Reaching the parent node, is currentLevelHash the left child?
bool isLeft = currentIndex % 2 == 0;
// If so, next time we will come from the right, so we need to save it
if (isLeft && !updatedSides) {
Arrays.unsafeAccess(self._sides, i).value = currentLevelHash;
updatedSides = true;
}
// Compute the current node hash by using the hash function
// with either its sibling (side) or the zero value for that level.
currentLevelHash = Merkle.efficientHash(
isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value,
isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash
);
// Update node index
currentIndex >>= 1;
}
Arrays.unsafeAccess(self._sides, levels).value = currentLevelHash;
return (index, currentLevelHash);
}
/**
* @dev Tree's root.
*/
function root(Bytes32PushTree storage self) internal view returns (bytes32) {
return Arrays.unsafeAccess(self._sides, self._sides.length - 1).value;
}
/**
* @dev Tree's height (does not include the root node).
*/
function height(Bytes32PushTree storage self) internal view returns (uint256) {
return self._sides.length - 1;
}
}// 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.21;
import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
import {MerkleIndexOrHeightMismatch, MerkleIndexOutOfBounds, MerkleNothingToProve, MerklePathEmpty, MerklePathLengthMismatch, MerklePathOutOfBounds} from "../../common/L1ContractErrors.sol";
/// @author Matter Labs
/// @custom:security-contact [email protected]
library Merkle {
using UncheckedMath for uint256;
/// @dev Calculate Merkle root by the provided Merkle proof.
/// NOTE: When using this function, check that the _path length is equal to the tree height to prevent shorter/longer paths attack
/// however, for chains settling on GW the proof includes the GW proof, so the path increases. See Mailbox for more details.
/// @param _path Merkle path from the leaf to the root
/// @param _index Leaf index in the tree
/// @param _itemHash Hash of leaf content
/// @return The Merkle root
function calculateRoot(
bytes32[] calldata _path,
uint256 _index,
bytes32 _itemHash
) internal pure returns (bytes32) {
uint256 pathLength = _path.length;
_validatePathLengthForSingleProof(_index, pathLength);
bytes32 currentHash = _itemHash;
for (uint256 i; i < pathLength; i = i.uncheckedInc()) {
currentHash = (_index % 2 == 0)
? efficientHash(currentHash, _path[i])
: efficientHash(_path[i], currentHash);
_index /= 2;
}
return currentHash;
}
/// @dev Calculate Merkle root by the provided Merkle proof.
/// @dev NOTE: When using this function, check that the _path length is appropriate to prevent shorter/longer paths attack
/// @param _path Merkle path from the leaf to the root
/// @param _index Leaf index in the tree.
/// @dev NOTE the tree can be joined. In this case the second tree's leaves indexes increase by the number of leaves in the first tree.
/// @param _itemHash Hash of leaf content
/// @return The Merkle root
function calculateRootMemory(
bytes32[] memory _path,
uint256 _index,
bytes32 _itemHash
) internal pure returns (bytes32) {
uint256 pathLength = _path.length;
_validatePathLengthForSingleProof(_index, pathLength);
bytes32 currentHash = _itemHash;
for (uint256 i; i < pathLength; i = i.uncheckedInc()) {
currentHash = (_index % 2 == 0)
? efficientHash(currentHash, _path[i])
: efficientHash(_path[i], currentHash);
_index /= 2;
}
return currentHash;
}
/// @dev Calculate Merkle root by the provided Merkle proof for a range of elements
/// NOTE: When using this function, check that the _startPath and _endPath lengths are equal to the tree height to prevent shorter/longer paths attack
/// @param _startPath Merkle path from the first element of the range to the root
/// @param _endPath Merkle path from the last element of the range to the root
/// @param _startIndex Index of the first element of the range in the tree
/// @param _itemHashes Hashes of the elements in the range
/// @return The Merkle root
function calculateRootPaths(
bytes32[] memory _startPath,
bytes32[] memory _endPath,
uint256 _startIndex,
bytes32[] memory _itemHashes
) internal pure returns (bytes32) {
uint256 pathLength = _startPath.length;
if (pathLength != _endPath.length) {
revert MerklePathLengthMismatch(pathLength, _endPath.length);
}
if (pathLength >= 256) {
revert MerklePathOutOfBounds();
}
uint256 levelLen = _itemHashes.length;
// Edge case: we want to be able to prove an element in a single-node tree.
if (pathLength == 0 && (_startIndex != 0 || levelLen != 1)) {
revert MerklePathEmpty();
}
if (levelLen == 0) {
revert MerkleNothingToProve();
}
if (_startIndex + levelLen > (1 << pathLength)) {
revert MerkleIndexOrHeightMismatch();
}
bytes32[] memory itemHashes = _itemHashes;
for (uint256 level; level < pathLength; level = level.uncheckedInc()) {
uint256 parity = _startIndex % 2;
// We get an extra element on the next level if on the current level elements either
// start on an odd index (`parity == 1`) or end on an even index (`levelLen % 2 == 1`)
uint256 nextLevelLen = levelLen / 2 + (parity | (levelLen % 2));
for (uint256 i; i < nextLevelLen; i = i.uncheckedInc()) {
bytes32 lhs = (i == 0 && parity == 1) ? _startPath[level] : itemHashes[2 * i - parity];
bytes32 rhs = (i == nextLevelLen - 1 && (levelLen - parity) % 2 == 1)
? _endPath[level]
: itemHashes[2 * i + 1 - parity];
itemHashes[i] = efficientHash(lhs, rhs);
}
levelLen = nextLevelLen;
_startIndex /= 2;
}
return itemHashes[0];
}
/// @dev Keccak hash of the concatenation of two 32-byte words
function efficientHash(bytes32 _lhs, bytes32 _rhs) internal pure returns (bytes32 result) {
assembly {
mstore(0x00, _lhs)
mstore(0x20, _rhs)
result := keccak256(0x00, 0x40)
}
}
function _validatePathLengthForSingleProof(uint256 _index, uint256 _pathLength) private pure {
if (_pathLength >= 256) {
revert MerklePathOutOfBounds();
}
if (_index >= (1 << _pathLength)) {
revert MerkleIndexOutOfBounds();
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; // 0xb325f767 error AdminZero(); // 0xca1c3cbc error AlreadyMigrated(); // 0x125d99b0 error BlobHashBlobCommitmentMismatchValue(); // 0xafda12bf error CommitBasedInteropNotSupported(); // 0xc02d3ee3 error ContractNotDeployed(); // 0xdf2c5fa5 error DependencyRootsRollingHashMismatch(bytes32 _expected, bytes32 _actual); // 0xedae13f3 error ExecutedIsNotConsistentWithVerified(uint256 batchesExecuted, uint256 batchesVerified); // 0xc866ff2c error InitialForceDeploymentMismatch(bytes32 forceDeploymentHash, bytes32 initialForceDeploymentHash); // 0xfbd630b8 error InvalidBatchesDataLength(uint256 batchesDataLength, uint256 priorityOpsDataLength); // 0x7a47c9a2 error InvalidChainId(); // 0xc06789fa error InvalidCommitment(); // 0xd2531c15 error InvalidL2DAOutputHash(bytes32 l2DAValidatorOutputHash); // 0x30043900 error InvalidNextLeafIndex(uint256 treeNextLeafIndex, uint256 commitmentNextLeafIndex); // 0xfb1a3b59 error InvalidNumberOfBatchHashes(uint256 batchHashesLength, uint256 expected); // 0xbeb96791 error InvalidNumberOfBlobs(uint256 blobsProvided, uint256 maxBlobsSupported); // 0x5513177c error InvalidPubdataHash(bytes32 fullPubdataHash, bytes32 providedPubdataHash); // 0x5717f940 error InvalidPubdataSource(uint8 pubdataSource); // 0x90f67ecf error InvalidStartIndex(uint256 treeStartIndex, uint256 commitmentStartIndex); // 0x0f67bc0a error InvalidUnprocessedIndex(uint256 treeUnprocessedIndex, uint256 commitmentUnprocessedIndex); // 0x2e89f517 error L1DAValidatorAddressIsZero(); // 0x7fbff2dd error L1DAValidatorInvalidSender(address msgSender); // 0x944bc075 error L2DAValidatorAddressIsZero(); // 0xa969e486 error LocalRootIsZero(); // 0xbdaf7d42 error LocalRootMustBeZero(); // 0x9b5f85eb error MessageRootIsZero(); // 0x2237c426 error MismatchL2DAValidator(); // 0x2c01a4af error MismatchNumberOfLayer1Txs(uint256 numberOfLayer1Txs, uint256 expectedLength); // 0xf9ba09d6 error NotAllBatchesExecuted(); // 0xf05c64c6 error NotChainAdmin(address prevMsgSender, address admin); // 0x8fd63d21 error NotEraChain(); // 0xa7050bf6 error NotHistoricalRoot(bytes32); // 0x32ddf9a2 error NotHyperchain(); // 0x87470e36 error NotL1(uint256 blockChainId); // 0xd7b2559b error NotMigrated(); // 0xd0266e26 error NotSettlementLayer(); // 0x04e05fd1 error OnlyOneBlobWithCalldataAllowed(); // 0x885ae069 error OperatorDAInputTooSmall(uint256 operatorDAInputLength, uint256 minAllowedLength); // 0x681150be error OutdatedProtocolVersion(uint256 protocolVersion, uint256 currentProtocolVersion); // 0xc59d372c error ProtocolVersionNotUpToDate(uint256 currentProtocolVersion, uint256 protocolVersion); // 0x2dc9747d error PubdataInputTooSmall(uint256 pubdataInputLength, uint256 totalBlobsCommitmentSize); // 0x9044dff9 error PubdataLengthTooBig(uint256 pubdataLength, uint256 totalBlobSizeBytes); // 0x79274f04 error UnsupportedProofMetadataVersion(uint256 metadataVersion); // 0x52595598 error ValL1DAWrongInputLength(uint256 inputLength, uint256 expectedLength); // 0x712d02d2 error VerifiedIsNotConsistentWithCommitted(uint256 batchesVerified, uint256 batchesCommitted);
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Arrays.sol)
pragma solidity ^0.8.0;
import "./StorageSlot.sol";
import "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
if (array.length == 0) {
return 0;
}
uint256 low = 0;
uint256 high = array.length;
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}{
"remappings": [
"@ensdomains/=node_modules/@ensdomains/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat/=node_modules/hardhat/",
"murky/=lib/murky/src/",
"foundry-test/=test/foundry/",
"l2-contracts/=../l2-contracts/contracts/",
"@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/",
"@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable-v4/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/",
"openzeppelin-contracts-v4/=lib/openzeppelin-contracts-v4/",
"openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 9999999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_l1ChainId","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_maxNumberOfZKChains","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"blockChainId","type":"uint256"}],"name":"AlreadyCurrentSL","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"AssetHandlerNotRegistered","type":"error"},{"inputs":[],"name":"AssetIdAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"AssetIdNotSupported","type":"error"},{"inputs":[],"name":"BridgeHubAlreadyRegistered","type":"error"},{"inputs":[],"name":"CTMAlreadyRegistered","type":"error"},{"inputs":[],"name":"CTMNotRegistered","type":"error"},{"inputs":[],"name":"ChainIdAlreadyExists","type":"error"},{"inputs":[],"name":"ChainIdAlreadyPresent","type":"error"},{"inputs":[],"name":"ChainIdCantBeCurrentChain","type":"error"},{"inputs":[],"name":"ChainIdMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainIdNotRegistered","type":"error"},{"inputs":[],"name":"ChainIdTooBig","type":"error"},{"inputs":[],"name":"ChainNotLegacy","type":"error"},{"inputs":[],"name":"ChainNotPresentInCTM","type":"error"},{"inputs":[],"name":"EmptyAssetId","type":"error"},{"inputs":[{"internalType":"address","name":"bridgehub","type":"address"}],"name":"IncorrectBridgeHubAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedMsgValue","type":"uint256"},{"internalType":"uint256","name":"providedMsgValue","type":"uint256"}],"name":"MsgValueMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"NoCTMForAssetId","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"chainAssetHandler","type":"address"}],"name":"NotChainAssetHandler","type":"error"},{"inputs":[{"internalType":"uint256","name":"settlementLayerChainId","type":"uint256"},{"internalType":"uint256","name":"blockChainId","type":"uint256"}],"name":"NotCurrentSL","type":"error"},{"inputs":[],"name":"NotInGatewayMode","type":"error"},{"inputs":[],"name":"NotInitializedReentrancyGuard","type":"error"},{"inputs":[{"internalType":"uint256","name":"l1ChainId","type":"uint256"},{"internalType":"uint256","name":"blockChainId","type":"uint256"}],"name":"NotL1","type":"error"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"address","name":"settlementLayerRelaySender","type":"address"}],"name":"NotRelayedSender","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SLNotWhitelisted","type":"error"},{"inputs":[{"internalType":"address","name":"secondBridgeAddress","type":"address"},{"internalType":"address","name":"minSecondBridgeAddress","type":"address"}],"name":"SecondBridgeAddressTooLow","type":"error"},{"inputs":[],"name":"SettlementLayersMustSettleOnL1","type":"error"},{"inputs":[],"name":"SharedBridgeNotSet","type":"error"},{"inputs":[],"name":"SlotOccupied","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedMagicValue","type":"uint256"},{"internalType":"uint256","name":"providedMagicValue","type":"uint256"}],"name":"WrongMagicValue","type":"error"},{"inputs":[],"name":"ZKChainLimitReached","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroChainId","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetInfo","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_assetAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"additionalData","type":"bytes32"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AssetRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetId","type":"bytes32"}],"name":"BaseTokenAssetIdRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chainTypeManager","type":"address"}],"name":"ChainTypeManagerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chainTypeManager","type":"address"}],"name":"ChainTypeManagerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"chainTypeManager","type":"address"},{"indexed":true,"internalType":"address","name":"chainGovernance","type":"address"}],"name":"NewChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isWhitelisted","type":"bool"}],"name":"SettlementLayerRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"L1_CHAIN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NUMBER_OF_ZK_CHAINS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainTypeManager","type":"address"}],"name":"addChainTypeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_baseTokenAssetId","type":"bytes32"}],"name":"addTokenAssetId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"baseTokenAssetId","type":"bytes32"}],"name":"assetIdIsRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"baseToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"baseTokenAssetId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainAssetHandler","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"chainTypeManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"chainTypeManager","type":"address"}],"name":"chainTypeManagerIsRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_chainTypeManager","type":"address"},{"internalType":"bytes32","name":"_baseTokenAssetId","type":"bytes32"},{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"bytes","name":"_initData","type":"bytes"},{"internalType":"bytes[]","name":"_factoryDeps","type":"bytes[]"}],"name":"createNewChain","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ctmAddress","type":"address"}],"name":"ctmAssetIdFromAddress","outputs":[{"internalType":"bytes32","name":"ctmAssetId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"ctmAssetIdFromChainId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ctmAssetId","type":"bytes32"}],"name":"ctmAssetIdToAddress","outputs":[{"internalType":"address","name":"ctmAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"bytes32","name":"_canonicalTxHash","type":"bytes32"},{"internalType":"uint64","name":"_expirationTimestamp","type":"uint64"}],"name":"forwardTransactionOnGateway","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"uint256","name":"_newSettlementLayerChainId","type":"uint256"}],"name":"forwardedBridgeBurnSetSettlementLayer","outputs":[{"internalType":"address","name":"zkChain","type":"address"},{"internalType":"address","name":"ctm","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_assetId","type":"bytes32"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"bytes32","name":"_baseTokenAssetId","type":"bytes32"}],"name":"forwardedBridgeMint","outputs":[{"internalType":"address","name":"zkChain","type":"address"},{"internalType":"address","name":"ctm","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"forwardedBridgeRecoverFailedTransfer","outputs":[{"internalType":"address","name":"zkChain","type":"address"},{"internalType":"address","name":"ctm","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllZKChainChainIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllZKChains","outputs":[{"internalType":"address[]","name":"chainAddresses","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"getHyperchain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"getZKChain","outputs":[{"internalType":"address","name":"chainAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1CtmDeployer","outputs":[{"internalType":"contract ICTMDeploymentTracker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"uint256","name":"_gasPrice","type":"uint256"},{"internalType":"uint256","name":"_l2GasLimit","type":"uint256"},{"internalType":"uint256","name":"_l2GasPerPubdataByteLimit","type":"uint256"}],"name":"l2TransactionBaseCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageRoot","outputs":[{"internalType":"contract IMessageRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"bytes32","name":"_l2TxHash","type":"bytes32"},{"internalType":"uint256","name":"_l2BatchNumber","type":"uint256"},{"internalType":"uint256","name":"_l2MessageIndex","type":"uint256"},{"internalType":"uint16","name":"_l2TxNumberInBatch","type":"uint16"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"enum TxStatus","name":"_status","type":"uint8"}],"name":"proveL1ToL2TransactionStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"uint256","name":"_batchNumber","type":"uint256"},{"internalType":"uint256","name":"_index","type":"uint256"},{"components":[{"internalType":"uint8","name":"l2ShardId","type":"uint8"},{"internalType":"bool","name":"isService","type":"bool"},{"internalType":"uint16","name":"txNumberInBatch","type":"uint16"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32","name":"value","type":"bytes32"}],"internalType":"struct L2Log","name":"_log","type":"tuple"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"proveL2LogInclusion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"uint256","name":"_batchNumber","type":"uint256"},{"internalType":"uint256","name":"_index","type":"uint256"},{"components":[{"internalType":"uint16","name":"txNumberInBatch","type":"uint16"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct L2Message","name":"_message","type":"tuple"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"proveL2MessageInclusion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_zkChain","type":"address"}],"name":"registerAlreadyDeployedZKChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"registerLegacyChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_zkChain","type":"address"},{"internalType":"bool","name":"_checkMaxNumberOfZKChains","type":"bool"}],"name":"registerNewZKChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newSettlementLayerChainId","type":"uint256"},{"internalType":"bool","name":"_isWhitelisted","type":"bool"}],"name":"registerSettlementLayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainTypeManager","type":"address"}],"name":"removeChainTypeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"mintValue","type":"uint256"},{"internalType":"address","name":"l2Contract","type":"address"},{"internalType":"uint256","name":"l2Value","type":"uint256"},{"internalType":"bytes","name":"l2Calldata","type":"bytes"},{"internalType":"uint256","name":"l2GasLimit","type":"uint256"},{"internalType":"uint256","name":"l2GasPerPubdataByteLimit","type":"uint256"},{"internalType":"bytes[]","name":"factoryDeps","type":"bytes[]"},{"internalType":"address","name":"refundRecipient","type":"address"}],"internalType":"struct L2TransactionRequestDirect","name":"_request","type":"tuple"}],"name":"requestL2TransactionDirect","outputs":[{"internalType":"bytes32","name":"canonicalTxHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"mintValue","type":"uint256"},{"internalType":"uint256","name":"l2Value","type":"uint256"},{"internalType":"uint256","name":"l2GasLimit","type":"uint256"},{"internalType":"uint256","name":"l2GasPerPubdataByteLimit","type":"uint256"},{"internalType":"address","name":"refundRecipient","type":"address"},{"internalType":"address","name":"secondBridgeAddress","type":"address"},{"internalType":"uint256","name":"secondBridgeValue","type":"uint256"},{"internalType":"bytes","name":"secondBridgeCalldata","type":"bytes"}],"internalType":"struct L2TransactionRequestTwoBridgesOuter","name":"_request","type":"tuple"}],"name":"requestL2TransactionTwoBridges","outputs":[{"internalType":"bytes32","name":"canonicalTxHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_assetRouter","type":"address"},{"internalType":"contract ICTMDeploymentTracker","name":"_l1CtmDeployer","type":"address"},{"internalType":"contract IMessageRoot","name":"_messageRoot","type":"address"},{"internalType":"address","name":"_chainAssetHandler","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_additionalData","type":"bytes32"},{"internalType":"address","name":"_assetAddress","type":"address"}],"name":"setCTMAssetAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainAssetHandler","type":"address"}],"name":"setChainAssetHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPendingAdmin","type":"address"}],"name":"setPendingAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"settlementLayer","outputs":[{"internalType":"uint256","name":"activeSettlementLayerChainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sharedBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"whitelistedSettlementLayers","outputs":[{"internalType":"bool","name":"isWhitelistedSettlementLayer","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60e060405234801561000f575f5ffd5b50604051615bc2380380615bc283398101604081905261002e91610263565b6100366100a4565b61003e6100ee565b60a083905260c08190526100538360016101aa565b60805261005f826101fe565b61009c6080515f90815260da602090815260408083208054600160ff19918216811790925560a051855260d9909352922080549091169091179055565b5050506102d1565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf48054600190915580156100eb5760405163df3a8fdd60e01b815260040160405180910390fd5b50565b5f54610100900460ff16156101595760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146101a8575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f826101ba6201000060046102a6565b6040805160208101939093526001600160a01b0391821690830152831660608201526080016040516020818303038152906040528051906020012090505b92915050565b606580546001600160a01b03191690556100eb81603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f5f5f60608486031215610275575f5ffd5b835160208501519093506001600160a01b0381168114610293575f5ffd5b6040949094015192959394509192915050565b6001600160a01b0381811683821601908111156101f857634e487b7160e01b5f52601160045260245ffd5b60805160a05160c0516158186103aa5f395f81816107fb0152613fec01525f81816105380152818161131801528181611364015281816118b8015281816119d901528181611c0101528181611c4d0152818161227a0152818161261c01528181612668015281816126fa01528181612c2e01528181612c7a01528181613161015281816131ad01528181613248015281816133430152818161338f015281816136400152818161368c0152818161393a015261398601525f818161143a0152818161269c015281816131ea01526133d301526158185ff3fe608060405260043610610371575f3560e01c806379ba5097116101c8578063d4b9f4fa116100fd578063e680c4c11161009d578063f2fde38b1161006d578063f2fde38b14610b1e578063f7c7eb9214610b3d578063f851a44014610b51578063ff5a62a114610b7d575f5ffd5b8063e680c4c114610a93578063e6d9923b14610ab2578063e9420f8c14610ad1578063f113c88b14610aff575f5ffd5b8063dead6f7f116100d8578063dead6f7f146109f1578063e0ab636814610a10578063e30c397814610a3e578063e52db4ca14610a68575f5ffd5b8063d4b9f4fa14610993578063d52471c1146109bf578063dc8e4b26146109d2575f5ffd5b8063ac700e6311610168578063b93c936611610143578063b93c9366146108ee578063bc0aac101461091c578063c4d66de814610948578063cbe8361214610967575f5ffd5b8063ac700e631461089c578063b292f5f1146108b0578063b5662c5d146108cf575f5ffd5b80638f8d37a8116101a35780638f8d37a8146107ea57806399c16d1a1461081d5780639d5bd3da1461083c5780639f115e381461087d575f5ffd5b806379ba5097146107985780638456cb59146107ac5780638da5cb5b146107c0575f5ffd5b80633f4ba83a116102a95780635cd8a76b1161024957806370d8af871161021957806370d8af871461070957806370fccb521461073a578063715018a6146107655780637162327414610779575f5ffd5b80635cd8a76b1461068a578063671a71311461069e57806368b8d331146106c95780637011be85146106ea575f5ffd5b80634dd18bf5116102845780634dd18bf514610616578063524c0cfa1461063557806359ec65a2146106545780635c975abb14610673575f5ffd5b80633f4ba83a146105c257806349707f31146105d65780634a945f8d146105f7575f5ffd5b806324fd57fb116103145780632f90b184116102ef5780632f90b18414610527578063332b96dc1461055a57806338720778146105795780633885a750146105a3575f5ffd5b806324fd57fb146104cc5780632a641114146104df5780632dbcf55f14610508575f5ffd5b806317fa37511161034f57806317fa3751146104425780631c50cfea1461046157806322f3a9ba1461048057806324358c611461049f575f5ffd5b80630641e4f71461037557806307621f84146103c65780630e18b6811461042c575b5f5ffd5b348015610380575f5ffd5b5061039461038f3660046147ed565b610b9c565b6040805173ffffffffffffffffffffffffffffffffffffffff9384168152929091166020830152015b60405180910390f35b3480156103d1575f5ffd5b506104076103e036600461480d565b60d66020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103bd565b348015610437575f5ffd5b50610440610d57565b005b34801561044d575f5ffd5b5061039461045c366004614824565b610e85565b34801561046c575f5ffd5b5061044061047b36600461480d565b611055565b34801561048b575f5ffd5b5061044061049a36600461487e565b611176565b3480156104aa575f5ffd5b506104be6104b936600461480d565b6111ca565b6040519081526020016103bd565b6104be6104da3660046148b0565b611252565b3480156104ea575f5ffd5b5060db546104f89060ff1681565b60405190151581526020016103bd565b348015610513575f5ffd5b506104406105223660046148e2565b6118b4565b348015610532575f5ffd5b506104be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610565575f5ffd5b5061044061057436600461487e565b611ad8565b348015610584575f5ffd5b5060c95473ffffffffffffffffffffffffffffffffffffffff16610407565b3480156105ae575f5ffd5b506104406105bd36600461480d565b611bfe565b3480156105cd575f5ffd5b50610440611f48565b3480156105e1575f5ffd5b506105ea611f5a565b6040516103bd9190614910565b348015610602575f5ffd5b50610440610611366004614968565b61202e565b348015610621575f5ffd5b5061044061063036600461487e565b6120d2565b348015610640575f5ffd5b5061044061064f3660046149c1565b61220e565b34801561065f575f5ffd5b5061040761066e36600461480d565b612370565b34801561067e575f5ffd5b5060975460ff166104f8565b348015610695575f5ffd5b506104406124fa565b3480156106a9575f5ffd5b506104be6106b836600461480d565b60d86020525f908152604090205481565b3480156106d4575f5ffd5b506106dd612791565b6040516103bd9190614a03565b3480156106f5575f5ffd5b50610440610704366004614a47565b6127a2565b348015610714575f5ffd5b5060db5461040790610100900473ffffffffffffffffffffffffffffffffffffffff1681565b348015610745575f5ffd5b506104be61075436600461487e565b60d76020525f908152604090205481565b348015610770575f5ffd5b5061044061282e565b348015610784575f5ffd5b506104be610793366004614a7b565b61283f565b3480156107a3575f5ffd5b506104406128f4565b3480156107b7575f5ffd5b506104406129a6565b3480156107cb575f5ffd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610407565b3480156107f5575f5ffd5b506104be7f000000000000000000000000000000000000000000000000000000000000000081565b348015610828575f5ffd5b506104f8610837366004614aeb565b6129b6565b348015610847575f5ffd5b5061040761085636600461480d565b60cc6020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b348015610888575f5ffd5b5061039461089736600461480d565b612a6b565b3480156108a7575f5ffd5b50610440612b33565b3480156108bb575f5ffd5b506104f86108ca366004614b86565b612b68565b3480156108da575f5ffd5b506104406108e93660046148e2565b612c23565b3480156108f9575f5ffd5b506104f861090836600461487e565b60ca6020525f908152604090205460ff1681565b348015610927575f5ffd5b5060c9546104079073ffffffffffffffffffffffffffffffffffffffff1681565b348015610953575f5ffd5b5061044061096236600461487e565b613156565b348015610972575f5ffd5b5060d5546104079073ffffffffffffffffffffffffffffffffffffffff1681565b34801561099e575f5ffd5b5060d3546104079073ffffffffffffffffffffffffffffffffffffffff1681565b6104be6109cd3660046148b0565b61327d565b3480156109dd575f5ffd5b506104406109ec366004614c11565b613635565b3480156109fc575f5ffd5b50610407610a0b36600461480d565b61376d565b348015610a1b575f5ffd5b506104f8610a2a36600461480d565b60da6020525f908152604090205460ff1681565b348015610a49575f5ffd5b5060655473ffffffffffffffffffffffffffffffffffffffff16610407565b348015610a73575f5ffd5b506104be610a8236600461480d565b60d46020525f908152604090205481565b348015610a9e575f5ffd5b50610407610aad36600461480d565b61377d565b348015610abd575f5ffd5b506104f8610acc366004614c34565b613790565b348015610adc575f5ffd5b506104f8610aeb36600461480d565b60d96020525f908152604090205460ff1681565b348015610b0a575f5ffd5b506104be610b19366004614cad565b6137fa565b348015610b29575f5ffd5b50610440610b3836600461487e565b613bbd565b348015610b48575f5ffd5b50610440613c6d565b348015610b5c575f5ffd5b5060ce546104079073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b88575f5ffd5b50610440610b9736600461487e565b613c9f565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314610c215760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b5f83815260d9602052604090205460ff16610c68576040517f90c7cbf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260d860205260409020544614610cc7575f84815260d86020526040908190205490517fc0ca91820000000000000000000000000000000000000000000000000000000081526004810191909152466024820152604401610c18565b5f84815260d86020908152604080832086905560d990915290205460ff1615610d1c576040517f02181a1300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d2760d085613dc9565b5f94855260cc602052604090942054939473ffffffffffffffffffffffffffffffffffffffff9094169392505050565b60cf5473ffffffffffffffffffffffffffffffffffffffff16338114610dab576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b60ce805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000808416821790945560cf80549094169093556040519116915f917fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9908390a38173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc60405160405180910390a35050565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314610f055760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b505f84815260d6602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610f64576040517fce63ce1700000000000000000000000000000000000000000000000000000000815260048101869052602401610c18565b5f84815260d86020526040902054469003610fad576040517f587df426000000000000000000000000000000000000000000000000000000008152466004820152602401610c18565b5f84815260d86020908152604080832046905560cc825280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861617905560d4825280832086905585835260da909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561104b8461377d565b9150935093915050565b60ce5473ffffffffffffffffffffffffffffffffffffffff163314801590611095575060335473ffffffffffffffffffffffffffffffffffffffff163314155b156110ce576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b5f81815260da602052604090205460ff1615611116576040517ffe919e2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260da602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555182917f3df150949161462acf3be30521d7da9e533b247327a254e55dd01875897a6df391a250565b61117e613dd4565b60db805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b5f81815260cc602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611228576040517f23f3c35700000000000000000000000000000000000000000000000000000000815260048101849052602401610c18565b73ffffffffffffffffffffffffffffffffffffffff165f90815260d7602052604090205492915050565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f908082036112af576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181146112e9576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455611315613e55565b467f000000000000000000000000000000000000000000000000000000000000000014611396576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b61ffff6113a960e0850160c0860161487e565b73ffffffffffffffffffffffffffffffffffffffff1611611427576113d460e0840160c0850161487e565b6040517fb78dbaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015261ffff6024820152604401610c18565b82355f90815260d46020526040812054907f000000000000000000000000000000000000000000000000000000000000000082036114d05761147160e08601356020870135614dba565b34146114c55761148960e08601356020870135614dba565b6040517f4a0944310000000000000000000000000000000000000000000000000000000081526004810191909152346024820152604401610c18565b50602084013561151c565b8460e001353414611519576040517f4a09443100000000000000000000000000000000000000000000000000000000815260e08601356004820152346024820152604401610c18565b505f5b60c9546040517fc487944000000000000000000000000000000000000000000000000000000000815286356004820152602481018490523360448201526020870135606482015273ffffffffffffffffffffffffffffffffffffffff9091169063c48794409083906084015f604051808303818588803b15801561159e575f5ffd5b505af11580156115b0573d5f5f3e3d5ffd5b505050505050505f8360c00160208101906115cb919061487e565b73ffffffffffffffffffffffffffffffffffffffff1663ca408c2360e086013586353360408901356116016101008b018b614dcd565b6040518763ffffffff1660e01b8152600401611621959493929190614e75565b5f6040518083038185885af115801561163c573d5f5f3e3d5ffd5b50505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611682919081019061501a565b90506116af60017fa175e001c0e5684bc26302c2f9a55aec9f3936fe2aef558034003ef4da7fc77e615151565b81511461171e576116e160017fa175e001c0e5684bc26302c2f9a55aec9f3936fe2aef558034003ef4da7fc77e615151565b81516040517f15e8e42900000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c18565b6117e6843561173360c0870160a0880161487e565b6040805161012081019091528061175060e08a0160c08b0161487e565b73ffffffffffffffffffffffffffffffffffffffff168152602001856020015173ffffffffffffffffffffffffffffffffffffffff1681526020018860200135815260200188604001358152602001856040015181526020018860600135815260200188608001358152602001856060015181526020015f73ffffffffffffffffffffffffffffffffffffffff16815250613ec2565b92506117f860e0850160c0860161487e565b60808201516040517f8eb7db570000000000000000000000000000000000000000000000000000000081528635600482015260248101919091526044810185905273ffffffffffffffffffffffffffffffffffffffff9190911690638eb7db57906064015f604051808303815f87803b158015611873575f5ffd5b505af1158015611885573d5f5f3e3d5ffd5b505050505060017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45550919050565b5f467f000000000000000000000000000000000000000000000000000000000000000014611904577fffffffffffffffffffffffffeeeeffffffffffffffffffffffffffffffffeeef3301611906565b335b60d55490915073ffffffffffffffffffffffffffffffffffffffff808316911614611975576040517f8e4a23d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610c18565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260ca602052604090205460ff166119d3576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517f000000000000000000000000000000000000000000000000000000000000000060208083019190915273ffffffffffffffffffffffffffffffffffffffff841682840152606080830187905283518084039091018152608090920190925280519101205f905f81815260d66020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915580845260d783529281902084905551338152929350869284917f8f09d7694a9ae17acec5cf132d594d7eee23572f7fe132396ce72b1afbf7ef20910160405180910390a450505050565b611ae0613dd4565b73ffffffffffffffffffffffffffffffffffffffff8116611b2d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff16611b8b576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f81815260ca602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f4e04a497739580efe78a7ee09cdabe6f6fe90965c683292a519102ce5193b68a9190a250565b467f000000000000000000000000000000000000000000000000000000000000000014611c7f576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b5f81815260cc602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611cda576040517f5de7210700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ce560d083613f6a565b15611d1c576040517fff514c1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260cd602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611d77576040517f5de7210700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611d824683613f75565b5f85815260d46020908152604080832084905583835260da90915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f4caa740f000000000000000000000000000000000000000000000000000000008152600481018790529192509073ffffffffffffffffffffffffffffffffffffffff851690634caa740f90602401602060405180830381865afa158015611e34573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e589190615164565b905073ffffffffffffffffffffffffffffffffffffffff8116611ea7576040517f4bd4ae0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611eb285825f613fd5565b60d3546040517fd4ce08c20000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b158015611f1b575f5ffd5b505af1158015611f2d573d5f5f3e3d5ffd5b5050505f958652505060d86020525050604090912046905550565b611f50613dd4565b611f5861404e565b565b60605f611f6760d06140cb565b9050805167ffffffffffffffff811115611f8357611f83614ebb565b604051908082528060200260200182016040528015611fac578160200160208202803683370190505b5081519092505f5b8181101561202857611fe9838281518110611fd157611fd161517f565b602002602001015160d0613dc990919063ffffffff16565b848281518110611ffb57611ffb61517f565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152600101611fb4565b50505090565b612036613dd4565b60c9805473ffffffffffffffffffffffffffffffffffffffff9586167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560d580549486169482169490941790935560d38054928516929093169190911790915560db805491909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909116179055565b60ce5473ffffffffffffffffffffffffffffffffffffffff163314801590612112575060335473ffffffffffffffffffffffffffffffffffffffff163314155b1561214b576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b73ffffffffffffffffffffffffffffffffffffffff8116612198576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9905f90a35050565b3373111111111111111111111111111111111111111114612277576040517fa2ac02a00000000000000000000000000000000000000000000000000000000081523360048201527311111111111111111111111111111111111111116024820152604401610c18565b467f0000000000000000000000000000000000000000000000000000000000000000036122d0576040517f472477e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6122dc60d085613dc9565b6040517fddcc9eec0000000000000000000000000000000000000000000000000000000081526004810185905267ffffffffffffffff8416602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063ddcc9eec906044015f604051808303815f87803b158015612354575f5ffd5b505af1158015612366573d5f5f3e3d5ffd5b5050505050505050565b5f81815260d460205260408082205460c95491517f53b9e632000000000000000000000000000000000000000000000000000000008152600481018290529091839173ffffffffffffffffffffffffffffffffffffffff909116906353b9e63290602401602060405180830381865afa1580156123ef573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124139190615164565b905073ffffffffffffffffffffffffffffffffffffffff8116612465576040517f6410796800000000000000000000000000000000000000000000000000000000815260048101839052602401610c18565b6040517f97bb3ce90000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216906397bb3ce990602401602060405180830381865afa1580156124ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f29190615164565b949350505050565b5f54610100900460ff161580801561251857505f54600160ff909116105b806125315750303b15801561253157505f5460ff166001145b6125bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c18565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015612619575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b467f00000000000000000000000000000000000000000000000000000000000000001461269a576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b7f00000000000000000000000000000000000000000000000000000000000000005f90815260da60209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0000000000000000000000000000000000000000000000000000000000000000855260d9909352922080549091169091179055801561278e575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b606061279d60d06140cb565b905090565b60db54610100900473ffffffffffffffffffffffffffffffffffffffff16331461281e5760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b612829838383613fd5565b505050565b612836613dd4565b611f585f6140d7565b5f8061284c60d087613dc9565b6040517fb473318e00000000000000000000000000000000000000000000000000000000815260048101879052602481018690526044810185905290915073ffffffffffffffffffffffffffffffffffffffff82169063b473318e90606401602060405180830381865afa1580156128c6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128ea91906151ac565b9695505050505050565b606554339073ffffffffffffffffffffffffffffffffffffffff16811461299d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610c18565b61278e816140d7565b6129ae613dd4565b611f58614108565b5f806129c360d089613dc9565b6040517fe4948f4300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063e4948f4390612a20908a908a908a908a908a9060040161526c565b602060405180830381865afa158015612a3b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5f91906152f0565b98975050505050505050565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314612aeb5760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b5f83815260d860205260409020469055612b048361377d565b5f93845260cc602052604090932054929373ffffffffffffffffffffffffffffffffffffffff90931692915050565b612b3b613dd4565b60db80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f80612b7560d08b613dc9565b6040517f042901c700000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063042901c790612bd6908c908c908c908c908c908c908c9060040161530b565b602060405180830381865afa158015612bf1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1591906152f0565b9a9950505050505050505050565b612c2b613dd4565b467f000000000000000000000000000000000000000000000000000000000000000014612cac576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b73ffffffffffffffffffffffffffffffffffffffff8116612cf9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d0460d083613f6a565b15612d3b576040517f24591d8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff16633408e4706040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d85573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612da991906151ac565b14612de0576040517fa179f8c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff1663946ebad16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4e9190615164565b90505f8273ffffffffffffffffffffffffffffffffffffffff16636e9960c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e9a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ebe9190615164565b90505f8373ffffffffffffffffffffffffffffffffffffffff1663960dcf246040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f2e91906151ac565b90505f8473ffffffffffffffffffffffffffffffffffffffff16633591c1a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f9e9190615164565b905073ffffffffffffffffffffffffffffffffffffffff81163014613007576040517fdd381a4c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610c18565b613012868386614163565b5f86815260cc6020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891617905560d4825280832085905560d8909152902046905561308086866001613fd5565b60d3546040517fd4ce08c20000000000000000000000000000000000000000000000000000000081526004810188905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b1580156130e9575f5ffd5b505af11580156130fb573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff8781168252861692508891507f1e9125bc72db22c58abff6821d7333551967e26454b419ffa958e4cb8ef476009060200160405180910390a3505050505050565b61315e6143eb565b467f0000000000000000000000000000000000000000000000000000000000000000146131df576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b6131e8816140d7565b7f00000000000000000000000000000000000000000000000000000000000000005f90815260da60209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0000000000000000000000000000000000000000000000000000000000000000855260d990935292208054909116909117905550565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f908082036132da576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018114613314576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455613340613e55565b467f0000000000000000000000000000000000000000000000000000000000000000146133c1576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b82355f90815260d460205260409020547f000000000000000000000000000000000000000000000000000000000000000081036134465783602001353414613441576040517f4a09443100000000000000000000000000000000000000000000000000000000815260208501356004820152346024820152604401610c18565b613486565b3415613486576040517f4a0944310000000000000000000000000000000000000000000000000000000081525f6004820152346024820152604401610c18565b60c9546040517fc487944000000000000000000000000000000000000000000000000000000000815285356004820152602481018390523360448201526020860135606482015273ffffffffffffffffffffffffffffffffffffffff9091169063c48794409034906084015f604051808303818588803b158015613508575f5ffd5b505af115801561351a573d5f5f3e3d5ffd5b5061360a9450508635925061353a9150506101208601610100870161487e565b604080516101208101825233815290602082019061355e9060608a01908a0161487e565b73ffffffffffffffffffffffffffffffffffffffff168152602088810135908201526060808901356040830152016135996080890189614dcd565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050509082525060a0880135602082015260c088013560408201526060016135f360e0890189615383565b6135fc916153e7565b81525f602090910152613ec2565b60017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4559392505050565b61363d613dd4565b467f0000000000000000000000000000000000000000000000000000000000000000146136be576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b5f82815260d860205260409020544614613704576040517f02181a1300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260d9602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168415159081179091559051909184917f02629feb109d94b16a367231d248ba81c462f51ce5b984835f150f1c9f49ed259190a35050565b5f6137778261377d565b92915050565b5f61378960d08361444b565b9392505050565b5f8061379d60d089613dc9565b6040517f263b7f8e00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063263b7f8e90612a20908a908a908a908a908a9060040161548a565b60ce545f9073ffffffffffffffffffffffffffffffffffffffff16331480159061383c575060335473ffffffffffffffffffffffffffffffffffffffff163314155b15613875576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f8190036138d1576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811461390b576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455613937613e55565b467f0000000000000000000000000000000000000000000000000000000000000000146139b8576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c18565b6139c38b8a8c614163565b5f8b815260cc6020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8f1690811790915560d483528184208d905560d8909252808320469055517f88c7c5d20000000000000000000000000000000000000000000000000000000081526388c7c5d290613a6d908f908e908d908d908d908d908d9060040161552a565b6020604051808303815f875af1158015613a89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613aad9190615164565b9050613abb8c826001613fd5565b60d3546040517fd4ce08c2000000000000000000000000000000000000000000000000000000008152600481018e905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b158015613b24575f5ffd5b505af1158015613b36573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff8e811682528b1692508e91507f1e9125bc72db22c58abff6821d7333551967e26454b419ffa958e4cb8ef476009060200160405180910390a3505060017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455509798975050505050505050565b613bc5613dd4565b6065805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155613c2860335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b613c75613dd4565b60db80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b613ca7613dd4565b73ffffffffffffffffffffffffffffffffffffffff8116613cf4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff1615613d53576040517fec27343900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f81815260ca602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f2eae91be1021e05cc8076387b0182458ae474ae44ee44cc59aefda6ca53c1f429190a250565b5f6137898383614468565b60335473ffffffffffffffffffffffffffffffffffffffff163314611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c18565b60975460ff1615611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c18565b5f5f613ece84336144f1565b73ffffffffffffffffffffffffffffffffffffffff811661010085015290505f613ef960d087613dc9565b6040517f12f43dab00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8216906312f43dab90613f4e9087906004016156b3565b6020604051808303815f875af11580156128c6573d5f5f3e3d5ffd5b5f613789838361458f565b5f82613f856201000060046157b6565b60408051602081019390935273ffffffffffffffffffffffffffffffffffffffff918216908301528316606082015260800160405160208183030381529060405280519060200120905092915050565b613fe160d0848461459a565b5080801561401757507f000000000000000000000000000000000000000000000000000000000000000061401560d06145bc565b115b15612829576040517f601b688200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6140566145c6565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60605f61378983614632565b606580547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561278e8161463d565b614110613e55565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586140a13390565b825f0361419c576040517fc84885d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b65ffffffffffff8311156141dc576040517f8f620a0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468303614215576040517f717a165600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116614262576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81614299576040517f2d4d012f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff166142f7576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260da602052604090205460ff16614341576040517f04a0b7e900000000000000000000000000000000000000000000000000000000815260048101839052602401610c18565b60c95473ffffffffffffffffffffffffffffffffffffffff16614390576040517f856d5b7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f83815260cc602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612829576040517f6cf1231200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf480546001909155801561278e576040517fdf3a8fdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808061445986866146b3565b909450925050505b9250929050565b5f8181526002830160205260408120548015158061448b575061448b848461458f565b613789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610c18565b5f73ffffffffffffffffffffffffffffffffffffffff831661454f5773ffffffffffffffffffffffffffffffffffffffff82163214614546577311110000000000000000000000000000000011118201614548565b815b9050613777565b73ffffffffffffffffffffffffffffffffffffffff83163b15614588577311110000000000000000000000000000000011118301614548565b5090919050565b5f61378983836146eb565b5f6124f2848473ffffffffffffffffffffffffffffffffffffffff8516614702565b5f6137778261471e565b60975460ff16611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c18565b606061377782614728565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f8181526002830160205260408120548190806146e0576146d4858561458f565b92505f91506144619050565b600192509050614461565b5f8181526001830160205260408120541515613789565b5f82815260028401602052604081208290556124f28484614734565b5f6137778261473f565b60605f61378983614748565b5f61378983836147a1565b5f613777825490565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561479557602002820191905f5260205f20905b815481526020019060010190808311614781575b50505050509050919050565b5f8181526001830160205260408120546147e657508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155613777565b505f613777565b5f5f604083850312156147fe575f5ffd5b50508035926020909101359150565b5f6020828403121561481d575f5ffd5b5035919050565b5f5f5f60608486031215614836575f5ffd5b505081359360208301359350604090920135919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461278e575f5ffd5b80356148798161484d565b919050565b5f6020828403121561488e575f5ffd5b81356137898161484d565b5f61012082840312156148aa575f5ffd5b50919050565b5f602082840312156148c0575f5ffd5b813567ffffffffffffffff8111156148d6575f5ffd5b6124f284828501614899565b5f5f604083850312156148f3575f5ffd5b8235915060208301356149058161484d565b809150509250929050565b602080825282518282018190525f918401906040840190835b8181101561495d57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101614929565b509095945050505050565b5f5f5f5f6080858703121561497b575f5ffd5b84356149868161484d565b935060208501356149968161484d565b925060408501356149a68161484d565b915060608501356149b68161484d565b939692955090935050565b5f5f5f606084860312156149d3575f5ffd5b8335925060208401359150604084013567ffffffffffffffff811681146149f8575f5ffd5b809150509250925092565b602080825282518282018190525f918401906040840190835b8181101561495d578351835260209384019390920191600101614a1c565b801515811461278e575f5ffd5b5f5f5f60608486031215614a59575f5ffd5b833592506020840135614a6b8161484d565b915060408401356149f881614a3a565b5f5f5f5f60808587031215614a8e575f5ffd5b5050823594602084013594506040840135936060013592509050565b5f5f83601f840112614aba575f5ffd5b50813567ffffffffffffffff811115614ad1575f5ffd5b6020830191508360208260051b8501011115614461575f5ffd5b5f5f5f5f5f5f60a08789031215614b00575f5ffd5b863595506020870135945060408701359350606087013567ffffffffffffffff811115614b2b575f5ffd5b87016060818a031215614b3c575f5ffd5b9250608087013567ffffffffffffffff811115614b57575f5ffd5b614b6389828a01614aaa565b979a9699509497509295939492505050565b803561ffff81168114614879575f5ffd5b5f5f5f5f5f5f5f5f60e0898b031215614b9d575f5ffd5b88359750602089013596506040890135955060608901359450614bc260808a01614b75565b935060a089013567ffffffffffffffff811115614bdd575f5ffd5b614be98b828c01614aaa565b90945092505060c089013560028110614c00575f5ffd5b809150509295985092959890939650565b5f5f60408385031215614c22575f5ffd5b82359150602083013561490581614a3a565b5f5f5f5f5f5f868803610140811215614c4b575f5ffd5b87359650602088013595506040880135945060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa082011215614c8c575f5ffd5b5060608701925061012087013567ffffffffffffffff811115614b57575f5ffd5b5f5f5f5f5f5f5f5f5f60e08a8c031215614cc5575f5ffd5b8935985060208a0135614cd78161484d565b975060408a0135965060608a0135955060808a0135614cf58161484d565b945060a08a013567ffffffffffffffff811115614d10575f5ffd5b8a01601f81018c13614d20575f5ffd5b803567ffffffffffffffff811115614d36575f5ffd5b8c6020828401011115614d47575f5ffd5b6020919091019450925060c08a013567ffffffffffffffff811115614d6a575f5ffd5b614d768c828d01614aaa565b915080935050809150509295985092959850929598565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561377757613777614d8d565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614e00575f5ffd5b83018035915067ffffffffffffffff821115614e1a575f5ffd5b602001915036819003821315614461575f5ffd5b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b85815273ffffffffffffffffffffffffffffffffffffffff85166020820152836040820152608060608201525f614eb0608083018486614e2e565b979650505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614f0b57614f0b614ebb565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614f5857614f58614ebb565b604052919050565b5f67ffffffffffffffff821115614f7957614f79614ebb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f82601f830112614fb4575f5ffd5b8151614fc7614fc282614f60565b614f11565b818152846020838601011115614fdb575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f67ffffffffffffffff82111561501057615010614ebb565b5060051b60200190565b5f6020828403121561502a575f5ffd5b815167ffffffffffffffff811115615040575f5ffd5b820160a08185031215615051575f5ffd5b615059614ee8565b81518152602082015161506b8161484d565b6020820152604082015167ffffffffffffffff811115615089575f5ffd5b61509586828501614fa5565b604083015250606082015167ffffffffffffffff8111156150b4575f5ffd5b8201601f810186136150c4575f5ffd5b80516150d2614fc282614ff7565b8082825260208201915060208360051b8501019250888311156150f3575f5ffd5b602084015b8381101561513457805167ffffffffffffffff811115615116575f5ffd5b6151258b602083890101614fa5565b845250602092830192016150f8565b506060850152505050608091820151918101919091529392505050565b8181038181111561377757613777614d8d565b5f60208284031215615174575f5ffd5b81516137898161484d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156151bc575f5ffd5b5051919050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126151f6575f5ffd5b830160208101925035905067ffffffffffffffff811115615215575f5ffd5b803603821315614461575f5ffd5b8183525f7f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615253575f5ffd5b8260051b80836020870137939093016020019392505050565b8581528460208201526080604082015261ffff61528885614b75565b1660808201525f602085013561529d8161484d565b73ffffffffffffffffffffffffffffffffffffffff1660a08301526152c560408601866151c3565b606060c08501526152da60e085018284614e2e565b9150508281036060840152612a5f818587615223565b5f60208284031215615300575f5ffd5b815161378981614a3a565b87815286602082015285604082015261ffff8516606082015260c060808201525f61533a60c083018587615223565b905060028310615371577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8260a083015298975050505050505050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153b6575f5ffd5b83018035915067ffffffffffffffff8211156153d0575f5ffd5b6020019150600581901b3603821315614461575f5ffd5b5f6153f4614fc284614ff7565b8381526020810190600585901b84013681111561540f575f5ffd5b845b8181101561495d57803567ffffffffffffffff81111561542f575f5ffd5b860136601f82011261543f575f5ffd5b803561544d614fc282614f60565b818152366020838501011115615461575f5ffd5b816020840160208301375f60208383010152808752505050602084019350602081019050615411565b8581528460208201525f843560ff81168082146154a5575f5ffd5b60408401525060208501356154b981614a3a565b1515606083015261ffff6154cf60408701614b75565b1660808301526154e16060860161486e565b73ffffffffffffffffffffffffffffffffffffffff811660a084015250608085013560c083015260a085013560e08301526101206101008301819052614eb09083018486615223565b87815286602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015260a060608201525f61556560a083018688614e2e565b8281036080840152838152602080820190600586901b830101865f5b878110156155dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08584030184526155ba828a6151c3565b6155c5858284614e2e565b60209687019690955093909301925050600101615581565b50909c9b505050505050505050505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b5f82825180855260208501945060208160051b830101602085015f5b838110156156a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08584030188526156918383516155ef565b6020988901989093509190910190600101615657565b50909695505050505050565b602081526156da60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b5f6020830151615702604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151606083015260608301516080830152608083015161012060a08401526157326101408401826155ef565b905060a084015160c084015260c084015160e084015260e08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301610100850152615782828261563b565b9150506101008401516157ae61012085018273ffffffffffffffffffffffffffffffffffffffff169052565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff818116838216019081111561377757613777614d8d56fea264697066735822122006a6e419ee8d59e80df5bb72e1898f00bf6749cdef0e9be132c95a1e89a0236564736f6c634300081c00330000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e30dca3047b37dc7d88849de4a4dc07937ad5ab30000000000000000000000000000000000000000000000000000000000000064
Deployed Bytecode
0x608060405260043610610371575f3560e01c806379ba5097116101c8578063d4b9f4fa116100fd578063e680c4c11161009d578063f2fde38b1161006d578063f2fde38b14610b1e578063f7c7eb9214610b3d578063f851a44014610b51578063ff5a62a114610b7d575f5ffd5b8063e680c4c114610a93578063e6d9923b14610ab2578063e9420f8c14610ad1578063f113c88b14610aff575f5ffd5b8063dead6f7f116100d8578063dead6f7f146109f1578063e0ab636814610a10578063e30c397814610a3e578063e52db4ca14610a68575f5ffd5b8063d4b9f4fa14610993578063d52471c1146109bf578063dc8e4b26146109d2575f5ffd5b8063ac700e6311610168578063b93c936611610143578063b93c9366146108ee578063bc0aac101461091c578063c4d66de814610948578063cbe8361214610967575f5ffd5b8063ac700e631461089c578063b292f5f1146108b0578063b5662c5d146108cf575f5ffd5b80638f8d37a8116101a35780638f8d37a8146107ea57806399c16d1a1461081d5780639d5bd3da1461083c5780639f115e381461087d575f5ffd5b806379ba5097146107985780638456cb59146107ac5780638da5cb5b146107c0575f5ffd5b80633f4ba83a116102a95780635cd8a76b1161024957806370d8af871161021957806370d8af871461070957806370fccb521461073a578063715018a6146107655780637162327414610779575f5ffd5b80635cd8a76b1461068a578063671a71311461069e57806368b8d331146106c95780637011be85146106ea575f5ffd5b80634dd18bf5116102845780634dd18bf514610616578063524c0cfa1461063557806359ec65a2146106545780635c975abb14610673575f5ffd5b80633f4ba83a146105c257806349707f31146105d65780634a945f8d146105f7575f5ffd5b806324fd57fb116103145780632f90b184116102ef5780632f90b18414610527578063332b96dc1461055a57806338720778146105795780633885a750146105a3575f5ffd5b806324fd57fb146104cc5780632a641114146104df5780632dbcf55f14610508575f5ffd5b806317fa37511161034f57806317fa3751146104425780631c50cfea1461046157806322f3a9ba1461048057806324358c611461049f575f5ffd5b80630641e4f71461037557806307621f84146103c65780630e18b6811461042c575b5f5ffd5b348015610380575f5ffd5b5061039461038f3660046147ed565b610b9c565b6040805173ffffffffffffffffffffffffffffffffffffffff9384168152929091166020830152015b60405180910390f35b3480156103d1575f5ffd5b506104076103e036600461480d565b60d66020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103bd565b348015610437575f5ffd5b50610440610d57565b005b34801561044d575f5ffd5b5061039461045c366004614824565b610e85565b34801561046c575f5ffd5b5061044061047b36600461480d565b611055565b34801561048b575f5ffd5b5061044061049a36600461487e565b611176565b3480156104aa575f5ffd5b506104be6104b936600461480d565b6111ca565b6040519081526020016103bd565b6104be6104da3660046148b0565b611252565b3480156104ea575f5ffd5b5060db546104f89060ff1681565b60405190151581526020016103bd565b348015610513575f5ffd5b506104406105223660046148e2565b6118b4565b348015610532575f5ffd5b506104be7f000000000000000000000000000000000000000000000000000000000000000181565b348015610565575f5ffd5b5061044061057436600461487e565b611ad8565b348015610584575f5ffd5b5060c95473ffffffffffffffffffffffffffffffffffffffff16610407565b3480156105ae575f5ffd5b506104406105bd36600461480d565b611bfe565b3480156105cd575f5ffd5b50610440611f48565b3480156105e1575f5ffd5b506105ea611f5a565b6040516103bd9190614910565b348015610602575f5ffd5b50610440610611366004614968565b61202e565b348015610621575f5ffd5b5061044061063036600461487e565b6120d2565b348015610640575f5ffd5b5061044061064f3660046149c1565b61220e565b34801561065f575f5ffd5b5061040761066e36600461480d565b612370565b34801561067e575f5ffd5b5060975460ff166104f8565b348015610695575f5ffd5b506104406124fa565b3480156106a9575f5ffd5b506104be6106b836600461480d565b60d86020525f908152604090205481565b3480156106d4575f5ffd5b506106dd612791565b6040516103bd9190614a03565b3480156106f5575f5ffd5b50610440610704366004614a47565b6127a2565b348015610714575f5ffd5b5060db5461040790610100900473ffffffffffffffffffffffffffffffffffffffff1681565b348015610745575f5ffd5b506104be61075436600461487e565b60d76020525f908152604090205481565b348015610770575f5ffd5b5061044061282e565b348015610784575f5ffd5b506104be610793366004614a7b565b61283f565b3480156107a3575f5ffd5b506104406128f4565b3480156107b7575f5ffd5b506104406129a6565b3480156107cb575f5ffd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610407565b3480156107f5575f5ffd5b506104be7f000000000000000000000000000000000000000000000000000000000000006481565b348015610828575f5ffd5b506104f8610837366004614aeb565b6129b6565b348015610847575f5ffd5b5061040761085636600461480d565b60cc6020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b348015610888575f5ffd5b5061039461089736600461480d565b612a6b565b3480156108a7575f5ffd5b50610440612b33565b3480156108bb575f5ffd5b506104f86108ca366004614b86565b612b68565b3480156108da575f5ffd5b506104406108e93660046148e2565b612c23565b3480156108f9575f5ffd5b506104f861090836600461487e565b60ca6020525f908152604090205460ff1681565b348015610927575f5ffd5b5060c9546104079073ffffffffffffffffffffffffffffffffffffffff1681565b348015610953575f5ffd5b5061044061096236600461487e565b613156565b348015610972575f5ffd5b5060d5546104079073ffffffffffffffffffffffffffffffffffffffff1681565b34801561099e575f5ffd5b5060d3546104079073ffffffffffffffffffffffffffffffffffffffff1681565b6104be6109cd3660046148b0565b61327d565b3480156109dd575f5ffd5b506104406109ec366004614c11565b613635565b3480156109fc575f5ffd5b50610407610a0b36600461480d565b61376d565b348015610a1b575f5ffd5b506104f8610a2a36600461480d565b60da6020525f908152604090205460ff1681565b348015610a49575f5ffd5b5060655473ffffffffffffffffffffffffffffffffffffffff16610407565b348015610a73575f5ffd5b506104be610a8236600461480d565b60d46020525f908152604090205481565b348015610a9e575f5ffd5b50610407610aad36600461480d565b61377d565b348015610abd575f5ffd5b506104f8610acc366004614c34565b613790565b348015610adc575f5ffd5b506104f8610aeb36600461480d565b60d96020525f908152604090205460ff1681565b348015610b0a575f5ffd5b506104be610b19366004614cad565b6137fa565b348015610b29575f5ffd5b50610440610b3836600461487e565b613bbd565b348015610b48575f5ffd5b50610440613c6d565b348015610b5c575f5ffd5b5060ce546104079073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b88575f5ffd5b50610440610b9736600461487e565b613c9f565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314610c215760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b5f83815260d9602052604090205460ff16610c68576040517f90c7cbf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260d860205260409020544614610cc7575f84815260d86020526040908190205490517fc0ca91820000000000000000000000000000000000000000000000000000000081526004810191909152466024820152604401610c18565b5f84815260d86020908152604080832086905560d990915290205460ff1615610d1c576040517f02181a1300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d2760d085613dc9565b5f94855260cc602052604090942054939473ffffffffffffffffffffffffffffffffffffffff9094169392505050565b60cf5473ffffffffffffffffffffffffffffffffffffffff16338114610dab576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b60ce805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000808416821790945560cf80549094169093556040519116915f917fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9908390a38173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc60405160405180910390a35050565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314610f055760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b505f84815260d6602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610f64576040517fce63ce1700000000000000000000000000000000000000000000000000000000815260048101869052602401610c18565b5f84815260d86020526040902054469003610fad576040517f587df426000000000000000000000000000000000000000000000000000000008152466004820152602401610c18565b5f84815260d86020908152604080832046905560cc825280832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861617905560d4825280832086905585835260da909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561104b8461377d565b9150935093915050565b60ce5473ffffffffffffffffffffffffffffffffffffffff163314801590611095575060335473ffffffffffffffffffffffffffffffffffffffff163314155b156110ce576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b5f81815260da602052604090205460ff1615611116576040517ffe919e2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260da602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555182917f3df150949161462acf3be30521d7da9e533b247327a254e55dd01875897a6df391a250565b61117e613dd4565b60db805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b5f81815260cc602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611228576040517f23f3c35700000000000000000000000000000000000000000000000000000000815260048101849052602401610c18565b73ffffffffffffffffffffffffffffffffffffffff165f90815260d7602052604090205492915050565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f908082036112af576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181146112e9576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455611315613e55565b467f000000000000000000000000000000000000000000000000000000000000000114611396576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b61ffff6113a960e0850160c0860161487e565b73ffffffffffffffffffffffffffffffffffffffff1611611427576113d460e0840160c0850161487e565b6040517fb78dbaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015261ffff6024820152604401610c18565b82355f90815260d46020526040812054907f05e1c3ae4b9732444ae25217ac7666e46fa365fee1768de00c9fcb65532b760982036114d05761147160e08601356020870135614dba565b34146114c55761148960e08601356020870135614dba565b6040517f4a0944310000000000000000000000000000000000000000000000000000000081526004810191909152346024820152604401610c18565b50602084013561151c565b8460e001353414611519576040517f4a09443100000000000000000000000000000000000000000000000000000000815260e08601356004820152346024820152604401610c18565b505f5b60c9546040517fc487944000000000000000000000000000000000000000000000000000000000815286356004820152602481018490523360448201526020870135606482015273ffffffffffffffffffffffffffffffffffffffff9091169063c48794409083906084015f604051808303818588803b15801561159e575f5ffd5b505af11580156115b0573d5f5f3e3d5ffd5b505050505050505f8360c00160208101906115cb919061487e565b73ffffffffffffffffffffffffffffffffffffffff1663ca408c2360e086013586353360408901356116016101008b018b614dcd565b6040518763ffffffff1660e01b8152600401611621959493929190614e75565b5f6040518083038185885af115801561163c573d5f5f3e3d5ffd5b50505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611682919081019061501a565b90506116af60017fa175e001c0e5684bc26302c2f9a55aec9f3936fe2aef558034003ef4da7fc77e615151565b81511461171e576116e160017fa175e001c0e5684bc26302c2f9a55aec9f3936fe2aef558034003ef4da7fc77e615151565b81516040517f15e8e42900000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c18565b6117e6843561173360c0870160a0880161487e565b6040805161012081019091528061175060e08a0160c08b0161487e565b73ffffffffffffffffffffffffffffffffffffffff168152602001856020015173ffffffffffffffffffffffffffffffffffffffff1681526020018860200135815260200188604001358152602001856040015181526020018860600135815260200188608001358152602001856060015181526020015f73ffffffffffffffffffffffffffffffffffffffff16815250613ec2565b92506117f860e0850160c0860161487e565b60808201516040517f8eb7db570000000000000000000000000000000000000000000000000000000081528635600482015260248101919091526044810185905273ffffffffffffffffffffffffffffffffffffffff9190911690638eb7db57906064015f604051808303815f87803b158015611873575f5ffd5b505af1158015611885573d5f5f3e3d5ffd5b505050505060017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf45550919050565b5f467f000000000000000000000000000000000000000000000000000000000000000114611904577fffffffffffffffffffffffffeeeeffffffffffffffffffffffffffffffffeeef3301611906565b335b60d55490915073ffffffffffffffffffffffffffffffffffffffff808316911614611975576040517f8e4a23d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610c18565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260ca602052604090205460ff166119d3576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517f000000000000000000000000000000000000000000000000000000000000000160208083019190915273ffffffffffffffffffffffffffffffffffffffff841682840152606080830187905283518084039091018152608090920190925280519101205f905f81815260d66020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915580845260d783529281902084905551338152929350869284917f8f09d7694a9ae17acec5cf132d594d7eee23572f7fe132396ce72b1afbf7ef20910160405180910390a450505050565b611ae0613dd4565b73ffffffffffffffffffffffffffffffffffffffff8116611b2d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff16611b8b576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f81815260ca602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f4e04a497739580efe78a7ee09cdabe6f6fe90965c683292a519102ce5193b68a9190a250565b467f000000000000000000000000000000000000000000000000000000000000000114611c7f576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b5f81815260cc602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611cda576040517f5de7210700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ce560d083613f6a565b15611d1c576040517fff514c1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260cd602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611d77576040517f5de7210700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611d824683613f75565b5f85815260d46020908152604080832084905583835260da90915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f4caa740f000000000000000000000000000000000000000000000000000000008152600481018790529192509073ffffffffffffffffffffffffffffffffffffffff851690634caa740f90602401602060405180830381865afa158015611e34573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e589190615164565b905073ffffffffffffffffffffffffffffffffffffffff8116611ea7576040517f4bd4ae0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611eb285825f613fd5565b60d3546040517fd4ce08c20000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b158015611f1b575f5ffd5b505af1158015611f2d573d5f5f3e3d5ffd5b5050505f958652505060d86020525050604090912046905550565b611f50613dd4565b611f5861404e565b565b60605f611f6760d06140cb565b9050805167ffffffffffffffff811115611f8357611f83614ebb565b604051908082528060200260200182016040528015611fac578160200160208202803683370190505b5081519092505f5b8181101561202857611fe9838281518110611fd157611fd161517f565b602002602001015160d0613dc990919063ffffffff16565b848281518110611ffb57611ffb61517f565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152600101611fb4565b50505090565b612036613dd4565b60c9805473ffffffffffffffffffffffffffffffffffffffff9586167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560d580549486169482169490941790935560d38054928516929093169190911790915560db805491909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909116179055565b60ce5473ffffffffffffffffffffffffffffffffffffffff163314801590612112575060335473ffffffffffffffffffffffffffffffffffffffff163314155b1561214b576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b73ffffffffffffffffffffffffffffffffffffffff8116612198576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9905f90a35050565b3373111111111111111111111111111111111111111114612277576040517fa2ac02a00000000000000000000000000000000000000000000000000000000081523360048201527311111111111111111111111111111111111111116024820152604401610c18565b467f0000000000000000000000000000000000000000000000000000000000000001036122d0576040517f472477e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6122dc60d085613dc9565b6040517fddcc9eec0000000000000000000000000000000000000000000000000000000081526004810185905267ffffffffffffffff8416602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063ddcc9eec906044015f604051808303815f87803b158015612354575f5ffd5b505af1158015612366573d5f5f3e3d5ffd5b5050505050505050565b5f81815260d460205260408082205460c95491517f53b9e632000000000000000000000000000000000000000000000000000000008152600481018290529091839173ffffffffffffffffffffffffffffffffffffffff909116906353b9e63290602401602060405180830381865afa1580156123ef573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124139190615164565b905073ffffffffffffffffffffffffffffffffffffffff8116612465576040517f6410796800000000000000000000000000000000000000000000000000000000815260048101839052602401610c18565b6040517f97bb3ce90000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216906397bb3ce990602401602060405180830381865afa1580156124ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f29190615164565b949350505050565b5f54610100900460ff161580801561251857505f54600160ff909116105b806125315750303b15801561253157505f5460ff166001145b6125bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c18565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015612619575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b467f00000000000000000000000000000000000000000000000000000000000000011461269a576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b7f05e1c3ae4b9732444ae25217ac7666e46fa365fee1768de00c9fcb65532b76095f90815260da60209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0000000000000000000000000000000000000000000000000000000000000001855260d9909352922080549091169091179055801561278e575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b606061279d60d06140cb565b905090565b60db54610100900473ffffffffffffffffffffffffffffffffffffffff16331461281e5760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b612829838383613fd5565b505050565b612836613dd4565b611f585f6140d7565b5f8061284c60d087613dc9565b6040517fb473318e00000000000000000000000000000000000000000000000000000000815260048101879052602481018690526044810185905290915073ffffffffffffffffffffffffffffffffffffffff82169063b473318e90606401602060405180830381865afa1580156128c6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128ea91906151ac565b9695505050505050565b606554339073ffffffffffffffffffffffffffffffffffffffff16811461299d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610c18565b61278e816140d7565b6129ae613dd4565b611f58614108565b5f806129c360d089613dc9565b6040517fe4948f4300000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063e4948f4390612a20908a908a908a908a908a9060040161526c565b602060405180830381865afa158015612a3b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5f91906152f0565b98975050505050505050565b60db545f908190610100900473ffffffffffffffffffffffffffffffffffffffff163314612aeb5760db546040517f8beee3a300000000000000000000000000000000000000000000000000000000815233600482015261010090910473ffffffffffffffffffffffffffffffffffffffff166024820152604401610c18565b5f83815260d860205260409020469055612b048361377d565b5f93845260cc602052604090932054929373ffffffffffffffffffffffffffffffffffffffff90931692915050565b612b3b613dd4565b60db80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f80612b7560d08b613dc9565b6040517f042901c700000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063042901c790612bd6908c908c908c908c908c908c908c9060040161530b565b602060405180830381865afa158015612bf1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1591906152f0565b9a9950505050505050505050565b612c2b613dd4565b467f000000000000000000000000000000000000000000000000000000000000000114612cac576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b73ffffffffffffffffffffffffffffffffffffffff8116612cf9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d0460d083613f6a565b15612d3b576040517f24591d8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff16633408e4706040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d85573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612da991906151ac565b14612de0576040517fa179f8c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8173ffffffffffffffffffffffffffffffffffffffff1663946ebad16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4e9190615164565b90505f8273ffffffffffffffffffffffffffffffffffffffff16636e9960c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e9a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ebe9190615164565b90505f8373ffffffffffffffffffffffffffffffffffffffff1663960dcf246040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f2e91906151ac565b90505f8473ffffffffffffffffffffffffffffffffffffffff16633591c1a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f9e9190615164565b905073ffffffffffffffffffffffffffffffffffffffff81163014613007576040517fdd381a4c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610c18565b613012868386614163565b5f86815260cc6020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891617905560d4825280832085905560d8909152902046905561308086866001613fd5565b60d3546040517fd4ce08c20000000000000000000000000000000000000000000000000000000081526004810188905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b1580156130e9575f5ffd5b505af11580156130fb573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff8781168252861692508891507f1e9125bc72db22c58abff6821d7333551967e26454b419ffa958e4cb8ef476009060200160405180910390a3505050505050565b61315e6143eb565b467f0000000000000000000000000000000000000000000000000000000000000001146131df576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b6131e8816140d7565b7f05e1c3ae4b9732444ae25217ac7666e46fa365fee1768de00c9fcb65532b76095f90815260da60209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0000000000000000000000000000000000000000000000000000000000000001855260d990935292208054909116909117905550565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f908082036132da576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018114613314576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455613340613e55565b467f0000000000000000000000000000000000000000000000000000000000000001146133c1576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b82355f90815260d460205260409020547f05e1c3ae4b9732444ae25217ac7666e46fa365fee1768de00c9fcb65532b760981036134465783602001353414613441576040517f4a09443100000000000000000000000000000000000000000000000000000000815260208501356004820152346024820152604401610c18565b613486565b3415613486576040517f4a0944310000000000000000000000000000000000000000000000000000000081525f6004820152346024820152604401610c18565b60c9546040517fc487944000000000000000000000000000000000000000000000000000000000815285356004820152602481018390523360448201526020860135606482015273ffffffffffffffffffffffffffffffffffffffff9091169063c48794409034906084015f604051808303818588803b158015613508575f5ffd5b505af115801561351a573d5f5f3e3d5ffd5b5061360a9450508635925061353a9150506101208601610100870161487e565b604080516101208101825233815290602082019061355e9060608a01908a0161487e565b73ffffffffffffffffffffffffffffffffffffffff168152602088810135908201526060808901356040830152016135996080890189614dcd565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050509082525060a0880135602082015260c088013560408201526060016135f360e0890189615383565b6135fc916153e7565b81525f602090910152613ec2565b60017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4559392505050565b61363d613dd4565b467f0000000000000000000000000000000000000000000000000000000000000001146136be576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b5f82815260d860205260409020544614613704576040517f02181a1300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260d9602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168415159081179091559051909184917f02629feb109d94b16a367231d248ba81c462f51ce5b984835f150f1c9f49ed259190a35050565b5f6137778261377d565b92915050565b5f61378960d08361444b565b9392505050565b5f8061379d60d089613dc9565b6040517f263b7f8e00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063263b7f8e90612a20908a908a908a908a908a9060040161548a565b60ce545f9073ffffffffffffffffffffffffffffffffffffffff16331480159061383c575060335473ffffffffffffffffffffffffffffffffffffffff163314155b15613875576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610c18565b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4545f8190036138d1576040517fdd7e362100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811461390b576040517fab143c0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60027f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455613937613e55565b467f0000000000000000000000000000000000000000000000000000000000000001146139b8576040517fecb344490000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000016004820152466024820152604401610c18565b6139c38b8a8c614163565b5f8b815260cc6020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8f1690811790915560d483528184208d905560d8909252808320469055517f88c7c5d20000000000000000000000000000000000000000000000000000000081526388c7c5d290613a6d908f908e908d908d908d908d908d9060040161552a565b6020604051808303815f875af1158015613a89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613aad9190615164565b9050613abb8c826001613fd5565b60d3546040517fd4ce08c2000000000000000000000000000000000000000000000000000000008152600481018e905273ffffffffffffffffffffffffffffffffffffffff9091169063d4ce08c2906024015f604051808303815f87803b158015613b24575f5ffd5b505af1158015613b36573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff8e811682528b1692508e91507f1e9125bc72db22c58abff6821d7333551967e26454b419ffa958e4cb8ef476009060200160405180910390a3505060017f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf455509798975050505050505050565b613bc5613dd4565b6065805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155613c2860335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b613c75613dd4565b60db80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b613ca7613dd4565b73ffffffffffffffffffffffffffffffffffffffff8116613cf4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff1615613d53576040517fec27343900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f81815260ca602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f2eae91be1021e05cc8076387b0182458ae474ae44ee44cc59aefda6ca53c1f429190a250565b5f6137898383614468565b60335473ffffffffffffffffffffffffffffffffffffffff163314611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c18565b60975460ff1615611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c18565b5f5f613ece84336144f1565b73ffffffffffffffffffffffffffffffffffffffff811661010085015290505f613ef960d087613dc9565b6040517f12f43dab00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8216906312f43dab90613f4e9087906004016156b3565b6020604051808303815f875af11580156128c6573d5f5f3e3d5ffd5b5f613789838361458f565b5f82613f856201000060046157b6565b60408051602081019390935273ffffffffffffffffffffffffffffffffffffffff918216908301528316606082015260800160405160208183030381529060405280519060200120905092915050565b613fe160d0848461459a565b5080801561401757507f000000000000000000000000000000000000000000000000000000000000006461401560d06145bc565b115b15612829576040517f601b688200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6140566145c6565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60605f61378983614632565b606580547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561278e8161463d565b614110613e55565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586140a13390565b825f0361419c576040517fc84885d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b65ffffffffffff8311156141dc576040517f8f620a0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468303614215576040517f717a165600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116614262576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81614299576040517f2d4d012f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ca602052604090205460ff166142f7576040517fc630ef3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260da602052604090205460ff16614341576040517f04a0b7e900000000000000000000000000000000000000000000000000000000815260048101839052602401610c18565b60c95473ffffffffffffffffffffffffffffffffffffffff16614390576040517f856d5b7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f83815260cc602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612829576040517f6cf1231200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf480546001909155801561278e576040517fdf3a8fdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808061445986866146b3565b909450925050505b9250929050565b5f8181526002830160205260408120548015158061448b575061448b848461458f565b613789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610c18565b5f73ffffffffffffffffffffffffffffffffffffffff831661454f5773ffffffffffffffffffffffffffffffffffffffff82163214614546577311110000000000000000000000000000000011118201614548565b815b9050613777565b73ffffffffffffffffffffffffffffffffffffffff83163b15614588577311110000000000000000000000000000000011118301614548565b5090919050565b5f61378983836146eb565b5f6124f2848473ffffffffffffffffffffffffffffffffffffffff8516614702565b5f6137778261471e565b60975460ff16611f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c18565b606061377782614728565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f8181526002830160205260408120548190806146e0576146d4858561458f565b92505f91506144619050565b600192509050614461565b5f8181526001830160205260408120541515613789565b5f82815260028401602052604081208290556124f28484614734565b5f6137778261473f565b60605f61378983614748565b5f61378983836147a1565b5f613777825490565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561479557602002820191905f5260205f20905b815481526020019060010190808311614781575b50505050509050919050565b5f8181526001830160205260408120546147e657508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155613777565b505f613777565b5f5f604083850312156147fe575f5ffd5b50508035926020909101359150565b5f6020828403121561481d575f5ffd5b5035919050565b5f5f5f60608486031215614836575f5ffd5b505081359360208301359350604090920135919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461278e575f5ffd5b80356148798161484d565b919050565b5f6020828403121561488e575f5ffd5b81356137898161484d565b5f61012082840312156148aa575f5ffd5b50919050565b5f602082840312156148c0575f5ffd5b813567ffffffffffffffff8111156148d6575f5ffd5b6124f284828501614899565b5f5f604083850312156148f3575f5ffd5b8235915060208301356149058161484d565b809150509250929050565b602080825282518282018190525f918401906040840190835b8181101561495d57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101614929565b509095945050505050565b5f5f5f5f6080858703121561497b575f5ffd5b84356149868161484d565b935060208501356149968161484d565b925060408501356149a68161484d565b915060608501356149b68161484d565b939692955090935050565b5f5f5f606084860312156149d3575f5ffd5b8335925060208401359150604084013567ffffffffffffffff811681146149f8575f5ffd5b809150509250925092565b602080825282518282018190525f918401906040840190835b8181101561495d578351835260209384019390920191600101614a1c565b801515811461278e575f5ffd5b5f5f5f60608486031215614a59575f5ffd5b833592506020840135614a6b8161484d565b915060408401356149f881614a3a565b5f5f5f5f60808587031215614a8e575f5ffd5b5050823594602084013594506040840135936060013592509050565b5f5f83601f840112614aba575f5ffd5b50813567ffffffffffffffff811115614ad1575f5ffd5b6020830191508360208260051b8501011115614461575f5ffd5b5f5f5f5f5f5f60a08789031215614b00575f5ffd5b863595506020870135945060408701359350606087013567ffffffffffffffff811115614b2b575f5ffd5b87016060818a031215614b3c575f5ffd5b9250608087013567ffffffffffffffff811115614b57575f5ffd5b614b6389828a01614aaa565b979a9699509497509295939492505050565b803561ffff81168114614879575f5ffd5b5f5f5f5f5f5f5f5f60e0898b031215614b9d575f5ffd5b88359750602089013596506040890135955060608901359450614bc260808a01614b75565b935060a089013567ffffffffffffffff811115614bdd575f5ffd5b614be98b828c01614aaa565b90945092505060c089013560028110614c00575f5ffd5b809150509295985092959890939650565b5f5f60408385031215614c22575f5ffd5b82359150602083013561490581614a3a565b5f5f5f5f5f5f868803610140811215614c4b575f5ffd5b87359650602088013595506040880135945060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa082011215614c8c575f5ffd5b5060608701925061012087013567ffffffffffffffff811115614b57575f5ffd5b5f5f5f5f5f5f5f5f5f60e08a8c031215614cc5575f5ffd5b8935985060208a0135614cd78161484d565b975060408a0135965060608a0135955060808a0135614cf58161484d565b945060a08a013567ffffffffffffffff811115614d10575f5ffd5b8a01601f81018c13614d20575f5ffd5b803567ffffffffffffffff811115614d36575f5ffd5b8c6020828401011115614d47575f5ffd5b6020919091019450925060c08a013567ffffffffffffffff811115614d6a575f5ffd5b614d768c828d01614aaa565b915080935050809150509295985092959850929598565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561377757613777614d8d565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614e00575f5ffd5b83018035915067ffffffffffffffff821115614e1a575f5ffd5b602001915036819003821315614461575f5ffd5b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b85815273ffffffffffffffffffffffffffffffffffffffff85166020820152836040820152608060608201525f614eb0608083018486614e2e565b979650505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614f0b57614f0b614ebb565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614f5857614f58614ebb565b604052919050565b5f67ffffffffffffffff821115614f7957614f79614ebb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f82601f830112614fb4575f5ffd5b8151614fc7614fc282614f60565b614f11565b818152846020838601011115614fdb575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f67ffffffffffffffff82111561501057615010614ebb565b5060051b60200190565b5f6020828403121561502a575f5ffd5b815167ffffffffffffffff811115615040575f5ffd5b820160a08185031215615051575f5ffd5b615059614ee8565b81518152602082015161506b8161484d565b6020820152604082015167ffffffffffffffff811115615089575f5ffd5b61509586828501614fa5565b604083015250606082015167ffffffffffffffff8111156150b4575f5ffd5b8201601f810186136150c4575f5ffd5b80516150d2614fc282614ff7565b8082825260208201915060208360051b8501019250888311156150f3575f5ffd5b602084015b8381101561513457805167ffffffffffffffff811115615116575f5ffd5b6151258b602083890101614fa5565b845250602092830192016150f8565b506060850152505050608091820151918101919091529392505050565b8181038181111561377757613777614d8d565b5f60208284031215615174575f5ffd5b81516137898161484d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156151bc575f5ffd5b5051919050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126151f6575f5ffd5b830160208101925035905067ffffffffffffffff811115615215575f5ffd5b803603821315614461575f5ffd5b8183525f7f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615253575f5ffd5b8260051b80836020870137939093016020019392505050565b8581528460208201526080604082015261ffff61528885614b75565b1660808201525f602085013561529d8161484d565b73ffffffffffffffffffffffffffffffffffffffff1660a08301526152c560408601866151c3565b606060c08501526152da60e085018284614e2e565b9150508281036060840152612a5f818587615223565b5f60208284031215615300575f5ffd5b815161378981614a3a565b87815286602082015285604082015261ffff8516606082015260c060808201525f61533a60c083018587615223565b905060028310615371577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8260a083015298975050505050505050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153b6575f5ffd5b83018035915067ffffffffffffffff8211156153d0575f5ffd5b6020019150600581901b3603821315614461575f5ffd5b5f6153f4614fc284614ff7565b8381526020810190600585901b84013681111561540f575f5ffd5b845b8181101561495d57803567ffffffffffffffff81111561542f575f5ffd5b860136601f82011261543f575f5ffd5b803561544d614fc282614f60565b818152366020838501011115615461575f5ffd5b816020840160208301375f60208383010152808752505050602084019350602081019050615411565b8581528460208201525f843560ff81168082146154a5575f5ffd5b60408401525060208501356154b981614a3a565b1515606083015261ffff6154cf60408701614b75565b1660808301526154e16060860161486e565b73ffffffffffffffffffffffffffffffffffffffff811660a084015250608085013560c083015260a085013560e08301526101206101008301819052614eb09083018486615223565b87815286602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015260a060608201525f61556560a083018688614e2e565b8281036080840152838152602080820190600586901b830101865f5b878110156155dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08584030184526155ba828a6151c3565b6155c5858284614e2e565b60209687019690955093909301925050600101615581565b50909c9b505050505050505050505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b5f82825180855260208501945060208160051b830101602085015f5b838110156156a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08584030188526156918383516155ef565b6020988901989093509190910190600101615657565b50909695505050505050565b602081526156da60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b5f6020830151615702604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151606083015260608301516080830152608083015161012060a08401526157326101408401826155ef565b905060a084015160c084015260c084015160e084015260e08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301610100850152615782828261563b565b9150506101008401516157ae61012085018273ffffffffffffffffffffffffffffffffffffffff169052565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff818116838216019081111561377757613777614d8d56fea264697066735822122006a6e419ee8d59e80df5bb72e1898f00bf6749cdef0e9be132c95a1e89a0236564736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e30dca3047b37dc7d88849de4a4dc07937ad5ab30000000000000000000000000000000000000000000000000000000000000064
-----Decoded View---------------
Arg [0] : _l1ChainId (uint256): 1
Arg [1] : _owner (address): 0xE30Dca3047B37dc7d88849dE4A4Dc07937ad5Ab3
Arg [2] : _maxNumberOfZKChains (uint256): 100
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [1] : 000000000000000000000000e30dca3047b37dc7d88849de4a4dc07937ad5ab3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000064
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.