Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
PolygonZkEVMUpgraded
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 999999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.20; import "../PolygonZkEVM.sol"; /** * Contract responsible for managing the state and the updates of the L2 network * This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment */ contract PolygonZkEVMUpgraded is PolygonZkEVM { // Indicates the last version before upgrade uint256 public immutable VERSION_BEFORE_UPGRADE; // Indicates the current version uint256 public version; // Last batch verified before the last upgrade uint256 public lastVerifiedBatchBeforeUpgrade; /** * @param _globalExitRootManager Global exit root manager address * @param _matic MATIC token address * @param _rollupVerifier Rollup verifier address * @param _bridgeAddress Bridge address * @param _chainID L2 chainID */ constructor( IPolygonZkEVMGlobalExitRoot _globalExitRootManager, IERC20Upgradeable _matic, IVerifierRollup _rollupVerifier, IPolygonZkEVMBridge _bridgeAddress, uint64 _chainID, uint64 _forkID, uint256 versionBeforeUpgrade ) PolygonZkEVM( _globalExitRootManager, _matic, _rollupVerifier, _bridgeAddress, _chainID, _forkID ) { VERSION_BEFORE_UPGRADE = versionBeforeUpgrade; } /** * @dev Thrown when try to update version when it's already updated */ error VersionAlreadyUpdated(); /** * @dev Thrown when try to proof a non deterministic state using a verified batch from previous forkIDs */ error InitBatchMustMatchCurrentForkID(); /** * @notice Update version of the zkEVM * @param _versionString New version string */ function updateVersion(string memory _versionString) public { if (version != VERSION_BEFORE_UPGRADE) { revert VersionAlreadyUpdated(); } version++; lastVerifiedBatchBeforeUpgrade = lastVerifiedBatch; emit UpdateZkEVMVersion(lastVerifiedBatch, forkID, _versionString); } /** * @notice Internal function that proves a different state root given the same batches to verify * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _proveDistinctPendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal view override { if (initNumBatch < lastVerifiedBatchBeforeUpgrade) { revert InitBatchMustMatchCurrentForkID(); } super._proveDistinctPendingState( initPendingStateNum, finalPendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); } /** * @notice Verify and reward batches internal function * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _verifyAndRewardBatches( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal override { if (initNumBatch < lastVerifiedBatchBeforeUpgrade) { revert InitBatchMustMatchCurrentForkID(); } super._verifyAndRewardBatches( pendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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.8.1) (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] * ``` * 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 v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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 * ==== * * [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://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../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; } /** * @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: AGPL-3.0 pragma solidity ^0.8.20; interface IBasePolygonZkEVMGlobalExitRoot { /** * @dev Thrown when the caller is not the allowed contracts */ error OnlyAllowedContracts(); function updateExitRoot(bytes32 newRollupExitRoot) external; function globalExitRootMap( bytes32 globalExitRootNum ) external returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; interface IPolygonZkEVMBridge { /** * @dev Thrown when sender is not the PolygonZkEVM address */ error OnlyPolygonZkEVM(); /** * @dev Thrown when the destination network is invalid */ error DestinationNetworkInvalid(); /** * @dev Thrown when the amount does not match msg.value */ error AmountDoesNotMatchMsgValue(); /** * @dev Thrown when user is bridging tokens and is also sending a value */ error MsgValueNotZero(); /** * @dev Thrown when the Ether transfer on claimAsset fails */ error EtherTransferFailed(); /** * @dev Thrown when the message transaction on claimMessage fails */ error MessageFailed(); /** * @dev Thrown when the global exit root does not exist */ error GlobalExitRootInvalid(); /** * @dev Thrown when the smt proof does not match */ error InvalidSmtProof(); /** * @dev Thrown when an index is already claimed */ error AlreadyClaimed(); /** * @dev Thrown when the owner of permit does not match the sender */ error NotValidOwner(); /** * @dev Thrown when the spender of the permit does not match this contract address */ error NotValidSpender(); /** * @dev Thrown when the amount of the permit does not match */ error NotValidAmount(); /** * @dev Thrown when the permit data contains an invalid signature */ error NotValidSignature(); function bridgeAsset( uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData ) external payable; function bridgeMessage( uint32 destinationNetwork, address destinationAddress, bool forceUpdateGlobalExitRoot, bytes calldata metadata ) external payable; function claimAsset( bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata ) external; function claimMessage( bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata ) external; function updateGlobalExitRoot() external; function activateEmergencyState() external; function deactivateEmergencyState() external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; interface IPolygonZkEVMErrors { /** * @dev Thrown when the pending state timeout exceeds the _HALT_AGGREGATION_TIMEOUT */ error PendingStateTimeoutExceedHaltAggregationTimeout(); /** * @dev Thrown when the trusted aggregator timeout exceeds the _HALT_AGGREGATION_TIMEOUT */ error TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); /** * @dev Thrown when the caller is not the admin */ error OnlyAdmin(); /** * @dev Thrown when the caller is not the trusted sequencer */ error OnlyTrustedSequencer(); /** * @dev Thrown when the caller is not the trusted aggregator */ error OnlyTrustedAggregator(); /** * @dev Thrown when attempting to sequence 0 batches */ error SequenceZeroBatches(); /** * @dev Thrown when attempting to sequence or verify more batches than _MAX_VERIFY_BATCHES */ error ExceedMaxVerifyBatches(); /** * @dev Thrown when the forced data does not match */ error ForcedDataDoesNotMatch(); /** * @dev Thrown when the sequenced timestamp is below the forced minimum timestamp */ error SequencedTimestampBelowForcedTimestamp(); /** * @dev Thrown when a global exit root is not zero and does not exist */ error GlobalExitRootNotExist(); /** * @dev Thrown when transactions array length is above _MAX_TRANSACTIONS_BYTE_LENGTH. */ error TransactionsLengthAboveMax(); /** * @dev Thrown when a sequenced timestamp is not inside a correct range. */ error SequencedTimestampInvalid(); /** * @dev Thrown when there are more sequenced force batches than were actually submitted, should be unreachable */ error ForceBatchesOverflow(); /** * @dev Thrown when there are more sequenced force batches than were actually submitted */ error TrustedAggregatorTimeoutNotExpired(); /** * @dev Thrown when attempting to access a pending state that does not exist */ error PendingStateDoesNotExist(); /** * @dev Thrown when the init num batch does not match with the one in the pending state */ error InitNumBatchDoesNotMatchPendingState(); /** * @dev Thrown when the old state root of a certain batch does not exist */ error OldStateRootDoesNotExist(); /** * @dev Thrown when the init verification batch is above the last verification batch */ error InitNumBatchAboveLastVerifiedBatch(); /** * @dev Thrown when the final verification batch is below or equal the last verification batch */ error FinalNumBatchBelowLastVerifiedBatch(); /** * @dev Thrown when the zkproof is not valid */ error InvalidProof(); /** * @dev Thrown when attempting to consolidate a pending state not yet consolidable */ error PendingStateNotConsolidable(); /** * @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist */ error PendingStateInvalid(); /** * @dev Thrown when the matic amount is below the necessary matic fee */ error NotEnoughMaticAmount(); /** * @dev Thrown when attempting to sequence a force batch using sequenceForceBatches and the * force timeout did not expire */ error ForceBatchTimeoutNotExpired(); /** * @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one */ error NewTrustedAggregatorTimeoutMustBeLower(); /** * @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one */ error NewPendingStateTimeoutMustBeLower(); /** * @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values */ error InvalidRangeMultiplierBatchFee(); /** * @dev Thrown when attempting to set a batch time target in an invalid range of values */ error InvalidRangeBatchTimeTarget(); /** * @dev Thrown when attempting to set a force batch timeout in an invalid range of values */ error InvalidRangeForceBatchTimeout(); /** * @dev Thrown when the caller is not the pending admin */ error OnlyPendingAdmin(); /** * @dev Thrown when the final pending state num is not in a valid range */ error FinalPendingStateNumInvalid(); /** * @dev Thrown when the final num batch does not match with the one in the pending state */ error FinalNumBatchDoesNotMatchPendingState(); /** * @dev Thrown when the stored root matches the new root proving a different state */ error StoredRootMustBeDifferentThanNewRoot(); /** * @dev Thrown when the batch is already verified when attempting to activate the emergency state */ error BatchAlreadyVerified(); /** * @dev Thrown when the batch is not sequenced or not at the end of a sequence when attempting to activate the emergency state */ error BatchNotSequencedOrNotSequenceEnd(); /** * @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state */ error HaltTimeoutNotExpired(); /** * @dev Thrown when the old accumulate input hash does not exist */ error OldAccInputHashDoesNotExist(); /** * @dev Thrown when the new accumulate input hash does not exist */ error NewAccInputHashDoesNotExist(); /** * @dev Thrown when the new state root is not inside prime */ error NewStateRootNotInsidePrime(); /** * @dev Thrown when force batch is not allowed */ error ForceBatchNotAllowed(); /** * @dev Thrown when try to activate force batches when they are already active */ error ForceBatchesAlreadyActive(); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; import "./IBasePolygonZkEVMGlobalExitRoot.sol"; interface IPolygonZkEVMGlobalExitRoot is IBasePolygonZkEVMGlobalExitRoot { function getLastGlobalExitRoot() external view returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; /** * @dev Define interface verifier */ interface IVerifierRollup { function verifyProof( bytes32[24] calldata proof, uint256[1] memory pubSignals ) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; /** * @dev Contract helper responsible to manage the emergency state */ contract EmergencyManager { /** * @dev Thrown when emergency state is active, and the function requires otherwise */ error OnlyNotEmergencyState(); /** * @dev Thrown when emergency state is not active, and the function requires otherwise */ error OnlyEmergencyState(); /** * @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. */ uint256[10] private _gap; // Indicates whether the emergency state is active or not bool public isEmergencyState; /** * @dev Emitted when emergency state is activated */ event EmergencyStateActivated(); /** * @dev Emitted when emergency state is deactivated */ event EmergencyStateDeactivated(); /** * @notice Only allows a function to be callable if emergency state is unactive */ modifier ifNotEmergencyState() { if (isEmergencyState) { revert OnlyNotEmergencyState(); } _; } /** * @notice Only allows a function to be callable if emergency state is active */ modifier ifEmergencyState() { if (!isEmergencyState) { revert OnlyEmergencyState(); } _; } /** * @notice Activate emergency state */ function _activateEmergencyState() internal virtual ifNotEmergencyState { isEmergencyState = true; emit EmergencyStateActivated(); } /** * @notice Deactivate emergency state */ function _deactivateEmergencyState() internal virtual ifEmergencyState { isEmergencyState = false; emit EmergencyStateDeactivated(); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "./interfaces/IVerifierRollup.sol"; import "./interfaces/IPolygonZkEVMGlobalExitRoot.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./interfaces/IPolygonZkEVMBridge.sol"; import "./lib/EmergencyManager.sol"; import "./interfaces/IPolygonZkEVMErrors.sol"; /** * Contract responsible for managing the states and the updates of L2 network. * There will be a trusted sequencer, which is able to send transactions. * Any user can force some transaction and the sequencer will have a timeout to add them in the queue. * The sequenced state is deterministic and can be precalculated before it's actually verified by a zkProof. * The aggregators will be able to verify the sequenced state with zkProofs and therefore make available the withdrawals from L2 network. * To enter and exit of the L2 network will be used a PolygonZkEVMBridge smart contract that will be deployed in both networks. */ contract PolygonZkEVM is OwnableUpgradeable, EmergencyManager, IPolygonZkEVMErrors { using SafeERC20Upgradeable for IERC20Upgradeable; /** * @notice Struct which will be used to call sequenceBatches * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s * pre-EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data) || v || r || s * @param globalExitRoot Global exit root of the batch * @param timestamp Sequenced timestamp of the batch * @param minForcedTimestamp Minimum timestamp of the force batch data, empty when non forced batch */ struct BatchData { bytes transactions; bytes32 globalExitRoot; uint64 timestamp; uint64 minForcedTimestamp; } /** * @notice Struct which will be used to call sequenceForceBatches * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s * pre-EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data) || v || r || s * @param globalExitRoot Global exit root of the batch * @param minForcedTimestamp Indicates the minimum sequenced timestamp of the batch */ struct ForcedBatchData { bytes transactions; bytes32 globalExitRoot; uint64 minForcedTimestamp; } /** * @notice Struct which will be stored for every batch sequence * @param accInputHash Hash chain that contains all the information to process a batch: * keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 globalExitRoot, uint64 timestamp, address seqAddress) * @param sequencedTimestamp Sequenced timestamp * @param previousLastBatchSequenced Previous last batch sequenced before the current one, this is used to properly calculate the fees */ struct SequencedBatchData { bytes32 accInputHash; uint64 sequencedTimestamp; uint64 previousLastBatchSequenced; } /** * @notice Struct to store the pending states * Pending state will be an intermediary state, that after a timeout can be consolidated, which means that will be added * to the state root mapping, and the global exit root will be updated * This is a protection mechanism against soundness attacks, that will be turned off in the future * @param timestamp Timestamp where the pending state is added to the queue * @param lastVerifiedBatch Last batch verified batch of this pending state * @param exitRoot Pending exit root * @param stateRoot Pending state root */ struct PendingState { uint64 timestamp; uint64 lastVerifiedBatch; bytes32 exitRoot; bytes32 stateRoot; } /** * @notice Struct to call initialize, this saves gas because pack the parameters and avoid stack too deep errors. * @param admin Admin address * @param trustedSequencer Trusted sequencer address * @param pendingStateTimeout Pending state timeout * @param trustedAggregator Trusted aggregator * @param trustedAggregatorTimeout Trusted aggregator timeout */ struct InitializePackedParameters { address admin; address trustedSequencer; uint64 pendingStateTimeout; address trustedAggregator; uint64 trustedAggregatorTimeout; } // Modulus zkSNARK uint256 internal constant _RFIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Max transactions bytes that can be added in a single batch // Max keccaks circuit = (2**23 / 155286) * 44 = 2376 // Bytes per keccak = 136 // Minimum Static keccaks batch = 2 // Max bytes allowed = (2376 - 2) * 136 = 322864 bytes - 1 byte padding // Rounded to 300000 bytes // In order to process the transaction, the data is approximately hashed twice for ecrecover: // 300000 bytes / 2 = 150000 bytes // Since geth pool currently only accepts at maximum 128kb transactions: // https://github.com/ethereum/go-ethereum/blob/master/core/txpool/txpool.go#L54 // We will limit this length to be compliant with the geth restrictions since our node will use it // We let 8kb as a sanity margin uint256 internal constant _MAX_TRANSACTIONS_BYTE_LENGTH = 120000; // Max force batch transaction length // This is used to avoid huge calldata attacks, where the attacker call force batches from another contract uint256 internal constant _MAX_FORCE_BATCH_BYTE_LENGTH = 5000; // If a sequenced batch exceeds this timeout without being verified, the contract enters in emergency mode uint64 internal constant _HALT_AGGREGATION_TIMEOUT = 1 weeks; // Maximum batches that can be verified in one call. It depends on our current metrics // This should be a protection against someone that tries to generate huge chunk of invalid batches, and we can't prove otherwise before the pending timeout expires uint64 internal constant _MAX_VERIFY_BATCHES = 1000; // Max batch multiplier per verification uint256 internal constant _MAX_BATCH_MULTIPLIER = 12; // Max batch fee value uint256 internal constant _MAX_BATCH_FEE = 1000 ether; // Min value batch fee uint256 internal constant _MIN_BATCH_FEE = 1 gwei; // Goldilocks prime field uint256 internal constant _GOLDILOCKS_PRIME_FIELD = 0xFFFFFFFF00000001; // 2 ** 64 - 2 ** 32 + 1 // Max uint64 uint256 internal constant _MAX_UINT_64 = type(uint64).max; // 0xFFFFFFFFFFFFFFFF // MATIC token address IERC20Upgradeable public immutable matic; // Rollup verifier interface IVerifierRollup public immutable rollupVerifier; // Global Exit Root interface IPolygonZkEVMGlobalExitRoot public immutable globalExitRootManager; // PolygonZkEVM Bridge Address IPolygonZkEVMBridge public immutable bridgeAddress; // L2 chain identifier uint64 public immutable chainID; // L2 chain identifier uint64 public immutable forkID; // Time target of the verification of a batch // Adaptatly the batchFee will be updated to achieve this target uint64 public verifyBatchTimeTarget; // Batch fee multiplier with 3 decimals that goes from 1000 - 1023 uint16 public multiplierBatchFee; // Trusted sequencer address address public trustedSequencer; // Current matic fee per batch sequenced uint256 public batchFee; // Queue of forced batches with their associated data // ForceBatchNum --> hashedForcedBatchData // hashedForcedBatchData: hash containing the necessary information to force a batch: // keccak256(keccak256(bytes transactions), bytes32 globalExitRoot, unint64 minForcedTimestamp) mapping(uint64 => bytes32) public forcedBatches; // Queue of batches that defines the virtual state // SequenceBatchNum --> SequencedBatchData mapping(uint64 => SequencedBatchData) public sequencedBatches; // Last sequenced timestamp uint64 public lastTimestamp; // Last batch sent by the sequencers uint64 public lastBatchSequenced; // Last forced batch included in the sequence uint64 public lastForceBatchSequenced; // Last forced batch uint64 public lastForceBatch; // Last batch verified by the aggregators uint64 public lastVerifiedBatch; // Trusted aggregator address address public trustedAggregator; // State root mapping // BatchNum --> state root mapping(uint64 => bytes32) public batchNumToStateRoot; // Trusted sequencer URL string public trustedSequencerURL; // L2 network name string public networkName; // Pending state mapping // pendingStateNumber --> PendingState mapping(uint256 => PendingState) public pendingStateTransitions; // Last pending state uint64 public lastPendingState; // Last pending state consolidated uint64 public lastPendingStateConsolidated; // Once a pending state exceeds this timeout it can be consolidated uint64 public pendingStateTimeout; // Trusted aggregator timeout, if a sequence is not verified in this time frame, // everyone can verify that sequence uint64 public trustedAggregatorTimeout; // Address that will be able to adjust contract parameters or stop the emergency state address public admin; // This account will be able to accept the admin role address public pendingAdmin; // Force batch timeout uint64 public forceBatchTimeout; // Indicates if forced batches are disallowed bool public isForcedBatchDisallowed; /** * @dev Emitted when the trusted sequencer sends a new batch of transactions */ event SequenceBatches(uint64 indexed numBatch); /** * @dev Emitted when a batch is forced */ event ForceBatch( uint64 indexed forceBatchNum, bytes32 lastGlobalExitRoot, address sequencer, bytes transactions ); /** * @dev Emitted when forced batches are sequenced by not the trusted sequencer */ event SequenceForceBatches(uint64 indexed numBatch); /** * @dev Emitted when a aggregator verifies batches */ event VerifyBatches( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted when the trusted aggregator verifies batches */ event VerifyBatchesTrustedAggregator( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted when pending state is consolidated */ event ConsolidatePendingState( uint64 indexed numBatch, bytes32 stateRoot, uint64 indexed pendingStateNum ); /** * @dev Emitted when the admin updates the trusted sequencer address */ event SetTrustedSequencer(address newTrustedSequencer); /** * @dev Emitted when the admin updates the sequencer URL */ event SetTrustedSequencerURL(string newTrustedSequencerURL); /** * @dev Emitted when the admin updates the trusted aggregator timeout */ event SetTrustedAggregatorTimeout(uint64 newTrustedAggregatorTimeout); /** * @dev Emitted when the admin updates the pending state timeout */ event SetPendingStateTimeout(uint64 newPendingStateTimeout); /** * @dev Emitted when the admin updates the trusted aggregator address */ event SetTrustedAggregator(address newTrustedAggregator); /** * @dev Emitted when the admin updates the multiplier batch fee */ event SetMultiplierBatchFee(uint16 newMultiplierBatchFee); /** * @dev Emitted when the admin updates the verify batch timeout */ event SetVerifyBatchTimeTarget(uint64 newVerifyBatchTimeTarget); /** * @dev Emitted when the admin update the force batch timeout */ event SetForceBatchTimeout(uint64 newforceBatchTimeout); /** * @dev Emitted when activate force batches */ event ActivateForceBatches(); /** * @dev Emitted when the admin starts the two-step transfer role setting a new pending admin */ event TransferAdminRole(address newPendingAdmin); /** * @dev Emitted when the pending admin accepts the admin role */ event AcceptAdminRole(address newAdmin); /** * @dev Emitted when is proved a different state given the same batches */ event ProveNonDeterministicPendingState( bytes32 storedStateRoot, bytes32 provedStateRoot ); /** * @dev Emitted when the trusted aggregator overrides pending state */ event OverridePendingState( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted everytime the forkID is updated, this includes the first initialization of the contract * This event is intended to be emitted for every upgrade of the contract with relevant changes for the nodes */ event UpdateZkEVMVersion(uint64 numBatch, uint64 forkID, string version); /** * @param _globalExitRootManager Global exit root manager address * @param _matic MATIC token address * @param _rollupVerifier Rollup verifier address * @param _bridgeAddress Bridge address * @param _chainID L2 chainID * @param _forkID Fork Id */ constructor( IPolygonZkEVMGlobalExitRoot _globalExitRootManager, IERC20Upgradeable _matic, IVerifierRollup _rollupVerifier, IPolygonZkEVMBridge _bridgeAddress, uint64 _chainID, uint64 _forkID ) { globalExitRootManager = _globalExitRootManager; matic = _matic; rollupVerifier = _rollupVerifier; bridgeAddress = _bridgeAddress; chainID = _chainID; forkID = _forkID; } /** * @param initializePackedParameters Struct to save gas and avoid stack too deep errors * @param genesisRoot Rollup genesis root * @param _trustedSequencerURL Trusted sequencer URL * @param _networkName L2 network name */ function initialize( InitializePackedParameters calldata initializePackedParameters, bytes32 genesisRoot, string memory _trustedSequencerURL, string memory _networkName, string calldata _version ) external initializer { admin = initializePackedParameters.admin; trustedSequencer = initializePackedParameters.trustedSequencer; trustedAggregator = initializePackedParameters.trustedAggregator; batchNumToStateRoot[0] = genesisRoot; trustedSequencerURL = _trustedSequencerURL; networkName = _networkName; // Check initialize parameters if ( initializePackedParameters.pendingStateTimeout > _HALT_AGGREGATION_TIMEOUT ) { revert PendingStateTimeoutExceedHaltAggregationTimeout(); } pendingStateTimeout = initializePackedParameters.pendingStateTimeout; if ( initializePackedParameters.trustedAggregatorTimeout > _HALT_AGGREGATION_TIMEOUT ) { revert TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); } trustedAggregatorTimeout = initializePackedParameters .trustedAggregatorTimeout; // Constant deployment variables batchFee = 0.1 ether; // 0.1 Matic verifyBatchTimeTarget = 30 minutes; multiplierBatchFee = 1002; forceBatchTimeout = 5 days; isForcedBatchDisallowed = true; // Initialize OZ contracts __Ownable_init_unchained(); // emit version event emit UpdateZkEVMVersion(0, forkID, _version); } modifier onlyAdmin() { if (admin != msg.sender) { revert OnlyAdmin(); } _; } modifier onlyTrustedSequencer() { if (trustedSequencer != msg.sender) { revert OnlyTrustedSequencer(); } _; } modifier onlyTrustedAggregator() { if (trustedAggregator != msg.sender) { revert OnlyTrustedAggregator(); } _; } modifier isForceBatchAllowed() { if (isForcedBatchDisallowed) { revert ForceBatchNotAllowed(); } _; } ///////////////////////////////////// // Sequence/Verify batches functions //////////////////////////////////// /** * @notice Allows a sequencer to send multiple batches * @param batches Struct array which holds the necessary data to append new batches to the sequence * @param l2Coinbase Address that will receive the fees from L2 */ function sequenceBatches( BatchData[] calldata batches, address l2Coinbase ) external ifNotEmergencyState onlyTrustedSequencer { uint256 batchesNum = batches.length; if (batchesNum == 0) { revert SequenceZeroBatches(); } if (batchesNum > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } // Store storage variables in memory, to save gas, because will be overrided multiple times uint64 currentTimestamp = lastTimestamp; uint64 currentBatchSequenced = lastBatchSequenced; uint64 currentLastForceBatchSequenced = lastForceBatchSequenced; bytes32 currentAccInputHash = sequencedBatches[currentBatchSequenced] .accInputHash; // Store in a temporal variable, for avoid access again the storage slot uint64 initLastForceBatchSequenced = currentLastForceBatchSequenced; for (uint256 i = 0; i < batchesNum; i++) { // Load current sequence BatchData memory currentBatch = batches[i]; // Store the current transactions hash since can be used more than once for gas saving bytes32 currentTransactionsHash = keccak256( currentBatch.transactions ); // Check if it's a forced batch if (currentBatch.minForcedTimestamp > 0) { currentLastForceBatchSequenced++; // Check forced data matches bytes32 hashedForcedBatchData = keccak256( abi.encodePacked( currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.minForcedTimestamp ) ); if ( hashedForcedBatchData != forcedBatches[currentLastForceBatchSequenced] ) { revert ForcedDataDoesNotMatch(); } // Delete forceBatch data since won't be used anymore delete forcedBatches[currentLastForceBatchSequenced]; // Check timestamp is bigger than min timestamp if (currentBatch.timestamp < currentBatch.minForcedTimestamp) { revert SequencedTimestampBelowForcedTimestamp(); } } else { // Check global exit root exists with proper batch length. These checks are already done in the forceBatches call // Note that the sequencer can skip setting a global exit root putting zeros if ( currentBatch.globalExitRoot != bytes32(0) && globalExitRootManager.globalExitRootMap( currentBatch.globalExitRoot ) == 0 ) { revert GlobalExitRootNotExist(); } if ( currentBatch.transactions.length > _MAX_TRANSACTIONS_BYTE_LENGTH ) { revert TransactionsLengthAboveMax(); } } // Check Batch timestamps are correct if ( currentBatch.timestamp < currentTimestamp || currentBatch.timestamp > block.timestamp ) { revert SequencedTimestampInvalid(); } // Calculate next accumulated input hash currentAccInputHash = keccak256( abi.encodePacked( currentAccInputHash, currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.timestamp, l2Coinbase ) ); // Update timestamp currentTimestamp = currentBatch.timestamp; } // Update currentBatchSequenced currentBatchSequenced += uint64(batchesNum); // Sanity check, should be unreachable if (currentLastForceBatchSequenced > lastForceBatch) { revert ForceBatchesOverflow(); } uint256 nonForcedBatchesSequenced = batchesNum - (currentLastForceBatchSequenced - initLastForceBatchSequenced); // Update sequencedBatches mapping sequencedBatches[currentBatchSequenced] = SequencedBatchData({ accInputHash: currentAccInputHash, sequencedTimestamp: uint64(block.timestamp), previousLastBatchSequenced: lastBatchSequenced }); // Store back the storage variables lastTimestamp = currentTimestamp; lastBatchSequenced = currentBatchSequenced; if (currentLastForceBatchSequenced != initLastForceBatchSequenced) lastForceBatchSequenced = currentLastForceBatchSequenced; // Pay collateral for every non-forced batch submitted matic.safeTransferFrom( msg.sender, address(this), batchFee * nonForcedBatchesSequenced ); // Consolidate pending state if possible _tryConsolidatePendingState(); // Update global exit root if there are new deposits bridgeAddress.updateGlobalExitRoot(); emit SequenceBatches(currentBatchSequenced); } /** * @notice Allows an aggregator to verify multiple batches * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function verifyBatches( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external ifNotEmergencyState { // Check if the trusted aggregator timeout expired, // Note that the sequencedBatches struct must exists for this finalNewBatch, if not newAccInputHash will be 0 if ( sequencedBatches[finalNewBatch].sequencedTimestamp + trustedAggregatorTimeout > block.timestamp ) { revert TrustedAggregatorTimeoutNotExpired(); } if (finalNewBatch - initNumBatch > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } _verifyAndRewardBatches( pendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Update batch fees _updateBatchFee(finalNewBatch); if (pendingStateTimeout == 0) { // Consolidate state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); } else { // Consolidate pending state if possible _tryConsolidatePendingState(); // Update pending state lastPendingState++; pendingStateTransitions[lastPendingState] = PendingState({ timestamp: uint64(block.timestamp), lastVerifiedBatch: finalNewBatch, exitRoot: newLocalExitRoot, stateRoot: newStateRoot }); } emit VerifyBatches(finalNewBatch, newStateRoot, msg.sender); } /** * @notice Allows an aggregator to verify multiple batches * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function verifyBatchesTrustedAggregator( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external onlyTrustedAggregator { _verifyAndRewardBatches( pendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Consolidate state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); emit VerifyBatchesTrustedAggregator( finalNewBatch, newStateRoot, msg.sender ); } /** * @notice Verify and reward batches internal function * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _verifyAndRewardBatches( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal virtual { bytes32 oldStateRoot; uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); // Use pending state if specified, otherwise use consolidated state if (pendingStateNum != 0) { // Check that pending state exist // Already consolidated pending states can be used aswell if (pendingStateNum > lastPendingState) { revert PendingStateDoesNotExist(); } // Check choosen pending state PendingState storage currentPendingState = pendingStateTransitions[ pendingStateNum ]; // Get oldStateRoot from pending batch oldStateRoot = currentPendingState.stateRoot; // Check initNumBatch matches the pending state if (initNumBatch != currentPendingState.lastVerifiedBatch) { revert InitNumBatchDoesNotMatchPendingState(); } } else { // Use consolidated state oldStateRoot = batchNumToStateRoot[initNumBatch]; if (oldStateRoot == bytes32(0)) { revert OldStateRootDoesNotExist(); } // Check initNumBatch is inside the range, sanity check if (initNumBatch > currentLastVerifiedBatch) { revert InitNumBatchAboveLastVerifiedBatch(); } } // Check final batch if (finalNewBatch <= currentLastVerifiedBatch) { revert FinalNumBatchBelowLastVerifiedBatch(); } // Get snark bytes bytes memory snarkHashBytes = getInputSnarkBytes( initNumBatch, finalNewBatch, newLocalExitRoot, oldStateRoot, newStateRoot ); // Calulate the snark input uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD; // Verify proof if (!rollupVerifier.verifyProof(proof, [inputSnark])) { revert InvalidProof(); } // Get MATIC reward matic.safeTransfer( msg.sender, calculateRewardPerBatch() * (finalNewBatch - currentLastVerifiedBatch) ); } /** * @notice Internal function to consolidate the state automatically once sequence or verify batches are called * It tries to consolidate the first and the middle pending state in the queue */ function _tryConsolidatePendingState() internal { // Check if there's any state to consolidate if (lastPendingState > lastPendingStateConsolidated) { // Check if it's possible to consolidate the next pending state uint64 nextPendingState = lastPendingStateConsolidated + 1; if (isPendingStateConsolidable(nextPendingState)) { // Check middle pending state ( binary search of 1 step) uint64 middlePendingState = nextPendingState + (lastPendingState - nextPendingState) / 2; // Try to consolidate it, and if not, consolidate the nextPendingState if (isPendingStateConsolidable(middlePendingState)) { _consolidatePendingState(middlePendingState); } else { _consolidatePendingState(nextPendingState); } } } } /** * @notice Allows to consolidate any pending state that has already exceed the pendingStateTimeout * Can be called by the trusted aggregator, which can consolidate any state without the timeout restrictions * @param pendingStateNum Pending state to consolidate */ function consolidatePendingState(uint64 pendingStateNum) external { // Check if pending state can be consolidated // If trusted aggregator is the sender, do not check the timeout or the emergency state if (msg.sender != trustedAggregator) { if (isEmergencyState) { revert OnlyNotEmergencyState(); } if (!isPendingStateConsolidable(pendingStateNum)) { revert PendingStateNotConsolidable(); } } _consolidatePendingState(pendingStateNum); } /** * @notice Internal function to consolidate any pending state that has already exceed the pendingStateTimeout * @param pendingStateNum Pending state to consolidate */ function _consolidatePendingState(uint64 pendingStateNum) internal { // Check if pendingStateNum is in correct range // - not consolidated (implicity checks that is not 0) // - exist ( has been added) if ( pendingStateNum <= lastPendingStateConsolidated || pendingStateNum > lastPendingState ) { revert PendingStateInvalid(); } PendingState storage currentPendingState = pendingStateTransitions[ pendingStateNum ]; // Update state uint64 newLastVerifiedBatch = currentPendingState.lastVerifiedBatch; lastVerifiedBatch = newLastVerifiedBatch; batchNumToStateRoot[newLastVerifiedBatch] = currentPendingState .stateRoot; // Update pending state lastPendingStateConsolidated = pendingStateNum; // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(currentPendingState.exitRoot); emit ConsolidatePendingState( newLastVerifiedBatch, currentPendingState.stateRoot, pendingStateNum ); } /** * @notice Function to update the batch fee based on the new verified batches * The batch fee will not be updated when the trusted aggregator verifies batches * @param newLastVerifiedBatch New last verified batch */ function _updateBatchFee(uint64 newLastVerifiedBatch) internal { uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); uint64 currentBatch = newLastVerifiedBatch; uint256 totalBatchesAboveTarget; uint256 newBatchesVerified = newLastVerifiedBatch - currentLastVerifiedBatch; uint256 targetTimestamp = block.timestamp - verifyBatchTimeTarget; while (currentBatch != currentLastVerifiedBatch) { // Load sequenced batchdata SequencedBatchData storage currentSequencedBatchData = sequencedBatches[ currentBatch ]; // Check if timestamp is below the verifyBatchTimeTarget if ( targetTimestamp < currentSequencedBatchData.sequencedTimestamp ) { // update currentBatch currentBatch = currentSequencedBatchData .previousLastBatchSequenced; } else { // The rest of batches will be above totalBatchesAboveTarget = currentBatch - currentLastVerifiedBatch; break; } } uint256 totalBatchesBelowTarget = newBatchesVerified - totalBatchesAboveTarget; // _MAX_BATCH_FEE --> (< 70 bits) // multiplierBatchFee --> (< 10 bits) // _MAX_BATCH_MULTIPLIER = 12 // multiplierBatchFee ** _MAX_BATCH_MULTIPLIER --> (< 128 bits) // batchFee * (multiplierBatchFee ** _MAX_BATCH_MULTIPLIER)--> // (< 70 bits) * (< 128 bits) = < 256 bits // Since all the following operations cannot overflow, we can optimize this operations with unchecked unchecked { if (totalBatchesBelowTarget < totalBatchesAboveTarget) { // There are more batches above target, fee is multiplied uint256 diffBatches = totalBatchesAboveTarget - totalBatchesBelowTarget; diffBatches = diffBatches > _MAX_BATCH_MULTIPLIER ? _MAX_BATCH_MULTIPLIER : diffBatches; // For every multiplierBatchFee multiplication we must shift 3 zeroes since we have 3 decimals batchFee = (batchFee * (uint256(multiplierBatchFee) ** diffBatches)) / (uint256(1000) ** diffBatches); } else { // There are more batches below target, fee is divided uint256 diffBatches = totalBatchesBelowTarget - totalBatchesAboveTarget; diffBatches = diffBatches > _MAX_BATCH_MULTIPLIER ? _MAX_BATCH_MULTIPLIER : diffBatches; // For every multiplierBatchFee multiplication we must shift 3 zeroes since we have 3 decimals uint256 accDivisor = (uint256(1 ether) * (uint256(multiplierBatchFee) ** diffBatches)) / (uint256(1000) ** diffBatches); // multiplyFactor = multiplierBatchFee ** diffBatches / 10 ** (diffBatches * 3) // accDivisor = 1E18 * multiplyFactor // 1E18 * batchFee / accDivisor = batchFee / multiplyFactor // < 60 bits * < 70 bits / ~60 bits --> overflow not possible batchFee = (uint256(1 ether) * batchFee) / accDivisor; } } // Batch fee must remain inside a range if (batchFee > _MAX_BATCH_FEE) { batchFee = _MAX_BATCH_FEE; } else if (batchFee < _MIN_BATCH_FEE) { batchFee = _MIN_BATCH_FEE; } } //////////////////////////// // Force batches functions //////////////////////////// /** * @notice Allows a sequencer/user to force a batch of L2 transactions. * This should be used only in extreme cases where the trusted sequencer does not work as expected * Note The sequencer has certain degree of control on how non-forced and forced batches are ordered * In order to assure that users force transactions will be processed properly, user must not sign any other transaction * with the same nonce * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * @param maticAmount Max amount of MATIC tokens that the sender is willing to pay */ function forceBatch( bytes calldata transactions, uint256 maticAmount ) public isForceBatchAllowed ifNotEmergencyState { // Calculate matic collateral uint256 maticFee = getForcedBatchFee(); if (maticFee > maticAmount) { revert NotEnoughMaticAmount(); } if (transactions.length > _MAX_FORCE_BATCH_BYTE_LENGTH) { revert TransactionsLengthAboveMax(); } matic.safeTransferFrom(msg.sender, address(this), maticFee); // Get globalExitRoot global exit root bytes32 lastGlobalExitRoot = globalExitRootManager .getLastGlobalExitRoot(); // Update forcedBatches mapping lastForceBatch++; forcedBatches[lastForceBatch] = keccak256( abi.encodePacked( keccak256(transactions), lastGlobalExitRoot, uint64(block.timestamp) ) ); if (msg.sender == tx.origin) { // Getting the calldata from an EOA is easy so no need to put the `transactions` in the event emit ForceBatch(lastForceBatch, lastGlobalExitRoot, msg.sender, ""); } else { // Getting internal transaction calldata is complicated (because it requires an archive node) // Therefore it's worth it to put the `transactions` in the event, which is easy to query emit ForceBatch( lastForceBatch, lastGlobalExitRoot, msg.sender, transactions ); } } /** * @notice Allows anyone to sequence forced Batches if the trusted sequencer has not done so in the timeout period * @param batches Struct array which holds the necessary data to append force batches */ function sequenceForceBatches( ForcedBatchData[] calldata batches ) external isForceBatchAllowed ifNotEmergencyState { uint256 batchesNum = batches.length; if (batchesNum == 0) { revert SequenceZeroBatches(); } if (batchesNum > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } if ( uint256(lastForceBatchSequenced) + batchesNum > uint256(lastForceBatch) ) { revert ForceBatchesOverflow(); } // Store storage variables in memory, to save gas, because will be overrided multiple times uint64 currentBatchSequenced = lastBatchSequenced; uint64 currentLastForceBatchSequenced = lastForceBatchSequenced; bytes32 currentAccInputHash = sequencedBatches[currentBatchSequenced] .accInputHash; // Sequence force batches for (uint256 i = 0; i < batchesNum; i++) { // Load current sequence ForcedBatchData memory currentBatch = batches[i]; currentLastForceBatchSequenced++; // Store the current transactions hash since it's used more than once for gas saving bytes32 currentTransactionsHash = keccak256( currentBatch.transactions ); // Check forced data matches bytes32 hashedForcedBatchData = keccak256( abi.encodePacked( currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.minForcedTimestamp ) ); if ( hashedForcedBatchData != forcedBatches[currentLastForceBatchSequenced] ) { revert ForcedDataDoesNotMatch(); } // Delete forceBatch data since won't be used anymore delete forcedBatches[currentLastForceBatchSequenced]; if (i == (batchesNum - 1)) { // The last batch will have the most restrictive timestamp if ( currentBatch.minForcedTimestamp + forceBatchTimeout > block.timestamp ) { revert ForceBatchTimeoutNotExpired(); } } // Calculate next acc input hash currentAccInputHash = keccak256( abi.encodePacked( currentAccInputHash, currentTransactionsHash, currentBatch.globalExitRoot, uint64(block.timestamp), msg.sender ) ); } // Update currentBatchSequenced currentBatchSequenced += uint64(batchesNum); lastTimestamp = uint64(block.timestamp); // Store back the storage variables sequencedBatches[currentBatchSequenced] = SequencedBatchData({ accInputHash: currentAccInputHash, sequencedTimestamp: uint64(block.timestamp), previousLastBatchSequenced: lastBatchSequenced }); lastBatchSequenced = currentBatchSequenced; lastForceBatchSequenced = currentLastForceBatchSequenced; emit SequenceForceBatches(currentBatchSequenced); } ////////////////// // admin functions ////////////////// /** * @notice Allow the admin to set a new trusted sequencer * @param newTrustedSequencer Address of the new trusted sequencer */ function setTrustedSequencer( address newTrustedSequencer ) external onlyAdmin { trustedSequencer = newTrustedSequencer; emit SetTrustedSequencer(newTrustedSequencer); } /** * @notice Allow the admin to set the trusted sequencer URL * @param newTrustedSequencerURL URL of trusted sequencer */ function setTrustedSequencerURL( string memory newTrustedSequencerURL ) external onlyAdmin { trustedSequencerURL = newTrustedSequencerURL; emit SetTrustedSequencerURL(newTrustedSequencerURL); } /** * @notice Allow the admin to set a new trusted aggregator address * @param newTrustedAggregator Address of the new trusted aggregator */ function setTrustedAggregator( address newTrustedAggregator ) external onlyAdmin { trustedAggregator = newTrustedAggregator; emit SetTrustedAggregator(newTrustedAggregator); } /** * @notice Allow the admin to set a new pending state timeout * The timeout can only be lowered, except if emergency state is active * @param newTrustedAggregatorTimeout Trusted aggregator timeout */ function setTrustedAggregatorTimeout( uint64 newTrustedAggregatorTimeout ) external onlyAdmin { if (newTrustedAggregatorTimeout > _HALT_AGGREGATION_TIMEOUT) { revert TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); } if (!isEmergencyState) { if (newTrustedAggregatorTimeout >= trustedAggregatorTimeout) { revert NewTrustedAggregatorTimeoutMustBeLower(); } } trustedAggregatorTimeout = newTrustedAggregatorTimeout; emit SetTrustedAggregatorTimeout(newTrustedAggregatorTimeout); } /** * @notice Allow the admin to set a new trusted aggregator timeout * The timeout can only be lowered, except if emergency state is active * @param newPendingStateTimeout Trusted aggregator timeout */ function setPendingStateTimeout( uint64 newPendingStateTimeout ) external onlyAdmin { if (newPendingStateTimeout > _HALT_AGGREGATION_TIMEOUT) { revert PendingStateTimeoutExceedHaltAggregationTimeout(); } if (!isEmergencyState) { if (newPendingStateTimeout >= pendingStateTimeout) { revert NewPendingStateTimeoutMustBeLower(); } } pendingStateTimeout = newPendingStateTimeout; emit SetPendingStateTimeout(newPendingStateTimeout); } /** * @notice Allow the admin to set a new multiplier batch fee * @param newMultiplierBatchFee multiplier batch fee */ function setMultiplierBatchFee( uint16 newMultiplierBatchFee ) external onlyAdmin { if (newMultiplierBatchFee < 1000 || newMultiplierBatchFee > 1023) { revert InvalidRangeMultiplierBatchFee(); } multiplierBatchFee = newMultiplierBatchFee; emit SetMultiplierBatchFee(newMultiplierBatchFee); } /** * @notice Allow the admin to set a new verify batch time target * This value will only be relevant once the aggregation is decentralized, so * the trustedAggregatorTimeout should be zero or very close to zero * @param newVerifyBatchTimeTarget Verify batch time target */ function setVerifyBatchTimeTarget( uint64 newVerifyBatchTimeTarget ) external onlyAdmin { if (newVerifyBatchTimeTarget > 1 days) { revert InvalidRangeBatchTimeTarget(); } verifyBatchTimeTarget = newVerifyBatchTimeTarget; emit SetVerifyBatchTimeTarget(newVerifyBatchTimeTarget); } /** * @notice Allow the admin to set the forcedBatchTimeout * The new value can only be lower, except if emergency state is active * @param newforceBatchTimeout New force batch timeout */ function setForceBatchTimeout( uint64 newforceBatchTimeout ) external onlyAdmin { if (newforceBatchTimeout > _HALT_AGGREGATION_TIMEOUT) { revert InvalidRangeForceBatchTimeout(); } if (!isEmergencyState) { if (newforceBatchTimeout >= forceBatchTimeout) { revert InvalidRangeForceBatchTimeout(); } } forceBatchTimeout = newforceBatchTimeout; emit SetForceBatchTimeout(newforceBatchTimeout); } /** * @notice Allow the admin to turn on the force batches * This action is not reversible */ function activateForceBatches() external onlyAdmin { if (!isForcedBatchDisallowed) { revert ForceBatchesAlreadyActive(); } isForcedBatchDisallowed = false; emit ActivateForceBatches(); } /** * @notice Starts the admin role transfer * This is a two step process, the pending admin must accepted to finalize the process * @param newPendingAdmin Address of the new pending admin */ function transferAdminRole(address newPendingAdmin) external onlyAdmin { pendingAdmin = newPendingAdmin; emit TransferAdminRole(newPendingAdmin); } /** * @notice Allow the current pending admin to accept the admin role */ function acceptAdminRole() external { if (pendingAdmin != msg.sender) { revert OnlyPendingAdmin(); } admin = pendingAdmin; emit AcceptAdminRole(pendingAdmin); } ///////////////////////////////// // Soundness protection functions ///////////////////////////////// /** * @notice Allows the trusted aggregator to override the pending state * if it's possible to prove a different state root given the same batches * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function overridePendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external onlyTrustedAggregator { _proveDistinctPendingState( initPendingStateNum, finalPendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Consolidate state state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); // Update trusted aggregator timeout to max trustedAggregatorTimeout = _HALT_AGGREGATION_TIMEOUT; emit OverridePendingState(finalNewBatch, newStateRoot, msg.sender); } /** * @notice Allows to halt the PolygonZkEVM if its possible to prove a different state root given the same batches * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function proveNonDeterministicPendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external ifNotEmergencyState { _proveDistinctPendingState( initPendingStateNum, finalPendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); emit ProveNonDeterministicPendingState( batchNumToStateRoot[finalNewBatch], newStateRoot ); // Activate emergency state _activateEmergencyState(); } /** * @notice Internal function that proves a different state root given the same batches to verify * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _proveDistinctPendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal view virtual { bytes32 oldStateRoot; // Use pending state if specified, otherwise use consolidated state if (initPendingStateNum != 0) { // Check that pending state exist // Already consolidated pending states can be used aswell if (initPendingStateNum > lastPendingState) { revert PendingStateDoesNotExist(); } // Check choosen pending state PendingState storage initPendingState = pendingStateTransitions[ initPendingStateNum ]; // Get oldStateRoot from init pending state oldStateRoot = initPendingState.stateRoot; // Check initNumBatch matches the init pending state if (initNumBatch != initPendingState.lastVerifiedBatch) { revert InitNumBatchDoesNotMatchPendingState(); } } else { // Use consolidated state oldStateRoot = batchNumToStateRoot[initNumBatch]; if (oldStateRoot == bytes32(0)) { revert OldStateRootDoesNotExist(); } // Check initNumBatch is inside the range, sanity check if (initNumBatch > lastVerifiedBatch) { revert InitNumBatchAboveLastVerifiedBatch(); } } // Assert final pending state num is in correct range // - exist ( has been added) // - bigger than the initPendingstate // - not consolidated if ( finalPendingStateNum > lastPendingState || finalPendingStateNum <= initPendingStateNum || finalPendingStateNum <= lastPendingStateConsolidated ) { revert FinalPendingStateNumInvalid(); } // Check final num batch if ( finalNewBatch != pendingStateTransitions[finalPendingStateNum].lastVerifiedBatch ) { revert FinalNumBatchDoesNotMatchPendingState(); } // Get snark bytes bytes memory snarkHashBytes = getInputSnarkBytes( initNumBatch, finalNewBatch, newLocalExitRoot, oldStateRoot, newStateRoot ); // Calulate the snark input uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD; // Verify proof if (!rollupVerifier.verifyProof(proof, [inputSnark])) { revert InvalidProof(); } if ( pendingStateTransitions[finalPendingStateNum].stateRoot == newStateRoot ) { revert StoredRootMustBeDifferentThanNewRoot(); } } /** * @notice Function to activate emergency state, which also enables the emergency mode on both PolygonZkEVM and PolygonZkEVMBridge contracts * If not called by the owner must be provided a batcnNum that does not have been aggregated in a _HALT_AGGREGATION_TIMEOUT period * @param sequencedBatchNum Sequenced batch number that has not been aggreagated in _HALT_AGGREGATION_TIMEOUT */ function activateEmergencyState(uint64 sequencedBatchNum) external { if (msg.sender != owner()) { // Only check conditions if is not called by the owner uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); // Check that the batch has not been verified if (sequencedBatchNum <= currentLastVerifiedBatch) { revert BatchAlreadyVerified(); } // Check that the batch has been sequenced and this was the end of a sequence if ( sequencedBatchNum > lastBatchSequenced || sequencedBatches[sequencedBatchNum].sequencedTimestamp == 0 ) { revert BatchNotSequencedOrNotSequenceEnd(); } // Check that has been passed _HALT_AGGREGATION_TIMEOUT since it was sequenced if ( sequencedBatches[sequencedBatchNum].sequencedTimestamp + _HALT_AGGREGATION_TIMEOUT > block.timestamp ) { revert HaltTimeoutNotExpired(); } } _activateEmergencyState(); } /** * @notice Function to deactivate emergency state on both PolygonZkEVM and PolygonZkEVMBridge contracts */ function deactivateEmergencyState() external onlyAdmin { // Deactivate emergency state on PolygonZkEVMBridge bridgeAddress.deactivateEmergencyState(); // Deactivate emergency state on this contract super._deactivateEmergencyState(); } /** * @notice Internal function to activate emergency state on both PolygonZkEVM and PolygonZkEVMBridge contracts */ function _activateEmergencyState() internal override { // Activate emergency state on PolygonZkEVM Bridge bridgeAddress.activateEmergencyState(); // Activate emergency state on this contract super._activateEmergencyState(); } //////////////////////// // public/view functions //////////////////////// /** * @notice Get forced batch fee */ function getForcedBatchFee() public view returns (uint256) { return batchFee * 100; } /** * @notice Get the last verified batch */ function getLastVerifiedBatch() public view returns (uint64) { if (lastPendingState > 0) { return pendingStateTransitions[lastPendingState].lastVerifiedBatch; } else { return lastVerifiedBatch; } } /** * @notice Returns a boolean that indicates if the pendingStateNum is or not consolidable * Note that his function does not check if the pending state currently exists, or if it's consolidated already */ function isPendingStateConsolidable( uint64 pendingStateNum ) public view returns (bool) { return (pendingStateTransitions[pendingStateNum].timestamp + pendingStateTimeout <= block.timestamp); } /** * @notice Function to calculate the reward to verify a single batch */ function calculateRewardPerBatch() public view returns (uint256) { uint256 currentBalance = matic.balanceOf(address(this)); // Total Sequenced Batches = forcedBatches to be sequenced (total forced Batches - sequenced Batches) + sequencedBatches // Total Batches to be verified = Total Sequenced Batches - verified Batches uint256 totalBatchesToVerify = ((lastForceBatch - lastForceBatchSequenced) + lastBatchSequenced) - getLastVerifiedBatch(); if (totalBatchesToVerify == 0) return 0; return currentBalance / totalBatchesToVerify; } /** * @notice Function to calculate the input snark bytes * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param oldStateRoot State root before batch is processed * @param newStateRoot New State root once the batch is processed */ function getInputSnarkBytes( uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 oldStateRoot, bytes32 newStateRoot ) public view returns (bytes memory) { // sanity checks bytes32 oldAccInputHash = sequencedBatches[initNumBatch].accInputHash; bytes32 newAccInputHash = sequencedBatches[finalNewBatch].accInputHash; if (initNumBatch != 0 && oldAccInputHash == bytes32(0)) { revert OldAccInputHashDoesNotExist(); } if (newAccInputHash == bytes32(0)) { revert NewAccInputHashDoesNotExist(); } // Check that new state root is inside goldilocks field if (!checkStateRootInsidePrime(uint256(newStateRoot))) { revert NewStateRootNotInsidePrime(); } return abi.encodePacked( msg.sender, oldStateRoot, oldAccInputHash, initNumBatch, chainID, forkID, newStateRoot, newAccInputHash, newLocalExitRoot, finalNewBatch ); } function checkStateRootInsidePrime( uint256 newStateRoot ) public pure returns (bool) { if ( ((newStateRoot & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && (((newStateRoot >> 64) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && (((newStateRoot >> 128) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && ((newStateRoot >> 192) < _GOLDILOCKS_PRIME_FIELD) ) { return true; } else { return false; } } }
{ "optimizer": { "enabled": true, "runs": 999999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IPolygonZkEVMGlobalExitRoot","name":"_globalExitRootManager","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"_matic","type":"address"},{"internalType":"contract IVerifierRollup","name":"_rollupVerifier","type":"address"},{"internalType":"contract IPolygonZkEVMBridge","name":"_bridgeAddress","type":"address"},{"internalType":"uint64","name":"_chainID","type":"uint64"},{"internalType":"uint64","name":"_forkID","type":"uint64"},{"internalType":"uint256","name":"versionBeforeUpgrade","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BatchAlreadyVerified","type":"error"},{"inputs":[],"name":"BatchNotSequencedOrNotSequenceEnd","type":"error"},{"inputs":[],"name":"ExceedMaxVerifyBatches","type":"error"},{"inputs":[],"name":"FinalNumBatchBelowLastVerifiedBatch","type":"error"},{"inputs":[],"name":"FinalNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"FinalPendingStateNumInvalid","type":"error"},{"inputs":[],"name":"ForceBatchNotAllowed","type":"error"},{"inputs":[],"name":"ForceBatchTimeoutNotExpired","type":"error"},{"inputs":[],"name":"ForceBatchesAlreadyActive","type":"error"},{"inputs":[],"name":"ForceBatchesOverflow","type":"error"},{"inputs":[],"name":"ForcedDataDoesNotMatch","type":"error"},{"inputs":[],"name":"GlobalExitRootNotExist","type":"error"},{"inputs":[],"name":"HaltTimeoutNotExpired","type":"error"},{"inputs":[],"name":"InitBatchMustMatchCurrentForkID","type":"error"},{"inputs":[],"name":"InitNumBatchAboveLastVerifiedBatch","type":"error"},{"inputs":[],"name":"InitNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidRangeBatchTimeTarget","type":"error"},{"inputs":[],"name":"InvalidRangeForceBatchTimeout","type":"error"},{"inputs":[],"name":"InvalidRangeMultiplierBatchFee","type":"error"},{"inputs":[],"name":"NewAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"NewPendingStateTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NewStateRootNotInsidePrime","type":"error"},{"inputs":[],"name":"NewTrustedAggregatorTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NotEnoughMaticAmount","type":"error"},{"inputs":[],"name":"OldAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"OldStateRootDoesNotExist","type":"error"},{"inputs":[],"name":"OnlyAdmin","type":"error"},{"inputs":[],"name":"OnlyEmergencyState","type":"error"},{"inputs":[],"name":"OnlyNotEmergencyState","type":"error"},{"inputs":[],"name":"OnlyPendingAdmin","type":"error"},{"inputs":[],"name":"OnlyTrustedAggregator","type":"error"},{"inputs":[],"name":"OnlyTrustedSequencer","type":"error"},{"inputs":[],"name":"PendingStateDoesNotExist","type":"error"},{"inputs":[],"name":"PendingStateInvalid","type":"error"},{"inputs":[],"name":"PendingStateNotConsolidable","type":"error"},{"inputs":[],"name":"PendingStateTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"SequenceZeroBatches","type":"error"},{"inputs":[],"name":"SequencedTimestampBelowForcedTimestamp","type":"error"},{"inputs":[],"name":"SequencedTimestampInvalid","type":"error"},{"inputs":[],"name":"StoredRootMustBeDifferentThanNewRoot","type":"error"},{"inputs":[],"name":"TransactionsLengthAboveMax","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutNotExpired","type":"error"},{"inputs":[],"name":"VersionAlreadyUpdated","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AcceptAdminRole","type":"event"},{"anonymous":false,"inputs":[],"name":"ActivateForceBatches","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"pendingStateNum","type":"uint64"}],"name":"ConsolidatePendingState","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyStateActivated","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyStateDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"forceBatchNum","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"lastGlobalExitRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"sequencer","type":"address"},{"indexed":false,"internalType":"bytes","name":"transactions","type":"bytes"}],"name":"ForceBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"OverridePendingState","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":"bytes32","name":"storedStateRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"provedStateRoot","type":"bytes32"}],"name":"ProveNonDeterministicPendingState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"}],"name":"SequenceBatches","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"}],"name":"SequenceForceBatches","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newforceBatchTimeout","type":"uint64"}],"name":"SetForceBatchTimeout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newMultiplierBatchFee","type":"uint16"}],"name":"SetMultiplierBatchFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newPendingStateTimeout","type":"uint64"}],"name":"SetPendingStateTimeout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTrustedAggregator","type":"address"}],"name":"SetTrustedAggregator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newTrustedAggregatorTimeout","type":"uint64"}],"name":"SetTrustedAggregatorTimeout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"SetTrustedSequencer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"SetTrustedSequencerURL","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newVerifyBatchTimeTarget","type":"uint64"}],"name":"SetVerifyBatchTimeTarget","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"TransferAdminRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"numBatch","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"forkID","type":"uint64"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"UpdateZkEVMVersion","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"VerifyBatches","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"numBatch","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":true,"internalType":"address","name":"aggregator","type":"address"}],"name":"VerifyBatchesTrustedAggregator","type":"event"},{"inputs":[],"name":"VERSION_BEFORE_UPGRADE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequencedBatchNum","type":"uint64"}],"name":"activateEmergencyState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateForceBatches","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"batchNumToStateRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeAddress","outputs":[{"internalType":"contract IPolygonZkEVMBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateRewardPerBatch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStateRoot","type":"uint256"}],"name":"checkStateRootInsidePrime","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"pendingStateNum","type":"uint64"}],"name":"consolidatePendingState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deactivateEmergencyState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"transactions","type":"bytes"},{"internalType":"uint256","name":"maticAmount","type":"uint256"}],"name":"forceBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forceBatchTimeout","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"forcedBatches","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forkID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getForcedBatchFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"initNumBatch","type":"uint64"},{"internalType":"uint64","name":"finalNewBatch","type":"uint64"},{"internalType":"bytes32","name":"newLocalExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"oldStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"newStateRoot","type":"bytes32"}],"name":"getInputSnarkBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastVerifiedBatch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalExitRootManager","outputs":[{"internalType":"contract IPolygonZkEVMGlobalExitRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"trustedSequencer","type":"address"},{"internalType":"uint64","name":"pendingStateTimeout","type":"uint64"},{"internalType":"address","name":"trustedAggregator","type":"address"},{"internalType":"uint64","name":"trustedAggregatorTimeout","type":"uint64"}],"internalType":"struct PolygonZkEVM.InitializePackedParameters","name":"initializePackedParameters","type":"tuple"},{"internalType":"bytes32","name":"genesisRoot","type":"bytes32"},{"internalType":"string","name":"_trustedSequencerURL","type":"string"},{"internalType":"string","name":"_networkName","type":"string"},{"internalType":"string","name":"_version","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isEmergencyState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isForcedBatchDisallowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"pendingStateNum","type":"uint64"}],"name":"isPendingStateConsolidable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBatchSequenced","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatchSequenced","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPendingState","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPendingStateConsolidated","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastVerifiedBatch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastVerifiedBatchBeforeUpgrade","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"matic","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiplierBatchFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"networkName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"initPendingStateNum","type":"uint64"},{"internalType":"uint64","name":"finalPendingStateNum","type":"uint64"},{"internalType":"uint64","name":"initNumBatch","type":"uint64"},{"internalType":"uint64","name":"finalNewBatch","type":"uint64"},{"internalType":"bytes32","name":"newLocalExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"newStateRoot","type":"bytes32"},{"internalType":"bytes32[24]","name":"proof","type":"bytes32[24]"}],"name":"overridePendingState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingStateTimeout","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingStateTransitions","outputs":[{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"lastVerifiedBatch","type":"uint64"},{"internalType":"bytes32","name":"exitRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"initPendingStateNum","type":"uint64"},{"internalType":"uint64","name":"finalPendingStateNum","type":"uint64"},{"internalType":"uint64","name":"initNumBatch","type":"uint64"},{"internalType":"uint64","name":"finalNewBatch","type":"uint64"},{"internalType":"bytes32","name":"newLocalExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"newStateRoot","type":"bytes32"},{"internalType":"bytes32[24]","name":"proof","type":"bytes32[24]"}],"name":"proveNonDeterministicPendingState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollupVerifier","outputs":[{"internalType":"contract IVerifierRollup","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"transactions","type":"bytes"},{"internalType":"bytes32","name":"globalExitRoot","type":"bytes32"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"minForcedTimestamp","type":"uint64"}],"internalType":"struct PolygonZkEVM.BatchData[]","name":"batches","type":"tuple[]"},{"internalType":"address","name":"l2Coinbase","type":"address"}],"name":"sequenceBatches","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"transactions","type":"bytes"},{"internalType":"bytes32","name":"globalExitRoot","type":"bytes32"},{"internalType":"uint64","name":"minForcedTimestamp","type":"uint64"}],"internalType":"struct PolygonZkEVM.ForcedBatchData[]","name":"batches","type":"tuple[]"}],"name":"sequenceForceBatches","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"sequencedBatches","outputs":[{"internalType":"bytes32","name":"accInputHash","type":"bytes32"},{"internalType":"uint64","name":"sequencedTimestamp","type":"uint64"},{"internalType":"uint64","name":"previousLastBatchSequenced","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"newforceBatchTimeout","type":"uint64"}],"name":"setForceBatchTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMultiplierBatchFee","type":"uint16"}],"name":"setMultiplierBatchFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newPendingStateTimeout","type":"uint64"}],"name":"setPendingStateTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTrustedAggregator","type":"address"}],"name":"setTrustedAggregator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newTrustedAggregatorTimeout","type":"uint64"}],"name":"setTrustedAggregatorTimeout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"setTrustedSequencer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"setTrustedSequencerURL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newVerifyBatchTimeTarget","type":"uint64"}],"name":"setVerifyBatchTimeTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"transferAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedAggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedAggregatorTimeout","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedSequencer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedSequencerURL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_versionString","type":"string"}],"name":"updateVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifyBatchTimeTarget","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"pendingStateNum","type":"uint64"},{"internalType":"uint64","name":"initNumBatch","type":"uint64"},{"internalType":"uint64","name":"finalNewBatch","type":"uint64"},{"internalType":"bytes32","name":"newLocalExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"newStateRoot","type":"bytes32"},{"internalType":"bytes32[24]","name":"proof","type":"bytes32[24]"}],"name":"verifyBatches","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"pendingStateNum","type":"uint64"},{"internalType":"uint64","name":"initNumBatch","type":"uint64"},{"internalType":"uint64","name":"finalNewBatch","type":"uint64"},{"internalType":"bytes32","name":"newLocalExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"newStateRoot","type":"bytes32"},{"internalType":"bytes32[24]","name":"proof","type":"bytes32[24]"}],"name":"verifyBatchesTrustedAggregator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61016060405234801562000011575f80fd5b50604051620061d3380380620061d38339810160408190526200003491620000a8565b6001600160a01b0396871660c05294861660805292851660a052931660e0526001600160401b03928316610100529190911661012052610140526200013a565b6001600160a01b038116811462000089575f80fd5b50565b80516001600160401b0381168114620000a3575f80fd5b919050565b5f805f805f805f60e0888a031215620000bf575f80fd5b8751620000cc8162000074565b6020890151909750620000df8162000074565b6040890151909650620000f28162000074565b6060890151909550620001058162000074565b935062000115608089016200008c565b92506200012560a089016200008c565b915060c0880151905092959891949750929550565b60805160a05160c05160e051610100516101205161014051615fbb620002185f395f818161084a015261259801525f81816106f101528181610e6901528181612642015261328601525f81816108840152610e3f01525f818161082301528181611df601528181613917015261463001525f81816109ef01528181610fdb015281816111a601528181611a03015281816121c401528181613af8015261410801525f8181610a9c01528181614a7a0152614ec801525f818161093f01528181611dc40152818161277c01528181613acd0152614b660152615fbb5ff3fe608060405234801561000f575f80fd5b50600436106103f3575f3560e01c8063837a47381161020f578063c0ed84e01161012e578063dbc16976116100c3578063ed6b010411610093578063f2fde38b11610079578063f2fde38b14610b11578063f851a44014610b24578063f8b823e414610b44575f80fd5b8063ed6b010414610ad1578063f14916d614610afe575f80fd5b8063dbc1697614610a5f578063e7a7ed0214610a67578063e8bf92ed14610a97578063eaeb077b14610abe575f80fd5b8063d02103ca116100fe578063d02103ca146109ea578063d2e129f914610a11578063d8d1091b14610a24578063d939b31514610a37575f80fd5b8063c0ed84e014610974578063c754c7ed1461097c578063c89e42df146109a8578063cfa8ed47146109bb575f80fd5b8063a3c573eb116101a4578063afd23cbe11610174578063afd23cbe146108a6578063b4d63f58146108d4578063b6b0b0971461093a578063ba58ae3914610961575f80fd5b8063a3c573eb1461081e578063a42ea14514610845578063ada8f9191461086c578063adc879e91461087f575f80fd5b806399f5634e116101df57806399f5634e146107dd5780639aa972a3146107e55780639c9f3dfe146107f8578063a066215c1461080b575f80fd5b8063837a473814610713578063841b24d7146107875780638c3d7301146107b75780638da5cb5b146107bf575f80fd5b80634a910e6a11610315578063621dd411116102aa578063715018a61161027a5780637240f9af116102605780637240f9af146106c55780637fcb3653146106d8578063831c7ead146106ec575f80fd5b8063715018a6146106aa5780637215541a146106b2575f80fd5b8063621dd4111461065c578063635684451461066f5780636b8616ce146106785780636ff512cc14610697575f80fd5b806354fd4d50116102e557806354fd4d50146106305780635e9145c9146106395780635ec919581461064c5780636046916914610654575f80fd5b80634a910e6a146105d55780634e487706146105e85780635392c5e0146105fb578063542028d514610628575f80fd5b80632b0006fa1161038b578063423fa8561161035b578063423fa856146105595780634560526714610579578063458c0477146105a15780634a1a89a7146105b5575f80fd5b80632b0006fa1461050d5780632c1f816a14610520578063383b3be814610533578063394218e914610546575f80fd5b806319d8ac61116103c657806319d8ac6114610475578063220d789914610489578063267822471461049c57806329878983146104e1575f80fd5b80630a0d9fbe146103f7578063107bf28c1461042e57806315064c96146104435780631816b7e514610460575b5f80fd5b606f5461041090610100900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610436610b4d565b6040516104259190615434565b606f546104509060ff1681565b6040519015158152602001610425565b61047361046e36600461544d565b610bd9565b005b6073546104109067ffffffffffffffff1681565b610436610497366004615485565b610cf1565b607b546104bc9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610425565b6074546104bc9068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61047361051b3660046154e5565b610ec7565b61047361052e366004615549565b611091565b6104506105413660046155be565b611299565b6104736105543660046155be565b6112ee565b6073546104109068010000000000000000900467ffffffffffffffff1681565b60735461041090700100000000000000000000000000000000900467ffffffffffffffff1681565b6079546104109067ffffffffffffffff1681565b6079546104109068010000000000000000900467ffffffffffffffff1681565b6104736105e33660046155be565b611472565b6104736105f63660046155be565b611525565b61061a6106093660046155be565b60756020525f908152604090205481565b604051908152602001610425565b6104366116a9565b61061a607c5481565b610473610647366004615642565b6116b6565b610473611eaf565b61061a611fae565b61047361066a3660046154e5565b611fc3565b61061a607d5481565b61061a6106863660046155be565b60716020525f908152604090205481565b6104736106a5366004615692565b612341565b610473612416565b6104736106c03660046155be565b612429565b6104736106d336600461577f565b612596565b6074546104109067ffffffffffffffff1681565b6104107f000000000000000000000000000000000000000000000000000000000000000081565b61075b6107213660046157b1565b60786020525f908152604090208054600182015460029092015467ffffffffffffffff808316936801000000000000000090930416919084565b6040805167ffffffffffffffff9586168152949093166020850152918301526060820152608001610425565b607954610410907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681565b610473612669565b60335473ffffffffffffffffffffffffffffffffffffffff166104bc565b61061a612735565b6104736107f3366004615549565b612888565b6104736108063660046155be565b612938565b6104736108193660046155be565b612ab4565b6104bc7f000000000000000000000000000000000000000000000000000000000000000081565b61061a7f000000000000000000000000000000000000000000000000000000000000000081565b61047361087a366004615692565b612bba565b6104107f000000000000000000000000000000000000000000000000000000000000000081565b606f546108c1906901000000000000000000900461ffff1681565b60405161ffff9091168152602001610425565b6109146108e23660046155be565b60726020525f90815260409020805460019091015467ffffffffffffffff808216916801000000000000000090041683565b6040805193845267ffffffffffffffff9283166020850152911690820152606001610425565b6104bc7f000000000000000000000000000000000000000000000000000000000000000081565b61045061096f3660046157b1565b612c7e565b610410612d06565b607b546104109074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b6104736109b636600461577f565b612d59565b606f546104bc906b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b6104bc7f000000000000000000000000000000000000000000000000000000000000000081565b610473610a1f366004615806565b612de6565b610473610a323660046158b1565b613329565b60795461041090700100000000000000000000000000000000900467ffffffffffffffff1681565b6104736138c4565b607354610410907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681565b6104bc7f000000000000000000000000000000000000000000000000000000000000000081565b610473610acc3660046158f0565b613998565b607b54610450907c0100000000000000000000000000000000000000000000000000000000900460ff1681565b610473610b0c366004615692565b613d88565b610473610b1f366004615692565b613e5a565b607a546104bc9073ffffffffffffffffffffffffffffffffffffffff1681565b61061a60705481565b60778054610b5a90615938565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8690615938565b8015610bd15780601f10610ba857610100808354040283529160200191610bd1565b820191905f5260205f20905b815481529060010190602001808311610bb457829003601f168201915b505050505081565b607a5473ffffffffffffffffffffffffffffffffffffffff163314610c2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e88161ffff161080610c4357506103ff8161ffff16115b15610c7a576040517f4c2533c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff16690100000000000000000061ffff8416908102919091179091556040519081527f7019933d795eba185c180209e8ae8bffbaa25bcef293364687702c31f4d302c5906020015b60405180910390a150565b67ffffffffffffffff8086165f818152607260205260408082205493881682529020546060929115801590610d24575081155b15610d5b576040517f6818c29e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610d92576040517f66385b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d9b84612c7e565b610dd1576040517f176b913c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481019690965260548601929092527fffffffffffffffff00000000000000000000000000000000000000000000000060c098891b811660748701527f0000000000000000000000000000000000000000000000000000000000000000891b8116607c8701527f0000000000000000000000000000000000000000000000000000000000000000891b81166084870152608c86019490945260ac85015260cc840194909452509290931b90911660ec830152805180830360d401815260f4909201905290565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610f24576040517fbbcbbc0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f32868686868686613f0e565b607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f9081526075602052604090208390556079541615610fac57607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b158015611031575f80fd5b505af1158015611043573d5f803e3d5ffd5b505060405184815233925067ffffffffffffffff871691507fcb339b570a7f0b25afa7333371ff11192092a0aeace12b671f4c212f2815c6fe906020015b60405180910390a3505050505050565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146110ee576040517fbbcbbc0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110fd87878787878787613f6a565b607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f908152607560205260409020839055607954161561117757607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b1580156111fc575f80fd5b505af115801561120e573d5f803e3d5ffd5b50506079805477ffffffffffffffffffffffffffffffffffffffffffffffff167a093a800000000000000000000000000000000000000000000000001790555050604051828152339067ffffffffffffffff8616907fcc1b5520188bf1dd3e63f98164b577c4d75c11a619ddea692112f0d1aec4cf729060200160405180910390a350505050505050565b60795467ffffffffffffffff8281165f90815260786020526040812054909242926112dc92700100000000000000000000000000000000909204811691166159b6565b67ffffffffffffffff16111592915050565b607a5473ffffffffffffffffffffffffffffffffffffffff16331461133f576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff82161115611386576040517f1d06e87900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff166113f55760795467ffffffffffffffff78010000000000000000000000000000000000000000000000009091048116908216106113f5576040517f401636df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6079805477ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527f1f4fa24c2e4bad19a7f3ec5c5485f70d46c798461c2e684f55bbd0fc661373a190602001610ce6565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16331461151957606f5460ff16156114da576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e381611299565b611519576040517f0ce9e4a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61152281613fbf565b50565b607a5473ffffffffffffffffffffffffffffffffffffffff163314611576576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff821611156115bd576040517ff5e37f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff1661162857607b5467ffffffffffffffff74010000000000000000000000000000000000000000909104811690821610611628576040517ff5e37f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527fa7eb6cb8a613eb4e8bddc1ac3d61ec6cf10898760f0b187bcca794c6ca6fa40b90602001610ce6565b60768054610b5a90615938565b606f5460ff16156116f3576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314611753576040517f11e7be1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f81900361178e576040517fcb591a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e88111156117ca576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000820481165f81815260726020526040812054838516949293700100000000000000000000000000000000909304909216919082905b86811015611c12575f8a8a83818110611830576118306159de565b90506020028101906118429190615a0b565b61184b90615a47565b8051805160209091012060608201519192509067ffffffffffffffff16156119c0578561187781615ad1565b9650505f81836020015184606001516040516020016118ce93929190928352602083019190915260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016604082015260480190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012067ffffffffffffffff8a165f90815260719093529120549091508114611956576040517fce3d755e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8088165f9081526071602052604080822091909155606085015190850151908216911610156119ba576040517f7f7ab87200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611afa565b602082015115801590611a84575060208201516040517f257b363200000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063257b3632906024016020604051808303815f875af1158015611a5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a829190615af7565b155b15611abb576040517f73bd668d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516201d4c01015611afa576040517fa29a6c7c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8767ffffffffffffffff16826040015167ffffffffffffffff161080611b2d575042826040015167ffffffffffffffff16115b15611b64576040517fea82791600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602082810151604080850151815193840189905290830184905260608084019290925260c01b7fffffffffffffffff0000000000000000000000000000000000000000000000001660808301528b901b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166088820152609c016040516020818303038152906040528051906020012094508160400151975050508080611c0a90615b0e565b915050611815565b50611c1d86856159b6565b60735490945067ffffffffffffffff780100000000000000000000000000000000000000000000000090910481169084161115611c86576040517fc630a00d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611c918285615b45565b611ca59067ffffffffffffffff1688615b66565b604080516060810182528581524267ffffffffffffffff908116602080840191825260738054680100000000000000009081900485168688019081528d86165f8181526072909552979093209551865592516001909501805492519585167fffffffffffffffffffffffffffffffff000000000000000000000000000000009384161795851684029590951790945583548c8416911617930292909217905590915082811690851614611d9a57607380547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8716021790555b611dec333083607054611dad9190615b79565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169291906141cc565b611df46142ae565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166379e2cf976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611e59575f80fd5b505af1158015611e6b573d5f803e3d5ffd5b505060405167ffffffffffffffff881692507f303446e6a8cb73c83dff421c0b1d5e5ce0719dab1bff13660fc254e58cc17fce91505f90a250505050505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314611f00576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b547c0100000000000000000000000000000000000000000000000000000000900460ff16611f5c576040517ff6ba91a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690556040517f854dd6ce5a1445c4c54388b21cffd11cf5bba1b9e763aec48ce3da75d617412f905f90a1565b5f6070546064611fbe9190615b79565b905090565b606f5460ff1615612000576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60795467ffffffffffffffff8581165f90815260726020526040902060010154429261204c927801000000000000000000000000000000000000000000000000909104811691166159b6565b67ffffffffffffffff16111561208e576040517f8a0704d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e861209b8686615b45565b67ffffffffffffffff1611156120dd576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120eb868686868686613f0e565b6120f48461435d565b607954700100000000000000000000000000000000900467ffffffffffffffff165f0361223557607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f908152607560205260409020839055607954161561219557607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b15801561221a575f80fd5b505af115801561222c573d5f803e3d5ffd5b50505050612303565b61223d6142ae565b6079805467ffffffffffffffff16905f61225683615ad1565b825467ffffffffffffffff9182166101009390930a92830292820219169190911790915560408051608081018252428316815287831660208083019182528284018981526060840189815260795487165f908152607890935294909120925183549251861668010000000000000000027fffffffffffffffffffffffffffffffff000000000000000000000000000000009093169516949094171781559151600183015551600290910155505b604051828152339067ffffffffffffffff8616907f9c72852172521097ba7e1482e6b44b351323df0155f97f4ea18fcec28e1f596690602001611081565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612392576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fff0000000000000000000000000000000000000000ffffffffffffffffffffff166b01000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8416908102919091179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610ce6565b61241e614537565b6124275f6145b8565b565b60335473ffffffffffffffffffffffffffffffffffffffff16331461258e575f612451612d06565b90508067ffffffffffffffff168267ffffffffffffffff16116124a0576040517f812a372d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000909104811690831611806124e5575067ffffffffffffffff8083165f9081526072602052604090206001015416155b1561251c576040517f98c5c01400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8083165f90815260726020526040902060010154429161254a9162093a8091166159b6565b67ffffffffffffffff16111561258c576040517fd257555a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b61152261462e565b7f0000000000000000000000000000000000000000000000000000000000000000607c54146125f1576040517fc10b159000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607c8054905f61260083615b0e565b909155505060745467ffffffffffffffff16607d8190556040517fed7be53c9f1a96a481223b15568a5b1a475e01a74b347d6ca187c8bf0c078cd691610ce6917f0000000000000000000000000000000000000000000000000000000000000000908590615b90565b607b5473ffffffffffffffffffffffffffffffffffffffff1633146126ba576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b54607a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691821790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e9060200160405180910390a1565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156127c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e59190615af7565b90505f6127f0612d06565b60735467ffffffffffffffff6801000000000000000082048116916128489170010000000000000000000000000000000082048116917801000000000000000000000000000000000000000000000000900416615b45565b61285291906159b6565b61285c9190615b45565b67ffffffffffffffff169050805f03612877575f9250505090565b6128818183615bf2565b9250505090565b606f5460ff16156128c5576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128d487878787878787613f6a565b67ffffffffffffffff84165f908152607560209081526040918290205482519081529081018490527f1f44c21118c4603cfb4e1b621dbcfa2b73efcececee2b99b620b2953d33a7010910160405180910390a161292f61462e565b50505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612989576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff821611156129d0576040517fcc96507000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff16612a375760795467ffffffffffffffff700100000000000000000000000000000000909104811690821610612a37576040517f48a05a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607980547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527fc4121f4e22c69632ebb7cf1f462be0511dc034f999b52013eddfb24aab765c7590602001610ce6565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612b05576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620151808167ffffffffffffffff161115612b4c576040517fe067dfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff1661010067ffffffffffffffff8416908102919091179091556040519081527f1b023231a1ab6b5d93992f168fb44498e1a7e64cef58daff6f1c216de6a68c2890602001610ce6565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612c0b576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610ce6565b5f67ffffffff0000000167ffffffffffffffff8316108015612cb5575067ffffffff00000001604083901c67ffffffffffffffff16105b8015612cd6575067ffffffff00000001608083901c67ffffffffffffffff16105b8015612ced575067ffffffff0000000160c083901c105b15612cfa57506001919050565b505f919050565b919050565b6079545f9067ffffffffffffffff1615612d48575060795467ffffffffffffffff9081165f908152607860205260409020546801000000000000000090041690565b5060745467ffffffffffffffff1690565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612daa576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6076612db68282615c4a565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610ce69190615434565b5f54610100900460ff1615808015612e0457505f54600160ff909116105b80612e1d5750303b158015612e1d57505f5460ff166001145b612eae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015612f0a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b612f176020880188615692565b607a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055612f6c6040880160208901615692565b606f805473ffffffffffffffffffffffffffffffffffffffff929092166b010000000000000000000000027fff0000000000000000000000000000000000000000ffffffffffffffffffffff909216919091179055612fd16080880160608901615692565b6074805473ffffffffffffffffffffffffffffffffffffffff9290921668010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff9092169190911790555f805260756020527ff9e3fbf150b7a0077118526f473c53cb4734f166167e2c6213e3567dd390b4ad869055607661305b8682615c4a565b5060776130688582615c4a565b5062093a8061307d6060890160408a016155be565b67ffffffffffffffff1611156130bf576040517fcc96507000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130cf60608801604089016155be565b6079805467ffffffffffffffff92909216700100000000000000000000000000000000027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff90921691909117905562093a8061313160a0890160808a016155be565b67ffffffffffffffff161115613173576040517f1d06e87900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61318360a08801608089016155be565b6079805477ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff939093169290920291909117905567016345785d8a0000607055606f80547fffffffffffffffffffffffffffffffffffffffffff00000000000000000000ff166a03ea000000000000070800179055607b80547fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff167c01000000000006978000000000000000000000000000000000000000001790556132626146b1565b7fed7be53c9f1a96a481223b15568a5b1a475e01a74b347d6ca187c8bf0c078cd65f7f000000000000000000000000000000000000000000000000000000000000000085856040516132b79493929190615da9565b60405180910390a1801561292f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b607b547c0100000000000000000000000000000000000000000000000000000000900460ff1615613386576040517f24eff8c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff16156133c3576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f8190036133fe576040517fcb591a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e881111561343a576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff78010000000000000000000000000000000000000000000000008204811691613485918491700100000000000000000000000000000000900416615de0565b11156134bd576040517fc630a00d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000820481165f8181526072602052604081205491937001000000000000000000000000000000009004909216915b84811015613762575f87878381811061351b5761351b6159de565b905060200281019061352d9190615df3565b61353690615e25565b90508361354281615ad1565b825180516020918201208185015160408087015190519499509194505f936135a39386939101928352602083019190915260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016604082015260480190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012067ffffffffffffffff89165f9081526071909352912054909150811461362b576040517fce3d755e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff86165f9081526071602052604081205561364f600189615b66565b84036136be5742607b60149054906101000a900467ffffffffffffffff16846040015161367c91906159b6565b67ffffffffffffffff1611156136be576040517fc44a082100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020838101516040805192830188905282018490526060808301919091524260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016608083015233901b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166088820152609c01604051602081830303815290604052805190602001209450505050808061375a90615b0e565b915050613500565b5061376d84846159b6565b6073805467ffffffffffffffff4281167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009092168217808455604080516060810182528781526020808201958652680100000000000000009384900485168284019081528589165f818152607290935284832093518455965160019390930180549151871686027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921693871693909317179091558554938916700100000000000000000000000000000000027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff938602939093167fffffffffffffffff00000000000000000000000000000000ffffffffffffffff90941693909317919091179093559151929550917f648a61dd2438f072f5a1960939abd30f37aea80d2e94c9792ad142d3e0a490a49190a2505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314613915576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663dbc169766040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561397a575f80fd5b505af115801561398c573d5f803e3d5ffd5b50505050612427614750565b607b547c0100000000000000000000000000000000000000000000000000000000900460ff16156139f5576040517f24eff8c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff1615613a32576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613a3b611fae565b905081811115613a77576040517f4732fdb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611388831115613ab3576040517fa29a6c7c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613af573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846141cc565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633ed691ef6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b839190615af7565b60738054919250780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16906018613bbd83615ad1565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550508484604051613bf4929190615e9e565b60408051918290038220602083015281018290527fffffffffffffffff0000000000000000000000000000000000000000000000004260c01b166060820152606801604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206073547801000000000000000000000000000000000000000000000000900467ffffffffffffffff165f9081526071909352912055323303613d22576073546040805183815233602082015260609181018290525f91810191909152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16907ff94bb37db835f1ab585ee00041849a09b12cd081d77fa15ca070757619cbc9319060800160405180910390a2613d81565b607360189054906101000a900467ffffffffffffffff1667ffffffffffffffff167ff94bb37db835f1ab585ee00041849a09b12cd081d77fa15ca070757619cbc93182338888604051613d789493929190615ead565b60405180910390a25b5050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314613dd9576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607480547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8416908102919091179091556040519081527f61f8fec29495a3078e9271456f05fb0707fd4e41f7661865f80fc437d06681ca90602001610ce6565b613e62614537565b73ffffffffffffffffffffffffffffffffffffffff8116613f05576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401612ea5565b611522816145b8565b607d548567ffffffffffffffff161015613f54576040517fead1340b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f628686868686866147de565b505050505050565b607d548567ffffffffffffffff161015613fb0576040517fead1340b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61292f87878787878787614b99565b60795467ffffffffffffffff680100000000000000009091048116908216111580613ff9575060795467ffffffffffffffff908116908216115b15614030576040517fd086b70b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8181165f81815260786020908152604080832080546074805468010000000000000000928390049098167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090981688179055600282015487865260759094529382902092909255607980547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff169390940292909217909255600182015490517f33d6247d00000000000000000000000000000000000000000000000000000000815260048101919091529091907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b15801561415e575f80fd5b505af1158015614170573d5f803e3d5ffd5b505050508267ffffffffffffffff168167ffffffffffffffff167f328d3c6c0fd6f1be0515e422f2d87e59f25922cbc2233568515a0c4bc3f8510e84600201546040516141bf91815260200190565b60405180910390a3505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526142a89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152614fc8565b50505050565b60795467ffffffffffffffff680100000000000000008204811691161115612427576079545f906142f69068010000000000000000900467ffffffffffffffff1660016159b6565b905061430181611299565b15611522576079545f9060029061432390849067ffffffffffffffff16615b45565b61432d9190615ee2565b61433790836159b6565b905061434281611299565b156143545761435081613fbf565b5050565b61435082613fbf565b5f614366612d06565b9050815f806143758484615b45565b606f5467ffffffffffffffff91821692505f916143989161010090041642615b66565b90505b8467ffffffffffffffff168467ffffffffffffffff16146144225767ffffffffffffffff8085165f908152607260205260409020600181015490911682101561440057600181015468010000000000000000900467ffffffffffffffff16945061441c565b61440a8686615b45565b67ffffffffffffffff16935050614422565b5061439b565b5f61442d8484615b66565b90508381101561448457808403600c8111614448578061444b565b600c5b9050806103e80a81606f60099054906101000a900461ffff1661ffff160a607054028161447a5761447a615bc5565b04607055506144f3565b838103600c81116144955780614498565b600c5b90505f816103e80a82606f60099054906101000a900461ffff1661ffff160a670de0b6b3a764000002816144ce576144ce615bc5565b04905080607054670de0b6b3a764000002816144ec576144ec615bc5565b0460705550505b683635c9adc5dea00000607054111561451857683635c9adc5dea0000060705561292f565b633b9aca00607054101561292f57633b9aca0060705550505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314612427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401612ea5565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632072f6c56040518163ffffffff1660e01b81526004015f604051808303815f87803b158015614693575f80fd5b505af11580156146a5573d5f803e3d5ffd5b505050506124276150d8565b5f54610100900460ff16614747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401612ea5565b612427336145b8565b606f5460ff1661478c576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f806147e8612d06565b905067ffffffffffffffff8816156148b75760795467ffffffffffffffff9081169089161115614844576040517fbb14c20500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8089165f9081526078602052604090206002810154815490945090918981166801000000000000000090920416146148b1576040517f2bd2e3e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50614957565b67ffffffffffffffff87165f90815260756020526040902054915081614909576040517f4997b98600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168767ffffffffffffffff161115614957576040517f1e56e9e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168667ffffffffffffffff16116149a4576040517fb9b18f5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6149b28888888689610cf1565b90505f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016002836040516149e69190615f08565b602060405180830381855afa158015614a01573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190614a249190615af7565b614a2e9190615f19565b6040805160208101825282815290517f9121da8a00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691639121da8a91614ab091899190600401615f2c565b602060405180830381865afa158015614acb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614aef9190615f66565b614b25576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614b8d33614b33858b615b45565b67ffffffffffffffff16614b45612735565b614b4f9190615b79565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016919061516a565b50505050505050505050565b5f67ffffffffffffffff881615614c655760795467ffffffffffffffff9081169089161115614bf4576040517fbb14c20500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5067ffffffffffffffff8088165f908152607860205260409020600281015481549092888116680100000000000000009092041614614c5f576040517f2bd2e3e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50614d00565b5067ffffffffffffffff85165f9081526075602052604090205480614cb6576040517f4997b98600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60745467ffffffffffffffff9081169087161115614d00576040517f1e56e9e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60795467ffffffffffffffff9081169088161180614d3257508767ffffffffffffffff168767ffffffffffffffff1611155b80614d59575060795467ffffffffffffffff68010000000000000000909104811690881611155b15614d90576040517fbfa7079f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8781165f90815260786020526040902054680100000000000000009004811690861614614df2576040517f32a2a77f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f614e008787878588610cf1565b90505f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600283604051614e349190615f08565b602060405180830381855afa158015614e4f573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190614e729190615af7565b614e7c9190615f19565b6040805160208101825282815290517f9121da8a00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691639121da8a91614efe91889190600401615f2c565b602060405180830381865afa158015614f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614f3d9190615f66565b614f73576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff89165f90815260786020526040902060020154859003614b8d576040517fa47276bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f615029826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166151c09092919063ffffffff16565b8051909150156150d357808060200190518101906150479190615f66565b6150d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401612ea5565b505050565b606f5460ff1615615115576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526150d39084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401614226565b60606151ce84845f856151d6565b949350505050565b606082471015615268576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401612ea5565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516152909190615f08565b5f6040518083038185875af1925050503d805f81146152ca576040519150601f19603f3d011682016040523d82523d5f602084013e6152cf565b606091505b50915091506152e0878383876152eb565b979650505050505050565b606083156153805782515f036153795773ffffffffffffffffffffffffffffffffffffffff85163b615379576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612ea5565b50816151ce565b6151ce83838151156153955781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ea59190615434565b5f5b838110156153e35781810151838201526020016153cb565b50505f910152565b5f81518084526154028160208601602086016153c9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f61544660208301846153eb565b9392505050565b5f6020828403121561545d575f80fd5b813561ffff81168114615446575f80fd5b803567ffffffffffffffff81168114612d01575f80fd5b5f805f805f60a08688031215615499575f80fd5b6154a28661546e565b94506154b06020870161546e565b94979496505050506040830135926060810135926080909101359150565b8061030081018310156154df575f80fd5b92915050565b5f805f805f806103a087890312156154fb575f80fd5b6155048761546e565b95506155126020880161546e565b94506155206040880161546e565b9350606087013592506080870135915061553d8860a089016154ce565b90509295509295509295565b5f805f805f805f6103c0888a031215615560575f80fd5b6155698861546e565b96506155776020890161546e565b95506155856040890161546e565b94506155936060890161546e565b93506080880135925060a088013591506155b08960c08a016154ce565b905092959891949750929550565b5f602082840312156155ce575f80fd5b6154468261546e565b5f8083601f8401126155e7575f80fd5b50813567ffffffffffffffff8111156155fe575f80fd5b6020830191508360208260051b8501011115615618575f80fd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114612d01575f80fd5b5f805f60408486031215615654575f80fd5b833567ffffffffffffffff81111561566a575f80fd5b615676868287016155d7565b909450925061568990506020850161561f565b90509250925092565b5f602082840312156156a2575f80fd5b6154468261561f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126156e7575f80fd5b813567ffffffffffffffff80821115615702576157026156ab565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715615748576157486156ab565b81604052838152866020858801011115615760575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6020828403121561578f575f80fd5b813567ffffffffffffffff8111156157a5575f80fd5b6151ce848285016156d8565b5f602082840312156157c1575f80fd5b5035919050565b5f8083601f8401126157d8575f80fd5b50813567ffffffffffffffff8111156157ef575f80fd5b602083019150836020828501011115615618575f80fd5b5f805f805f8086880361012081121561581d575f80fd5b60a081121561582a575f80fd5b5086955060a0870135945060c087013567ffffffffffffffff8082111561584f575f80fd5b61585b8a838b016156d8565b955060e0890135915080821115615870575f80fd5b61587c8a838b016156d8565b9450610100890135915080821115615892575f80fd5b5061589f89828a016157c8565b979a9699509497509295939492505050565b5f80602083850312156158c2575f80fd5b823567ffffffffffffffff8111156158d8575f80fd5b6158e4858286016155d7565b90969095509350505050565b5f805f60408486031215615902575f80fd5b833567ffffffffffffffff811115615918575f80fd5b615924868287016157c8565b909790965060209590950135949350505050565b600181811c9082168061594c57607f821691505b602082108103615983577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff8181168382160190808211156159d7576159d7615989565b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112615a3d575f80fd5b9190910192915050565b5f60808236031215615a57575f80fd5b6040516080810167ffffffffffffffff8282108183111715615a7b57615a7b6156ab565b816040528435915080821115615a8f575f80fd5b50615a9c368286016156d8565b82525060208301356020820152615ab56040840161546e565b6040820152615ac66060840161546e565b606082015292915050565b5f67ffffffffffffffff808316818103615aed57615aed615989565b6001019392505050565b5f60208284031215615b07575f80fd5b5051919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b3e57615b3e615989565b5060010190565b67ffffffffffffffff8281168282160390808211156159d7576159d7615989565b818103818111156154df576154df615989565b80820281158282048414176154df576154df615989565b5f67ffffffffffffffff808616835280851660208401525060606040830152615bbc60608301846153eb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615c0057615c00615bc5565b500490565b601f8211156150d3575f81815260208120601f850160051c81016020861015615c2b5750805b601f850160051c820191505b81811015613f6257828155600101615c37565b815167ffffffffffffffff811115615c6457615c646156ab565b615c7881615c728454615938565b84615c05565b602080601f831160018114615cca575f8415615c945750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613f62565b5f858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615d1657888601518255948401946001909101908401615cf7565b5085821015615d5257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f67ffffffffffffffff808716835280861660208401525060606040830152615dd6606083018486615d62565b9695505050505050565b808201808211156154df576154df615989565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112615a3d575f80fd5b5f60608236031215615e35575f80fd5b6040516060810167ffffffffffffffff8282108183111715615e5957615e596156ab565b816040528435915080821115615e6d575f80fd5b50615e7a368286016156d8565b82525060208301356020820152615e936040840161546e565b604082015292915050565b818382375f9101908152919050565b84815273ffffffffffffffffffffffffffffffffffffffff84166020820152606060408201525f615dd6606083018486615d62565b5f67ffffffffffffffff80841680615efc57615efc615bc5565b92169190910492915050565b5f8251615a3d8184602087016153c9565b5f82615f2757615f27615bc5565b500690565b6103208101610300808584378201835f5b6001811015615f5c578151835260209283019290910190600101615f3d565b5050509392505050565b5f60208284031215615f76575f80fd5b81518015158114615446575f80fdfea2646970667358221220c127415502dda9601f3fb40aaec997c6ddf247345b4659c2aa077ef0bb1d722a64736f6c63430008140033000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb000000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede000000000000000000000000000000000000000000000000000000000000044d00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106103f3575f3560e01c8063837a47381161020f578063c0ed84e01161012e578063dbc16976116100c3578063ed6b010411610093578063f2fde38b11610079578063f2fde38b14610b11578063f851a44014610b24578063f8b823e414610b44575f80fd5b8063ed6b010414610ad1578063f14916d614610afe575f80fd5b8063dbc1697614610a5f578063e7a7ed0214610a67578063e8bf92ed14610a97578063eaeb077b14610abe575f80fd5b8063d02103ca116100fe578063d02103ca146109ea578063d2e129f914610a11578063d8d1091b14610a24578063d939b31514610a37575f80fd5b8063c0ed84e014610974578063c754c7ed1461097c578063c89e42df146109a8578063cfa8ed47146109bb575f80fd5b8063a3c573eb116101a4578063afd23cbe11610174578063afd23cbe146108a6578063b4d63f58146108d4578063b6b0b0971461093a578063ba58ae3914610961575f80fd5b8063a3c573eb1461081e578063a42ea14514610845578063ada8f9191461086c578063adc879e91461087f575f80fd5b806399f5634e116101df57806399f5634e146107dd5780639aa972a3146107e55780639c9f3dfe146107f8578063a066215c1461080b575f80fd5b8063837a473814610713578063841b24d7146107875780638c3d7301146107b75780638da5cb5b146107bf575f80fd5b80634a910e6a11610315578063621dd411116102aa578063715018a61161027a5780637240f9af116102605780637240f9af146106c55780637fcb3653146106d8578063831c7ead146106ec575f80fd5b8063715018a6146106aa5780637215541a146106b2575f80fd5b8063621dd4111461065c578063635684451461066f5780636b8616ce146106785780636ff512cc14610697575f80fd5b806354fd4d50116102e557806354fd4d50146106305780635e9145c9146106395780635ec919581461064c5780636046916914610654575f80fd5b80634a910e6a146105d55780634e487706146105e85780635392c5e0146105fb578063542028d514610628575f80fd5b80632b0006fa1161038b578063423fa8561161035b578063423fa856146105595780634560526714610579578063458c0477146105a15780634a1a89a7146105b5575f80fd5b80632b0006fa1461050d5780632c1f816a14610520578063383b3be814610533578063394218e914610546575f80fd5b806319d8ac61116103c657806319d8ac6114610475578063220d789914610489578063267822471461049c57806329878983146104e1575f80fd5b80630a0d9fbe146103f7578063107bf28c1461042e57806315064c96146104435780631816b7e514610460575b5f80fd5b606f5461041090610100900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610436610b4d565b6040516104259190615434565b606f546104509060ff1681565b6040519015158152602001610425565b61047361046e36600461544d565b610bd9565b005b6073546104109067ffffffffffffffff1681565b610436610497366004615485565b610cf1565b607b546104bc9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610425565b6074546104bc9068010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61047361051b3660046154e5565b610ec7565b61047361052e366004615549565b611091565b6104506105413660046155be565b611299565b6104736105543660046155be565b6112ee565b6073546104109068010000000000000000900467ffffffffffffffff1681565b60735461041090700100000000000000000000000000000000900467ffffffffffffffff1681565b6079546104109067ffffffffffffffff1681565b6079546104109068010000000000000000900467ffffffffffffffff1681565b6104736105e33660046155be565b611472565b6104736105f63660046155be565b611525565b61061a6106093660046155be565b60756020525f908152604090205481565b604051908152602001610425565b6104366116a9565b61061a607c5481565b610473610647366004615642565b6116b6565b610473611eaf565b61061a611fae565b61047361066a3660046154e5565b611fc3565b61061a607d5481565b61061a6106863660046155be565b60716020525f908152604090205481565b6104736106a5366004615692565b612341565b610473612416565b6104736106c03660046155be565b612429565b6104736106d336600461577f565b612596565b6074546104109067ffffffffffffffff1681565b6104107f000000000000000000000000000000000000000000000000000000000000000581565b61075b6107213660046157b1565b60786020525f908152604090208054600182015460029092015467ffffffffffffffff808316936801000000000000000090930416919084565b6040805167ffffffffffffffff9586168152949093166020850152918301526060820152608001610425565b607954610410907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681565b610473612669565b60335473ffffffffffffffffffffffffffffffffffffffff166104bc565b61061a612735565b6104736107f3366004615549565b612888565b6104736108063660046155be565b612938565b6104736108193660046155be565b612ab4565b6104bc7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede81565b61061a7f000000000000000000000000000000000000000000000000000000000000000081565b61047361087a366004615692565b612bba565b6104107f000000000000000000000000000000000000000000000000000000000000044d81565b606f546108c1906901000000000000000000900461ffff1681565b60405161ffff9091168152602001610425565b6109146108e23660046155be565b60726020525f90815260409020805460019091015467ffffffffffffffff808216916801000000000000000090041683565b6040805193845267ffffffffffffffff9283166020850152911690820152606001610425565b6104bc7f0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb081565b61045061096f3660046157b1565b612c7e565b610410612d06565b607b546104109074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b6104736109b636600461577f565b612d59565b606f546104bc906b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b6104bc7f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb81565b610473610a1f366004615806565b612de6565b610473610a323660046158b1565b613329565b60795461041090700100000000000000000000000000000000900467ffffffffffffffff1681565b6104736138c4565b607354610410907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681565b6104bc7f00000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d681565b610473610acc3660046158f0565b613998565b607b54610450907c0100000000000000000000000000000000000000000000000000000000900460ff1681565b610473610b0c366004615692565b613d88565b610473610b1f366004615692565b613e5a565b607a546104bc9073ffffffffffffffffffffffffffffffffffffffff1681565b61061a60705481565b60778054610b5a90615938565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8690615938565b8015610bd15780601f10610ba857610100808354040283529160200191610bd1565b820191905f5260205f20905b815481529060010190602001808311610bb457829003601f168201915b505050505081565b607a5473ffffffffffffffffffffffffffffffffffffffff163314610c2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e88161ffff161080610c4357506103ff8161ffff16115b15610c7a576040517f4c2533c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff16690100000000000000000061ffff8416908102919091179091556040519081527f7019933d795eba185c180209e8ae8bffbaa25bcef293364687702c31f4d302c5906020015b60405180910390a150565b67ffffffffffffffff8086165f818152607260205260408082205493881682529020546060929115801590610d24575081155b15610d5b576040517f6818c29e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80610d92576040517f66385b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d9b84612c7e565b610dd1576040517f176b913c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481019690965260548601929092527fffffffffffffffff00000000000000000000000000000000000000000000000060c098891b811660748701527f000000000000000000000000000000000000000000000000000000000000044d891b8116607c8701527f0000000000000000000000000000000000000000000000000000000000000005891b81166084870152608c86019490945260ac85015260cc840194909452509290931b90911660ec830152805180830360d401815260f4909201905290565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610f24576040517fbbcbbc0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f32868686868686613f0e565b607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f9081526075602052604090208390556079541615610fac57607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b158015611031575f80fd5b505af1158015611043573d5f803e3d5ffd5b505060405184815233925067ffffffffffffffff871691507fcb339b570a7f0b25afa7333371ff11192092a0aeace12b671f4c212f2815c6fe906020015b60405180910390a3505050505050565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146110ee576040517fbbcbbc0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110fd87878787878787613f6a565b607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f908152607560205260409020839055607954161561117757607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b1580156111fc575f80fd5b505af115801561120e573d5f803e3d5ffd5b50506079805477ffffffffffffffffffffffffffffffffffffffffffffffff167a093a800000000000000000000000000000000000000000000000001790555050604051828152339067ffffffffffffffff8616907fcc1b5520188bf1dd3e63f98164b577c4d75c11a619ddea692112f0d1aec4cf729060200160405180910390a350505050505050565b60795467ffffffffffffffff8281165f90815260786020526040812054909242926112dc92700100000000000000000000000000000000909204811691166159b6565b67ffffffffffffffff16111592915050565b607a5473ffffffffffffffffffffffffffffffffffffffff16331461133f576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff82161115611386576040517f1d06e87900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff166113f55760795467ffffffffffffffff78010000000000000000000000000000000000000000000000009091048116908216106113f5576040517f401636df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6079805477ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527f1f4fa24c2e4bad19a7f3ec5c5485f70d46c798461c2e684f55bbd0fc661373a190602001610ce6565b60745468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16331461151957606f5460ff16156114da576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e381611299565b611519576040517f0ce9e4a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61152281613fbf565b50565b607a5473ffffffffffffffffffffffffffffffffffffffff163314611576576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff821611156115bd576040517ff5e37f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff1661162857607b5467ffffffffffffffff74010000000000000000000000000000000000000000909104811690821610611628576040517ff5e37f2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527fa7eb6cb8a613eb4e8bddc1ac3d61ec6cf10898760f0b187bcca794c6ca6fa40b90602001610ce6565b60768054610b5a90615938565b606f5460ff16156116f3576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314611753576040517f11e7be1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f81900361178e576040517fcb591a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e88111156117ca576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000820481165f81815260726020526040812054838516949293700100000000000000000000000000000000909304909216919082905b86811015611c12575f8a8a83818110611830576118306159de565b90506020028101906118429190615a0b565b61184b90615a47565b8051805160209091012060608201519192509067ffffffffffffffff16156119c0578561187781615ad1565b9650505f81836020015184606001516040516020016118ce93929190928352602083019190915260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016604082015260480190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012067ffffffffffffffff8a165f90815260719093529120549091508114611956576040517fce3d755e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8088165f9081526071602052604080822091909155606085015190850151908216911610156119ba576040517f7f7ab87200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611afa565b602082015115801590611a84575060208201516040517f257b363200000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff169063257b3632906024016020604051808303815f875af1158015611a5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a829190615af7565b155b15611abb576040517f73bd668d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516201d4c01015611afa576040517fa29a6c7c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8767ffffffffffffffff16826040015167ffffffffffffffff161080611b2d575042826040015167ffffffffffffffff16115b15611b64576040517fea82791600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602082810151604080850151815193840189905290830184905260608084019290925260c01b7fffffffffffffffff0000000000000000000000000000000000000000000000001660808301528b901b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166088820152609c016040516020818303038152906040528051906020012094508160400151975050508080611c0a90615b0e565b915050611815565b50611c1d86856159b6565b60735490945067ffffffffffffffff780100000000000000000000000000000000000000000000000090910481169084161115611c86576040517fc630a00d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611c918285615b45565b611ca59067ffffffffffffffff1688615b66565b604080516060810182528581524267ffffffffffffffff908116602080840191825260738054680100000000000000009081900485168688019081528d86165f8181526072909552979093209551865592516001909501805492519585167fffffffffffffffffffffffffffffffff000000000000000000000000000000009384161795851684029590951790945583548c8416911617930292909217905590915082811690851614611d9a57607380547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8716021790555b611dec333083607054611dad9190615b79565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0169291906141cc565b611df46142ae565b7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede73ffffffffffffffffffffffffffffffffffffffff166379e2cf976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611e59575f80fd5b505af1158015611e6b573d5f803e3d5ffd5b505060405167ffffffffffffffff881692507f303446e6a8cb73c83dff421c0b1d5e5ce0719dab1bff13660fc254e58cc17fce91505f90a250505050505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314611f00576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b547c0100000000000000000000000000000000000000000000000000000000900460ff16611f5c576040517ff6ba91a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690556040517f854dd6ce5a1445c4c54388b21cffd11cf5bba1b9e763aec48ce3da75d617412f905f90a1565b5f6070546064611fbe9190615b79565b905090565b606f5460ff1615612000576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60795467ffffffffffffffff8581165f90815260726020526040902060010154429261204c927801000000000000000000000000000000000000000000000000909104811691166159b6565b67ffffffffffffffff16111561208e576040517f8a0704d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e861209b8686615b45565b67ffffffffffffffff1611156120dd576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120eb868686868686613f0e565b6120f48461435d565b607954700100000000000000000000000000000000900467ffffffffffffffff165f0361223557607480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8681169182179092555f908152607560205260409020839055607954161561219557607980547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690555b6040517f33d6247d000000000000000000000000000000000000000000000000000000008152600481018490527f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b15801561221a575f80fd5b505af115801561222c573d5f803e3d5ffd5b50505050612303565b61223d6142ae565b6079805467ffffffffffffffff16905f61225683615ad1565b825467ffffffffffffffff9182166101009390930a92830292820219169190911790915560408051608081018252428316815287831660208083019182528284018981526060840189815260795487165f908152607890935294909120925183549251861668010000000000000000027fffffffffffffffffffffffffffffffff000000000000000000000000000000009093169516949094171781559151600183015551600290910155505b604051828152339067ffffffffffffffff8616907f9c72852172521097ba7e1482e6b44b351323df0155f97f4ea18fcec28e1f596690602001611081565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612392576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fff0000000000000000000000000000000000000000ffffffffffffffffffffff166b01000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8416908102919091179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610ce6565b61241e614537565b6124275f6145b8565b565b60335473ffffffffffffffffffffffffffffffffffffffff16331461258e575f612451612d06565b90508067ffffffffffffffff168267ffffffffffffffff16116124a0576040517f812a372d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000909104811690831611806124e5575067ffffffffffffffff8083165f9081526072602052604090206001015416155b1561251c576040517f98c5c01400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8083165f90815260726020526040902060010154429161254a9162093a8091166159b6565b67ffffffffffffffff16111561258c576040517fd257555a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b61152261462e565b7f0000000000000000000000000000000000000000000000000000000000000000607c54146125f1576040517fc10b159000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607c8054905f61260083615b0e565b909155505060745467ffffffffffffffff16607d8190556040517fed7be53c9f1a96a481223b15568a5b1a475e01a74b347d6ca187c8bf0c078cd691610ce6917f0000000000000000000000000000000000000000000000000000000000000005908590615b90565b607b5473ffffffffffffffffffffffffffffffffffffffff1633146126ba576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b54607a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691821790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e9060200160405180910390a1565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f90819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb016906370a0823190602401602060405180830381865afa1580156127c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e59190615af7565b90505f6127f0612d06565b60735467ffffffffffffffff6801000000000000000082048116916128489170010000000000000000000000000000000082048116917801000000000000000000000000000000000000000000000000900416615b45565b61285291906159b6565b61285c9190615b45565b67ffffffffffffffff169050805f03612877575f9250505090565b6128818183615bf2565b9250505090565b606f5460ff16156128c5576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128d487878787878787613f6a565b67ffffffffffffffff84165f908152607560209081526040918290205482519081529081018490527f1f44c21118c4603cfb4e1b621dbcfa2b73efcececee2b99b620b2953d33a7010910160405180910390a161292f61462e565b50505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612989576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62093a8067ffffffffffffffff821611156129d0576040517fcc96507000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff16612a375760795467ffffffffffffffff700100000000000000000000000000000000909104811690821610612a37576040517f48a05a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607980547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8416908102919091179091556040519081527fc4121f4e22c69632ebb7cf1f462be0511dc034f999b52013eddfb24aab765c7590602001610ce6565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612b05576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620151808167ffffffffffffffff161115612b4c576040517fe067dfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff1661010067ffffffffffffffff8416908102919091179091556040519081527f1b023231a1ab6b5d93992f168fb44498e1a7e64cef58daff6f1c216de6a68c2890602001610ce6565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612c0b576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610ce6565b5f67ffffffff0000000167ffffffffffffffff8316108015612cb5575067ffffffff00000001604083901c67ffffffffffffffff16105b8015612cd6575067ffffffff00000001608083901c67ffffffffffffffff16105b8015612ced575067ffffffff0000000160c083901c105b15612cfa57506001919050565b505f919050565b919050565b6079545f9067ffffffffffffffff1615612d48575060795467ffffffffffffffff9081165f908152607860205260409020546801000000000000000090041690565b5060745467ffffffffffffffff1690565b607a5473ffffffffffffffffffffffffffffffffffffffff163314612daa576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6076612db68282615c4a565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610ce69190615434565b5f54610100900460ff1615808015612e0457505f54600160ff909116105b80612e1d5750303b158015612e1d57505f5460ff166001145b612eae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015612f0a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b612f176020880188615692565b607a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055612f6c6040880160208901615692565b606f805473ffffffffffffffffffffffffffffffffffffffff929092166b010000000000000000000000027fff0000000000000000000000000000000000000000ffffffffffffffffffffff909216919091179055612fd16080880160608901615692565b6074805473ffffffffffffffffffffffffffffffffffffffff9290921668010000000000000000027fffffffff0000000000000000000000000000000000000000ffffffffffffffff9092169190911790555f805260756020527ff9e3fbf150b7a0077118526f473c53cb4734f166167e2c6213e3567dd390b4ad869055607661305b8682615c4a565b5060776130688582615c4a565b5062093a8061307d6060890160408a016155be565b67ffffffffffffffff1611156130bf576040517fcc96507000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130cf60608801604089016155be565b6079805467ffffffffffffffff92909216700100000000000000000000000000000000027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff90921691909117905562093a8061313160a0890160808a016155be565b67ffffffffffffffff161115613173576040517f1d06e87900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61318360a08801608089016155be565b6079805477ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff939093169290920291909117905567016345785d8a0000607055606f80547fffffffffffffffffffffffffffffffffffffffffff00000000000000000000ff166a03ea000000000000070800179055607b80547fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff167c01000000000006978000000000000000000000000000000000000000001790556132626146b1565b7fed7be53c9f1a96a481223b15568a5b1a475e01a74b347d6ca187c8bf0c078cd65f7f000000000000000000000000000000000000000000000000000000000000000585856040516132b79493929190615da9565b60405180910390a1801561292f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b607b547c0100000000000000000000000000000000000000000000000000000000900460ff1615613386576040517f24eff8c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff16156133c3576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f8190036133fe576040517fcb591a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103e881111561343a576040517fb59f753a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff78010000000000000000000000000000000000000000000000008204811691613485918491700100000000000000000000000000000000900416615de0565b11156134bd576040517fc630a00d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60735467ffffffffffffffff68010000000000000000820481165f8181526072602052604081205491937001000000000000000000000000000000009004909216915b84811015613762575f87878381811061351b5761351b6159de565b905060200281019061352d9190615df3565b61353690615e25565b90508361354281615ad1565b825180516020918201208185015160408087015190519499509194505f936135a39386939101928352602083019190915260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016604082015260480190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012067ffffffffffffffff89165f9081526071909352912054909150811461362b576040517fce3d755e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff86165f9081526071602052604081205561364f600189615b66565b84036136be5742607b60149054906101000a900467ffffffffffffffff16846040015161367c91906159b6565b67ffffffffffffffff1611156136be576040517fc44a082100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020838101516040805192830188905282018490526060808301919091524260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016608083015233901b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166088820152609c01604051602081830303815290604052805190602001209450505050808061375a90615b0e565b915050613500565b5061376d84846159b6565b6073805467ffffffffffffffff4281167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009092168217808455604080516060810182528781526020808201958652680100000000000000009384900485168284019081528589165f818152607290935284832093518455965160019390930180549151871686027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921693871693909317179091558554938916700100000000000000000000000000000000027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff938602939093167fffffffffffffffff00000000000000000000000000000000ffffffffffffffff90941693909317919091179093559151929550917f648a61dd2438f072f5a1960939abd30f37aea80d2e94c9792ad142d3e0a490a49190a2505050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314613915576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede73ffffffffffffffffffffffffffffffffffffffff1663dbc169766040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561397a575f80fd5b505af115801561398c573d5f803e3d5ffd5b50505050612427614750565b607b547c0100000000000000000000000000000000000000000000000000000000900460ff16156139f5576040517f24eff8c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f5460ff1615613a32576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613a3b611fae565b905081811115613a77576040517f4732fdb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611388831115613ab3576040517fa29a6c7c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613af573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0163330846141cc565b5f7f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff16633ed691ef6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b839190615af7565b60738054919250780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16906018613bbd83615ad1565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550508484604051613bf4929190615e9e565b60408051918290038220602083015281018290527fffffffffffffffff0000000000000000000000000000000000000000000000004260c01b166060820152606801604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206073547801000000000000000000000000000000000000000000000000900467ffffffffffffffff165f9081526071909352912055323303613d22576073546040805183815233602082015260609181018290525f91810191909152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16907ff94bb37db835f1ab585ee00041849a09b12cd081d77fa15ca070757619cbc9319060800160405180910390a2613d81565b607360189054906101000a900467ffffffffffffffff1667ffffffffffffffff167ff94bb37db835f1ab585ee00041849a09b12cd081d77fa15ca070757619cbc93182338888604051613d789493929190615ead565b60405180910390a25b5050505050565b607a5473ffffffffffffffffffffffffffffffffffffffff163314613dd9576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b607480547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166801000000000000000073ffffffffffffffffffffffffffffffffffffffff8416908102919091179091556040519081527f61f8fec29495a3078e9271456f05fb0707fd4e41f7661865f80fc437d06681ca90602001610ce6565b613e62614537565b73ffffffffffffffffffffffffffffffffffffffff8116613f05576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401612ea5565b611522816145b8565b607d548567ffffffffffffffff161015613f54576040517fead1340b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613f628686868686866147de565b505050505050565b607d548567ffffffffffffffff161015613fb0576040517fead1340b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61292f87878787878787614b99565b60795467ffffffffffffffff680100000000000000009091048116908216111580613ff9575060795467ffffffffffffffff908116908216115b15614030576040517fd086b70b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8181165f81815260786020908152604080832080546074805468010000000000000000928390049098167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090981688179055600282015487865260759094529382902092909255607980547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff169390940292909217909255600182015490517f33d6247d00000000000000000000000000000000000000000000000000000000815260048101919091529091907f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb73ffffffffffffffffffffffffffffffffffffffff16906333d6247d906024015f604051808303815f87803b15801561415e575f80fd5b505af1158015614170573d5f803e3d5ffd5b505050508267ffffffffffffffff168167ffffffffffffffff167f328d3c6c0fd6f1be0515e422f2d87e59f25922cbc2233568515a0c4bc3f8510e84600201546040516141bf91815260200190565b60405180910390a3505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526142a89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152614fc8565b50505050565b60795467ffffffffffffffff680100000000000000008204811691161115612427576079545f906142f69068010000000000000000900467ffffffffffffffff1660016159b6565b905061430181611299565b15611522576079545f9060029061432390849067ffffffffffffffff16615b45565b61432d9190615ee2565b61433790836159b6565b905061434281611299565b156143545761435081613fbf565b5050565b61435082613fbf565b5f614366612d06565b9050815f806143758484615b45565b606f5467ffffffffffffffff91821692505f916143989161010090041642615b66565b90505b8467ffffffffffffffff168467ffffffffffffffff16146144225767ffffffffffffffff8085165f908152607260205260409020600181015490911682101561440057600181015468010000000000000000900467ffffffffffffffff16945061441c565b61440a8686615b45565b67ffffffffffffffff16935050614422565b5061439b565b5f61442d8484615b66565b90508381101561448457808403600c8111614448578061444b565b600c5b9050806103e80a81606f60099054906101000a900461ffff1661ffff160a607054028161447a5761447a615bc5565b04607055506144f3565b838103600c81116144955780614498565b600c5b90505f816103e80a82606f60099054906101000a900461ffff1661ffff160a670de0b6b3a764000002816144ce576144ce615bc5565b04905080607054670de0b6b3a764000002816144ec576144ec615bc5565b0460705550505b683635c9adc5dea00000607054111561451857683635c9adc5dea0000060705561292f565b633b9aca00607054101561292f57633b9aca0060705550505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314612427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401612ea5565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede73ffffffffffffffffffffffffffffffffffffffff16632072f6c56040518163ffffffff1660e01b81526004015f604051808303815f87803b158015614693575f80fd5b505af11580156146a5573d5f803e3d5ffd5b505050506124276150d8565b5f54610100900460ff16614747576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401612ea5565b612427336145b8565b606f5460ff1661478c576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f806147e8612d06565b905067ffffffffffffffff8816156148b75760795467ffffffffffffffff9081169089161115614844576040517fbb14c20500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8089165f9081526078602052604090206002810154815490945090918981166801000000000000000090920416146148b1576040517f2bd2e3e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50614957565b67ffffffffffffffff87165f90815260756020526040902054915081614909576040517f4997b98600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168767ffffffffffffffff161115614957576040517f1e56e9e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168667ffffffffffffffff16116149a4576040517fb9b18f5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6149b28888888689610cf1565b90505f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016002836040516149e69190615f08565b602060405180830381855afa158015614a01573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190614a249190615af7565b614a2e9190615f19565b6040805160208101825282815290517f9121da8a00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d61691639121da8a91614ab091899190600401615f2c565b602060405180830381865afa158015614acb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614aef9190615f66565b614b25576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614b8d33614b33858b615b45565b67ffffffffffffffff16614b45612735565b614b4f9190615b79565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb016919061516a565b50505050505050505050565b5f67ffffffffffffffff881615614c655760795467ffffffffffffffff9081169089161115614bf4576040517fbb14c20500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5067ffffffffffffffff8088165f908152607860205260409020600281015481549092888116680100000000000000009092041614614c5f576040517f2bd2e3e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50614d00565b5067ffffffffffffffff85165f9081526075602052604090205480614cb6576040517f4997b98600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60745467ffffffffffffffff9081169087161115614d00576040517f1e56e9e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60795467ffffffffffffffff9081169088161180614d3257508767ffffffffffffffff168767ffffffffffffffff1611155b80614d59575060795467ffffffffffffffff68010000000000000000909104811690881611155b15614d90576040517fbfa7079f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8781165f90815260786020526040902054680100000000000000009004811690861614614df2576040517f32a2a77f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f614e008787878588610cf1565b90505f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600283604051614e349190615f08565b602060405180830381855afa158015614e4f573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190614e729190615af7565b614e7c9190615f19565b6040805160208101825282815290517f9121da8a00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d61691639121da8a91614efe91889190600401615f2c565b602060405180830381865afa158015614f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614f3d9190615f66565b614f73576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff89165f90815260786020526040902060020154859003614b8d576040517fa47276bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f615029826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166151c09092919063ffffffff16565b8051909150156150d357808060200190518101906150479190615f66565b6150d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401612ea5565b505050565b606f5460ff1615615115576040517f2f0047fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526150d39084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401614226565b60606151ce84845f856151d6565b949350505050565b606082471015615268576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401612ea5565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516152909190615f08565b5f6040518083038185875af1925050503d805f81146152ca576040519150601f19603f3d011682016040523d82523d5f602084013e6152cf565b606091505b50915091506152e0878383876152eb565b979650505050505050565b606083156153805782515f036153795773ffffffffffffffffffffffffffffffffffffffff85163b615379576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612ea5565b50816151ce565b6151ce83838151156153955781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ea59190615434565b5f5b838110156153e35781810151838201526020016153cb565b50505f910152565b5f81518084526154028160208601602086016153c9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f61544660208301846153eb565b9392505050565b5f6020828403121561545d575f80fd5b813561ffff81168114615446575f80fd5b803567ffffffffffffffff81168114612d01575f80fd5b5f805f805f60a08688031215615499575f80fd5b6154a28661546e565b94506154b06020870161546e565b94979496505050506040830135926060810135926080909101359150565b8061030081018310156154df575f80fd5b92915050565b5f805f805f806103a087890312156154fb575f80fd5b6155048761546e565b95506155126020880161546e565b94506155206040880161546e565b9350606087013592506080870135915061553d8860a089016154ce565b90509295509295509295565b5f805f805f805f6103c0888a031215615560575f80fd5b6155698861546e565b96506155776020890161546e565b95506155856040890161546e565b94506155936060890161546e565b93506080880135925060a088013591506155b08960c08a016154ce565b905092959891949750929550565b5f602082840312156155ce575f80fd5b6154468261546e565b5f8083601f8401126155e7575f80fd5b50813567ffffffffffffffff8111156155fe575f80fd5b6020830191508360208260051b8501011115615618575f80fd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114612d01575f80fd5b5f805f60408486031215615654575f80fd5b833567ffffffffffffffff81111561566a575f80fd5b615676868287016155d7565b909450925061568990506020850161561f565b90509250925092565b5f602082840312156156a2575f80fd5b6154468261561f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126156e7575f80fd5b813567ffffffffffffffff80821115615702576157026156ab565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715615748576157486156ab565b81604052838152866020858801011115615760575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6020828403121561578f575f80fd5b813567ffffffffffffffff8111156157a5575f80fd5b6151ce848285016156d8565b5f602082840312156157c1575f80fd5b5035919050565b5f8083601f8401126157d8575f80fd5b50813567ffffffffffffffff8111156157ef575f80fd5b602083019150836020828501011115615618575f80fd5b5f805f805f8086880361012081121561581d575f80fd5b60a081121561582a575f80fd5b5086955060a0870135945060c087013567ffffffffffffffff8082111561584f575f80fd5b61585b8a838b016156d8565b955060e0890135915080821115615870575f80fd5b61587c8a838b016156d8565b9450610100890135915080821115615892575f80fd5b5061589f89828a016157c8565b979a9699509497509295939492505050565b5f80602083850312156158c2575f80fd5b823567ffffffffffffffff8111156158d8575f80fd5b6158e4858286016155d7565b90969095509350505050565b5f805f60408486031215615902575f80fd5b833567ffffffffffffffff811115615918575f80fd5b615924868287016157c8565b909790965060209590950135949350505050565b600181811c9082168061594c57607f821691505b602082108103615983577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff8181168382160190808211156159d7576159d7615989565b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112615a3d575f80fd5b9190910192915050565b5f60808236031215615a57575f80fd5b6040516080810167ffffffffffffffff8282108183111715615a7b57615a7b6156ab565b816040528435915080821115615a8f575f80fd5b50615a9c368286016156d8565b82525060208301356020820152615ab56040840161546e565b6040820152615ac66060840161546e565b606082015292915050565b5f67ffffffffffffffff808316818103615aed57615aed615989565b6001019392505050565b5f60208284031215615b07575f80fd5b5051919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b3e57615b3e615989565b5060010190565b67ffffffffffffffff8281168282160390808211156159d7576159d7615989565b818103818111156154df576154df615989565b80820281158282048414176154df576154df615989565b5f67ffffffffffffffff808616835280851660208401525060606040830152615bbc60608301846153eb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615c0057615c00615bc5565b500490565b601f8211156150d3575f81815260208120601f850160051c81016020861015615c2b5750805b601f850160051c820191505b81811015613f6257828155600101615c37565b815167ffffffffffffffff811115615c6457615c646156ab565b615c7881615c728454615938565b84615c05565b602080601f831160018114615cca575f8415615c945750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613f62565b5f858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615d1657888601518255948401946001909101908401615cf7565b5085821015615d5257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f67ffffffffffffffff808716835280861660208401525060606040830152615dd6606083018486615d62565b9695505050505050565b808201808211156154df576154df615989565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112615a3d575f80fd5b5f60608236031215615e35575f80fd5b6040516060810167ffffffffffffffff8282108183111715615e5957615e596156ab565b816040528435915080821115615e6d575f80fd5b50615e7a368286016156d8565b82525060208301356020820152615e936040840161546e565b604082015292915050565b818382375f9101908152919050565b84815273ffffffffffffffffffffffffffffffffffffffff84166020820152606060408201525f615dd6606083018486615d62565b5f67ffffffffffffffff80841680615efc57615efc615bc5565b92169190910492915050565b5f8251615a3d8184602087016153c9565b5f82615f2757615f27615bc5565b500690565b6103208101610300808584378201835f5b6001811015615f5c578151835260209283019290910190600101615f3d565b5050509392505050565b5f60208284031215615f76575f80fd5b81518015158114615446575f80fdfea2646970667358221220c127415502dda9601f3fb40aaec997c6ddf247345b4659c2aa077ef0bb1d722a64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb000000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede000000000000000000000000000000000000000000000000000000000000044d00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _globalExitRootManager (address): 0x580bda1e7A0CFAe92Fa7F6c20A3794F169CE3CFb
Arg [1] : _matic (address): 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0
Arg [2] : _rollupVerifier (address): 0x21f65deadb3b85082BA99766f323bEA90eb5a3D6
Arg [3] : _bridgeAddress (address): 0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe
Arg [4] : _chainID (uint64): 1101
Arg [5] : _forkID (uint64): 5
Arg [6] : versionBeforeUpgrade (uint256): 0
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb
Arg [1] : 0000000000000000000000007d1afa7b718fb893db30a3abc0cfc608aacfebb0
Arg [2] : 00000000000000000000000021f65deadb3b85082ba99766f323bea90eb5a3d6
Arg [3] : 0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede
Arg [4] : 000000000000000000000000000000000000000000000000000000000000044d
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.