Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Rollup
Compiler Version
v0.8.16+commit.07a7930e
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2024-01-23 */ // SPDX-License-Identifier: MIT pragma solidity =0.8.16; // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } } /** * @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; } /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } /** * @title SafeCall * @notice Perform low level safe calls */ library SafeCall { /** * @notice Performs a low level call without copying any returndata. * @dev Passes no calldata to the call context. * * @param _target Address to call * @param _gas Amount of gas to pass to the call * @param _value Amount of value to pass to the call */ function send( address _target, uint256 _gas, uint256 _value ) internal returns (bool) { bool _success; assembly { _success := call( _gas, // gas _target, // recipient _value, // ether value 0, // inloc 0, // inlen 0, // outloc 0 // outlen ) } return _success; } /** * @notice Perform a low level call without copying any returndata * * @param _target Address to call * @param _gas Amount of gas to pass to the call * @param _value Amount of value to pass to the call * @param _calldata Calldata to pass to the call */ function call( address _target, uint256 _gas, uint256 _value, bytes memory _calldata ) internal returns (bool) { bool _success; assembly { _success := call( _gas, // gas _target, // recipient _value, // ether value add(_calldata, 32), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) } return _success; } /** * @notice Helper function to determine if there is sufficient gas remaining within the context * to guarantee that the minimum gas requirement for a call will be met as well as * optionally reserving a specified amount of gas for after the call has concluded. * @param _minGas The minimum amount of gas that may be passed to the target context. * @param _reservedGas Optional amount of gas to reserve for the caller after the execution * of the target context. * @return `true` if there is enough gas remaining to safely supply `_minGas` to the target * context as well as reserve `_reservedGas` for the caller after the execution of * the target context. * @dev !!!!! FOOTGUN ALERT !!!!! * 1.) The 40_000 base buffer is to account for the worst case of the dynamic cost of the * `CALL` opcode's `address_access_cost`, `positive_value_cost`, and * `value_to_empty_account_cost` factors with an added buffer of 5,700 gas. It is * still possible to self-rekt by initiating a withdrawal with a minimum gas limit * that does not account for the `memory_expansion_cost` & `code_execution_cost` * factors of the dynamic cost of the `CALL` opcode. * 2.) This function should *directly* precede the external call if possible. There is an * added buffer to account for gas consumed between this check and the call, but it * is only 5,700 gas. * 3.) Because EIP-150 ensures that a maximum of 63/64ths of the remaining gas in the call * frame may be passed to a subcontext, we need to ensure that the gas will not be * truncated. * 4.) Use wisely. This function is not a silver bullet. */ function hasMinGas(uint256 _minGas, uint256 _reservedGas) internal view returns (bool) { bool _hasMinGas; assembly { // Equation: gas × 63 ≥ minGas × 64 + 63(40_000 + reservedGas) _hasMinGas := iszero( lt(mul(gas(), 63), add(mul(_minGas, 64), mul(add(40000, _reservedGas), 63))) ) } return _hasMinGas; } /** * @notice Perform a low level call without copying any returndata. This function * will revert if the call cannot be performed with the specified minimum * gas. * * @param _target Address to call * @param _minGas The minimum amount of gas that may be passed to the call * @param _value Amount of value to pass to the call * @param _calldata Calldata to pass to the call */ function callWithMinGas( address _target, uint256 _minGas, uint256 _value, bytes memory _calldata ) internal returns (bool) { bool _success; bool _hasMinGas = hasMinGas(_minGas, 0); assembly { // Assertion: gasleft() >= (_minGas * 64) / 63 + 40_000 if iszero(_hasMinGas) { // Store the "Error(string)" selector in scratch space. mstore(0, 0x08c379a0) // Store the pointer to the string length in scratch space. mstore(32, 32) // Store the string. // // SAFETY: // - We pad the beginning of the string with two zero bytes as well as the // length (24) to ensure that we override the free memory pointer at offset // 0x40. This is necessary because the free memory pointer is likely to // be greater than 1 byte when this function is called, but it is incredibly // unlikely that it will be greater than 3 bytes. As for the data within // 0x60, it is ensured that it is 0 due to 0x60 being the zero offset. // - It's fine to clobber the free memory pointer, we're reverting. mstore(88, 0x0000185361666543616c6c3a204e6f7420656e6f75676820676173) // Revert with 'Error("SafeCall: Not enough gas")' revert(28, 100) } // The call will be supplied at least ((_minGas * 64) / 63) gas due to the // above assertion. This ensures that, in all circumstances (except for when the // `_minGas` does not account for the `memory_expansion_cost` and `code_execution_cost` // factors of the dynamic cost of the `CALL` opcode), the call will receive at least // the minimum amount of gas specified. _success := call( gas(), // gas _target, // recipient _value, // ether value add(_calldata, 32), // inloc mload(_calldata), // inlen 0x00, // outloc 0x00 // outlen ) } return _success; } } /** * @title Types * @notice Contains various types used throughout the Morph contract system. */ library Types { /** * @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end * user (as opposed to a system deposit transaction generated by the system). * * @custom:field queueIndex Index of the transaction. * @custom:field gas Gas limit of the transaction. * @custom:field to Address of the recipient of the transaction. * @custom:field value Value to send to the recipient. * @custom:field data Data of the transaction. * @custom:field sender Address of the sender of the transaction. */ struct L1MessageTx { uint64 queueIndex; uint64 gas; address to; uint256 value; bytes data; address sender; } /** * @notice Struct representing a withdrawal transaction. * * @custom:field nonce Nonce of the withdrawal transaction * @custom:field sender Address of the sender of the transaction. * @custom:field target Address of the recipient of the transaction. * @custom:field value Value to send to the recipient. * @custom:field gasLimit Gas limit of the transaction. * @custom:field data Data of the transaction. */ struct WithdrawalTransaction { uint256 nonce; address sender; address target; uint256 value; uint256 gasLimit; bytes data; } /** * @notice Struct representing a sequencer information. * * @custom:field addr Address of the sequencer. * @custom:field tmKey Tendermint key(ED25519) of the seuqencer. * @custom:field blsKey BLS key of the seuqencer. */ struct SequencerInfo { address addr; bytes32 tmKey; bytes blsKey; } /** * @notice BatchInfo representing a batch. * * @custom:field submitter batch submitter * @custom:field startBlock batch start block * @custom:field endBlock batch end block * @custom:field rollupTime batch rollup time * @custom:field maxChunks max chunks */ struct BatchInfo { address submitter; uint256 startBlock; uint256 endBlock; uint256 rollupTime; } /** * @notice BatchInfo representing a epoch. * * @custom:field submitter submitter * @custom:field startTime epoch start time * @custom:field endTime epoch end time */ struct EpochInfo { address submitter; uint256 startTime; uint256 endTime; } } /** * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode * @title RLPWriter * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor * modifications to improve legibility. */ library RLPWriter { /** * @notice RLP encodes a byte string. * * @param _in The byte string to encode. * * @return The RLP encoded string in bytes. */ function writeBytes(bytes memory _in) internal pure returns (bytes memory) { bytes memory encoded; if (_in.length == 1 && uint8(_in[0]) < 128) { encoded = _in; } else { encoded = abi.encodePacked(_writeLength(_in.length, 128), _in); } return encoded; } /** * @notice RLP encodes a list of RLP encoded byte byte strings. * * @param _in The list of RLP encoded byte strings. * * @return The RLP encoded list of items in bytes. */ function writeList(bytes[] memory _in) internal pure returns (bytes memory) { bytes memory list = _flatten(_in); return abi.encodePacked(_writeLength(list.length, 192), list); } /** * @notice RLP encodes a string. * * @param _in The string to encode. * * @return The RLP encoded string in bytes. */ function writeString(string memory _in) internal pure returns (bytes memory) { return writeBytes(bytes(_in)); } /** * @notice RLP encodes an address. * * @param _in The address to encode. * * @return The RLP encoded address in bytes. */ function writeAddress(address _in) internal pure returns (bytes memory) { return writeBytes(abi.encodePacked(_in)); } /** * @notice RLP encodes a uint. * * @param _in The uint256 to encode. * * @return The RLP encoded uint256 in bytes. */ function writeUint(uint256 _in) internal pure returns (bytes memory) { return writeBytes(_toBinary(_in)); } /** * @notice RLP encodes a bool. * * @param _in The bool to encode. * * @return The RLP encoded bool in bytes. */ function writeBool(bool _in) internal pure returns (bytes memory) { bytes memory encoded = new bytes(1); encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80)); return encoded; } /** * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55. * * @param _len The length of the string or the payload. * @param _offset 128 if item is string, 192 if item is list. * * @return RLP encoded bytes. */ function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) { bytes memory encoded; if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len) + uint8(_offset)); } else { uint256 lenLen; uint256 i = 1; while (_len / i != 0) { lenLen++; i *= 256; } encoded = new bytes(lenLen + 1); encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55); for (i = 1; i <= lenLen; i++) { encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256)); } } return encoded; } /** * @notice Encode integer in big endian binary form with no leading zeroes. * * @param _x The integer to encode. * * @return RLP encoded bytes. */ function _toBinary(uint256 _x) private pure returns (bytes memory) { bytes memory b = abi.encodePacked(_x); uint256 i = 0; for (; i < 32; i++) { if (b[i] != 0) { break; } } bytes memory res = new bytes(32 - i); for (uint256 j = 0; j < res.length; j++) { res[j] = b[i++]; } return res; } /** * @custom:attribution https://github.com/Arachnid/solidity-stringutils * @notice Copies a piece of memory to another location. * * @param _dest Destination location. * @param _src Source location. * @param _len Length of memory to copy. */ function _memcpy( uint256 _dest, uint256 _src, uint256 _len ) private pure { uint256 dest = _dest; uint256 src = _src; uint256 len = _len; for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } uint256 mask; unchecked { mask = 256**(32 - len) - 1; } assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } /** * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder * @notice Flattens a list of byte strings into one byte string. * * @param _list List of byte strings to flatten. * * @return The flattened byte string. */ function _flatten(bytes[] memory _list) private pure returns (bytes memory) { if (_list.length == 0) { return new bytes(0); } uint256 len; uint256 i = 0; for (; i < _list.length; i++) { len += _list[i].length; } bytes memory flattened = new bytes(len); uint256 flattenedPtr; assembly { flattenedPtr := add(flattened, 0x20) } for (i = 0; i < _list.length; i++) { bytes memory item = _list[i]; uint256 listPtr; assembly { listPtr := add(item, 0x20) } _memcpy(flattenedPtr, listPtr, item.length); flattenedPtr += _list[i].length; } return flattened; } } /** * @custom:attribution https://github.com/hamdiallam/Solidity-RLP * @title RLPReader * @notice RLPReader is a library for parsing RLP-encoded byte arrays into Solidity types. Adapted * from Solidity-RLP (https://github.com/hamdiallam/Solidity-RLP) by Hamdi Allam with * various tweaks to improve readability. */ library RLPReader { /** * Custom pointer type to avoid confusion between pointers and uint256s. */ type MemoryPointer is uint256; /** * @notice RLP item types. * * @custom:value DATA_ITEM Represents an RLP data item (NOT a list). * @custom:value LIST_ITEM Represents an RLP list item. */ enum RLPItemType { DATA_ITEM, LIST_ITEM } /** * @notice Struct representing an RLP item. * * @custom:field length Length of the RLP item. * @custom:field ptr Pointer to the RLP item in memory. */ struct RLPItem { uint256 length; MemoryPointer ptr; } /** * @notice Max list length that this library will accept. */ uint256 internal constant MAX_LIST_LENGTH = 32; /** * @notice Converts bytes to a reference to memory position and length. * * @param _in Input bytes to convert. * * @return Output memory reference. */ function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) { // Empty arrays are not RLP items. require( _in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable" ); MemoryPointer ptr; assembly { ptr := add(_in, 32) } return RLPItem({ length: _in.length, ptr: ptr }); } /** * @notice Reads an RLP list value into a list of RLP items. * * @param _in RLP list value. * * @return Decoded RLP list items. */ function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) { (uint256 listOffset, uint256 listLength, RLPItemType itemType) = _decodeLength(_in); require( itemType == RLPItemType.LIST_ITEM, "RLPReader: decoded item type for list is not a list item" ); require( listOffset + listLength == _in.length, "RLPReader: list item has an invalid data remainder" ); // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by // writing to the length. Since we can't know the number of RLP items without looping over // the entire input, we'd have to loop twice to accurately size this array. It's easier to // simply set a reasonable maximum list length and decrease the size before we finish. RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH); uint256 itemCount = 0; uint256 offset = listOffset; while (offset < _in.length) { (uint256 itemOffset, uint256 itemLength, ) = _decodeLength( RLPItem({ length: _in.length - offset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }) ); // We don't need to check itemCount < out.length explicitly because Solidity already // handles this check on our behalf, we'd just be wasting gas. out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }); itemCount += 1; offset += itemOffset + itemLength; } // Decrease the array size to match the actual item count. assembly { mstore(out, itemCount) } return out; } /** * @notice Reads an RLP list value into a list of RLP items. * * @param _in RLP list value. * * @return Decoded RLP list items. */ function readList(bytes memory _in) internal pure returns (RLPItem[] memory) { return readList(toRLPItem(_in)); } /** * @notice Reads an RLP bytes value into bytes. * * @param _in RLP bytes value. * * @return Decoded bytes. */ function readBytes(RLPItem memory _in) internal pure returns (bytes memory) { (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require( itemType == RLPItemType.DATA_ITEM, "RLPReader: decoded item type for bytes is not a data item" ); require( _in.length == itemOffset + itemLength, "RLPReader: bytes value contains an invalid remainder" ); return _copy(_in.ptr, itemOffset, itemLength); } /** * @notice Reads an RLP bytes value into bytes. * * @param _in RLP bytes value. * * @return Decoded bytes. */ function readBytes(bytes memory _in) internal pure returns (bytes memory) { return readBytes(toRLPItem(_in)); } /** * @notice Reads the raw bytes of an RLP item. * * @param _in RLP item to read. * * @return Raw RLP bytes. */ function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) { return _copy(_in.ptr, 0, _in.length); } /** * @notice Decodes the length of an RLP item. * * @param _in RLP item to decode. * * @return Offset of the encoded data. * @return Length of the encoded data. * @return RLP item type (LIST_ITEM or DATA_ITEM). */ function _decodeLength(RLPItem memory _in) private pure returns ( uint256, uint256, RLPItemType ) { // Short-circuit if there's nothing to decode, note that we perform this check when // the user creates an RLP item via toRLPItem, but it's always possible for them to bypass // that function and create an RLP item directly. So we need to check this anyway. require( _in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable" ); MemoryPointer ptr = _in.ptr; uint256 prefix; assembly { prefix := byte(0, mload(ptr)) } if (prefix <= 0x7f) { // Single byte. return (0, 1, RLPItemType.DATA_ITEM); } else if (prefix <= 0xb7) { // Short string. // slither-disable-next-line variable-scope uint256 strLen = prefix - 0x80; require( _in.length > strLen, "RLPReader: length of content must be greater than string length (short string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( strLen != 1 || firstByteOfContent >= 0x80, "RLPReader: invalid prefix, single byte < 0x80 are not prefixed (short string)" ); return (1, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xbf) { // Long string. uint256 lenOfStrLen = prefix - 0xb7; require( _in.length > lenOfStrLen, "RLPReader: length of content must be > than length of string length (long string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long string)" ); uint256 strLen; assembly { strLen := shr(sub(256, mul(8, lenOfStrLen)), mload(add(ptr, 1))) } require( strLen > 55, "RLPReader: length of content must be greater than 55 bytes (long string)" ); require( _in.length > lenOfStrLen + strLen, "RLPReader: length of content must be greater than total length (long string)" ); return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xf7) { // Short list. // slither-disable-next-line variable-scope uint256 listLen = prefix - 0xc0; require( _in.length > listLen, "RLPReader: length of content must be greater than list length (short list)" ); return (1, listLen, RLPItemType.LIST_ITEM); } else { // Long list. uint256 lenOfListLen = prefix - 0xf7; require( _in.length > lenOfListLen, "RLPReader: length of content must be > than length of list length (long list)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long list)" ); uint256 listLen; assembly { listLen := shr(sub(256, mul(8, lenOfListLen)), mload(add(ptr, 1))) } require( listLen > 55, "RLPReader: length of content must be greater than 55 bytes (long list)" ); require( _in.length > lenOfListLen + listLen, "RLPReader: length of content must be greater than total length (long list)" ); return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM); } } /** * @notice Copies the bytes from a memory location. * * @param _src Pointer to the location to read from. * @param _offset Offset to start reading from. * @param _length Number of bytes to read. * * @return Copied bytes. */ function _copy( MemoryPointer _src, uint256 _offset, uint256 _length ) private pure returns (bytes memory) { bytes memory out = new bytes(_length); if (_length == 0) { return out; } // Mostly based on Solidity's copy_memory_to_memory: // solhint-disable max-line-length // https://github.com/ethereum/solidity/blob/34dd30d71b4da730488be72ff6af7083cf2a91f6/libsolidity/codegen/YulUtilFunctions.cpp#L102-L114 uint256 src = MemoryPointer.unwrap(_src) + _offset; assembly { let dest := add(out, 32) let i := 0 for { } lt(i, _length) { i := add(i, 32) } { mstore(add(dest, i), mload(add(src, i))) } if gt(i, _length) { mstore(add(dest, _length), 0) } } return out; } } /** * @title Encoding * @notice Encoding handles Morph's various different encoding schemes. */ library Encoding { /** * @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent * to the L2 system. Useful for searching for a deposit in the L2 system. The * transaction is prefixed with 0x7e to identify its EIP-2718 type. * * @param _tx User deposit transaction to encode. * * @return RLP encoded L2 deposit transaction. */ function encodeL1MessageTx( Types.L1MessageTx memory _tx ) internal pure returns (bytes memory) { bytes[] memory raw = new bytes[](6); raw[0] = RLPWriter.writeUint(uint256(_tx.queueIndex)); raw[1] = RLPWriter.writeUint(uint256(_tx.gas)); raw[2] = RLPWriter.writeAddress(_tx.to); raw[3] = RLPWriter.writeUint(_tx.value); raw[4] = RLPWriter.writeBytes(_tx.data); raw[5] = RLPWriter.writeAddress(_tx.sender); return abi.encodePacked(uint8(0x7e), RLPWriter.writeList(raw)); } /** * @notice Encodes the cross domain message based on the version that is encoded into the * message nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Encoded cross domain message. */ function encodeCrossDomainMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes memory) { (, uint16 version) = decodeVersionedNonce(_nonce); if (version == 0) { return encodeCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { return encodeCrossDomainMessageV1( _nonce, _sender, _target, _value, _gasLimit, _data ); } else { revert("Encoding: unknown cross domain message version"); } } /** * @notice Encodes a cross domain message based on the V0 (legacy) encoding. * * @param _target Address of the target of the message. * @param _sender Address of the sender of the message. * @param _data Data to send with the message. * @param _nonce Message nonce. * * @return Encoded cross domain message. */ function encodeCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes memory) { return abi.encodeWithSignature( "relayMessage(address,address,bytes,uint256)", _target, _sender, _data, _nonce ); } /** * @notice Encodes a cross domain message based on the V1 (current) encoding. * * @param _nonce Message nonce. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Encoded cross domain message. */ function encodeCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes memory) { return abi.encodeWithSignature( "relayMessage(uint256,address,address,uint256,uint256,bytes)", _nonce, _sender, _target, _value, _gasLimit, _data ); } /** * @notice Adds a version number into the first two bytes of a message nonce. * * @param _nonce Message nonce to encode into. * @param _version Version number to encode into the message nonce. * * @return Message nonce with version encoded into the first two bytes. */ function encodeVersionedNonce( uint240 _nonce, uint16 _version ) internal pure returns (uint256) { uint256 nonce; assembly { nonce := or(shl(240, _version), _nonce) } return nonce; } /** * @notice Pulls the version out of a version-encoded nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * * @return Nonce without encoded version. * @return Version of the message. */ function decodeVersionedNonce( uint256 _nonce ) internal pure returns (uint240, uint16) { uint240 nonce; uint16 version; assembly { nonce := and( _nonce, 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ) version := shr(240, _nonce) } return (nonce, version); } /** * @notice Encodes sequencers information with length. * * @param infos Sequencer informations. * * @return Encoded Sequencer informations with length. */ function encodeSequencerInfos( Types.SequencerInfo[] memory infos ) internal pure returns (bytes memory) { uint256 len = infos.length; bytes[] memory raw = new bytes[](len + 1); raw[0] = RLPWriter.writeUint(len); for (uint256 i = 0; i < len; i++) { bytes memory data = abi.encode(infos[i]); raw[i + 1] = RLPWriter.writeBytes(data); } return RLPWriter.writeList(raw); } /** * @notice Decodes sequencers information. * * @return Decode Sequencer informations array. */ function decodeSequencerInfos( bytes memory infosBytes ) internal pure returns (Types.SequencerInfo[] memory) { RLPReader.RLPItem memory rlpitem = RLPReader.toRLPItem(infosBytes); RLPReader.RLPItem[] memory list = RLPReader.readList(rlpitem); bytes memory lenBytes = RLPReader.readBytes(list[0]); uint256 len = abi.decode(padWithZero(lenBytes), (uint256)); Types.SequencerInfo[] memory sequencerInfos = new Types.SequencerInfo[]( len ); for (uint256 i = 0; i < len; i++) { sequencerInfos[i] = abi.decode( RLPReader.readBytes(list[i + 1]), (Types.SequencerInfo) ); } return sequencerInfos; } function padWithZero( bytes memory data ) internal pure returns (bytes memory) { require(data.length <= 32, "Data length exceeds 32 bytes"); uint256 bytesLen = 32; bytes memory paddedData = new bytes(bytesLen); for (uint256 i = 0; i < data.length; i++) { paddedData[bytesLen - data.length + i] = data[i]; } return paddedData; } } /** * @title Hashing * @notice Hashing handles Morph's various different hashing schemes. */ library Hashing { /** * @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a * given deposit is sent to the L2 system. Useful for searching for a deposit in the L2 * system. * * @param _tx User deposit transaction to hash. * * @return Hash of the RLP encoded L2 deposit transaction. */ function hashL1MessageTx( Types.L1MessageTx memory _tx ) internal pure returns (bytes32) { return keccak256(Encoding.encodeL1MessageTx(_tx)); } /** * @notice Computes the deposit transaction's "source hash", a value that guarantees the hash * of the L2 transaction that corresponds to a deposit is unique and is * deterministically generated from L1 transaction data. * * @param _l1BlockHash Hash of the L1 block where the deposit was included. * @param _logIndex The index of the log that created the deposit transaction. * * @return Hash of the deposit transaction's "source hash". */ function hashDepositSource( bytes32 _l1BlockHash, uint256 _logIndex ) internal pure returns (bytes32) { bytes32 depositId = keccak256(abi.encode(_l1BlockHash, _logIndex)); return keccak256(abi.encode(bytes32(0), depositId)); } /** * @notice Hashes the cross domain message based on the version that is encoded into the * message nonce. * * @param _nonce Message nonce with version encoded into the first two bytes. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Hashed cross domain message. */ function hashCrossDomainMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes32) { (, uint16 version) = Encoding.decodeVersionedNonce(_nonce); if (version == 0) { return hashCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { return hashCrossDomainMessageV1( _nonce, _sender, _target, _value, _gasLimit, _data ); } else { revert("Hashing: unknown cross domain message version"); } } /** * @notice Hashes a cross domain message based on the V0 (legacy) encoding. * * @param _target Address of the target of the message. * @param _sender Address of the sender of the message. * @param _data Data to send with the message. * @param _nonce Message nonce. * * @return Hashed cross domain message. */ function hashCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes32) { return keccak256( Encoding.encodeCrossDomainMessageV0( _target, _sender, _data, _nonce ) ); } /** * @notice Hashes a cross domain message based on the V1 (current) encoding. * * @param _nonce Message nonce. * @param _sender Address of the sender of the message. * @param _target Address of the target of the message. * @param _value ETH value to send to the target. * @param _gasLimit Gas limit to use for the message. * @param _data Data to send with the message. * * @return Hashed cross domain message. */ function hashCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes32) { return keccak256( Encoding.encodeCrossDomainMessageV1( _nonce, _sender, _target, _value, _gasLimit, _data ) ); } /** * @notice Derives the withdrawal hash according to the encoding in the L2 Withdrawer contract * * @param _tx Withdrawal transaction to hash. * * @return Hashed withdrawal transaction. */ function hashWithdrawal( Types.WithdrawalTransaction memory _tx ) internal pure returns (bytes32) { return keccak256( abi.encode( _tx.nonce, _tx.sender, _tx.target, _tx.value, _tx.gasLimit, _tx.data ) ); } } // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } } /** * @title Burn * @notice Utilities for burning stuff. */ library Burn { /** * Burns a given amount of ETH. * * @param _amount Amount of ETH to burn. */ function eth(uint256 _amount) internal { new Burner{ value: _amount }(); } /** * Burns a given amount of gas. * * @param _amount Amount of gas to burn. */ function gas(uint256 _amount) internal view { uint256 i = 0; uint256 initialGas = gasleft(); while (initialGas - gasleft() < _amount) { ++i; } } } /** * @title Burner * @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to * the contract from the circulating supply. Self-destructing is the only way to remove ETH * from the circulating supply. */ contract Burner { constructor() payable { selfdestruct(payable(address(this))); } } // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } } /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } function powWad(int256 x, int256 y) internal pure returns (int256) { // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0. } function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return 0; // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); } } function lnWad(int256 x) internal pure returns (int256 r) { unchecked { require(x > 0, "UNDEFINED"); // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) int256 k = int256(log2(uint256(x))) - 96; x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function log2(uint256 x) internal pure returns (uint256 r) { require(x > 0, "UNDEFINED"); assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } } } /** * @title Arithmetic * @notice Even more math than before. */ library Arithmetic { /** * @notice Clamps a value between a minimum and maximum. * * @param _value The value to clamp. * @param _min The minimum value. * @param _max The maximum value. * * @return The clamped value. */ function clamp( int256 _value, int256 _min, int256 _max ) internal pure returns (int256) { return SignedMath.min(SignedMath.max(_value, _min), _max); } /** * @notice (c)oefficient (d)enominator (exp)onentiation function. * Returns the result of: c * (1 - 1/d)^exp. * * @param _coefficient Coefficient of the function. * @param _denominator Fractional denominator. * @param _exponent Power function exponent. * * @return Result of c * (1 - 1/d)^exp. */ function cdexp( int256 _coefficient, int256 _denominator, int256 _exponent ) internal pure returns (int256) { return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18; } } /** * @custom:upgradeable * @title ResourceMetering * @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing * updates automatically based on current demand. */ abstract contract ResourceMetering is Initializable { /** * @notice Represents the various parameters that control the way in which resources are * metered. Corresponds to the EIP-1559 resource metering system. * * @custom:field prevBaseFee Base fee from the previous block(s). * @custom:field prevBoughtGas Amount of gas bought so far in the current block. * @custom:field prevBlockNum Last block number that the base fee was updated. */ struct ResourceParams { uint128 prevBaseFee; uint64 prevBoughtGas; uint64 prevBlockNum; } /** * @notice Represents the configuration for the EIP-1559 based curve for the deposit gas * market. These values should be set with care as it is possible to set them in * a way that breaks the deposit gas market. The target resource limit is defined as * maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a * single word. There is additional space for additions in the future. * * @custom:field maxResourceLimit Represents the maximum amount of deposit gas that * can be purchased per block. * @custom:field elasticityMultiplier Determines the target resource limit along with * the resource limit. * @custom:field baseFeeMaxChangeDenominator Determines max change on fee per block. * @custom:field minimumBaseFee The min deposit base fee, it is clamped to this * value. * @custom:field systemTxMaxGas The amount of gas supplied to the system * transaction. This should be set to the same number * that the op-node sets as the gas limit for the * system transaction. * @custom:field maximumBaseFee The max deposit base fee, it is clamped to this * value. */ struct ResourceConfig { uint32 maxResourceLimit; uint8 elasticityMultiplier; uint8 baseFeeMaxChangeDenominator; uint32 minimumBaseFee; uint32 systemTxMaxGas; uint128 maximumBaseFee; } /** * @notice EIP-1559 style gas parameters. */ ResourceParams public params; /** * @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. */ uint256[48] private __gap; /** * @notice Meters access to a function based an amount of a requested resource. * * @param _amount Amount of the resource requested. */ modifier metered(uint64 _amount) { // Record initial gas amount so we can refund for it later. uint256 initialGas = gasleft(); // Run the underlying function. _; // Run the metering function. _metered(_amount, initialGas); } /** * @notice An internal function that holds all of the logic for metering a resource. * * @param _amount Amount of the resource requested. * @param _initialGas The amount of gas before any modifier execution. */ function _metered(uint64 _amount, uint256 _initialGas) internal { // Update block number and base fee if necessary. uint256 blockDiff = block.number - params.prevBlockNum; ResourceConfig memory config = _resourceConfig(); int256 targetResourceLimit = int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier)); if (blockDiff > 0) { // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate // at which deposits can be created and therefore limit the potential for deposits to // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes. int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit; int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta) / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator))); // Update base fee by adding the base fee delta and clamp the resulting value between // min and max. int256 newBaseFee = Arithmetic.clamp({ _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta, _min: int256(uint256(config.minimumBaseFee)), _max: int256(uint256(config.maximumBaseFee)) }); // If we skipped more than one block, we also need to account for every empty block. // Empty block means there was no demand for deposits in that block, so we should // reflect this lack of demand in the fee. if (blockDiff > 1) { // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator) // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value // between min and max. newBaseFee = Arithmetic.clamp({ _value: Arithmetic.cdexp({ _coefficient: newBaseFee, _denominator: int256( uint256(config.baseFeeMaxChangeDenominator) ), _exponent: int256(blockDiff - 1) }), _min: int256(uint256(config.minimumBaseFee)), _max: int256(uint256(config.maximumBaseFee)) }); } // Update new base fee, reset bought gas, and update block number. params.prevBaseFee = uint128(uint256(newBaseFee)); params.prevBoughtGas = 0; params.prevBlockNum = uint64(block.number); } // Make sure we can actually buy the resource amount requested by the user. params.prevBoughtGas += _amount; require( int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)), "ResourceMetering: cannot buy more gas than available gas limit" ); // Determine the amount of ETH to be paid. uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee); // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei // during any 1 day period in the last 5 years, so should be fine. uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei); // Give the user a refund based on the amount of gas they used to do all of the work up to // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts // effectively like a dynamic stipend (with a minimum value). uint256 usedGas = _initialGas - gasleft(); if (gasCost > usedGas) { Burn.gas(gasCost - usedGas); } } /** * @notice Virtual function that returns the resource config. Contracts that inherit this * contract must implement this function. * * @return ResourceConfig */ function _resourceConfig() internal virtual returns (ResourceConfig memory); /** * @notice Sets initial resource parameter values. This function must either be called by the * initializer function of an upgradeable child contract. */ // solhint-disable-next-line func-name-mixedcase function __ResourceMetering_init() internal onlyInitializing { params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) }); } } /** * @title Constants * @notice Constants is a library for storing constants. Simple! Don't put everything in here, just * the stuff used in multiple contracts. Constants that only apply to a single contract * should be defined in that contract instead. */ library Constants { /** * @notice Special address to be used as the tx origin for gas estimation calls in the * MorphPortal and CrossDomainMessenger calls. You only need to use this address if * the minimum gas limit specified by the user is not actually enough to execute the * given message and you're attempting to estimate the actual necessary gas limit. We * use address(1) because it's the ecrecover precompile and therefore guaranteed to * never have any code on any EVM chain. */ address internal constant ESTIMATION_ADDRESS = address(1); /** * @notice Value used for the L2 sender storage slot in both the MorphPortal and the * CrossDomainMessenger contracts before an actual sender is set. This value is * non-zero to reduce the gas cost of message passing transactions. */ address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD; /** * @notice Returns the default values for the ResourceConfig. These are the recommended values * for a production network. */ function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) { ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ maxResourceLimit: 20_000_000, elasticityMultiplier: 10, baseFeeMaxChangeDenominator: 8, minimumBaseFee: 1 gwei, systemTxMaxGas: 1_000_000, maximumBaseFee: type(uint128).max }); return config; } } /** * @custom:legacy * @title CrossDomainMessengerLegacySpacer0 * @notice Contract only exists to add a spacer to the CrossDomainMessenger where the * libAddressManager variable used to exist. Must be the first contract in the inheritance * tree of the CrossDomainMessenger. */ contract CrossDomainMessengerLegacySpacer0 { /** * @custom:legacy * @custom:spacer libAddressManager * @notice Spacer for backwards compatibility. */ address private spacer_0_0_20; } /** * @custom:legacy * @title CrossDomainMessengerLegacySpacer1 * @notice Contract only exists to add a spacer to the CrossDomainMessenger where the * PausableUpgradable and OwnableUpgradeable variables used to exist. Must be * the third contract in the inheritance tree of the CrossDomainMessenger. */ contract CrossDomainMessengerLegacySpacer1 { /** * @custom:legacy * @custom:spacer ContextUpgradable's __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * ContextUpgradable. * */ uint256[50] private spacer_1_0_1600; /** * @custom:legacy * @custom:spacer OwnableUpgradeable's _owner * @notice Spacer for backwards compatibility. * Come from OpenZeppelin OwnableUpgradeable. */ address private spacer_51_0_20; /** * @custom:legacy * @custom:spacer OwnableUpgradeable's __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * OwnableUpgradeable. */ uint256[49] private spacer_52_0_1568; /** * @custom:legacy * @custom:spacer PausableUpgradable's _paused * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * PausableUpgradable. */ bool private spacer_101_0_1; /** * @custom:legacy * @custom:spacer PausableUpgradable's __gap * @notice Spacer for backwards compatibility. Comes from OpenZeppelin * PausableUpgradable. */ uint256[49] private spacer_102_0_1568; /** * @custom:legacy * @custom:spacer ReentrancyGuardUpgradeable's `_status` field. * @notice Spacer for backwards compatibility. */ uint256 private spacer_151_0_32; /** * @custom:legacy * @custom:spacer ReentrancyGuardUpgradeable's __gap * @notice Spacer for backwards compatibility. */ uint256[49] private spacer_152_0_1568; /** * @custom:legacy * @custom:spacer blockedMessages * @notice Spacer for backwards compatibility. */ mapping(bytes32 => bool) private spacer_201_0_32; /** * @custom:legacy * @custom:spacer relayedMessages * @notice Spacer for backwards compatibility. */ mapping(bytes32 => bool) private spacer_202_0_32; } /** * @custom:upgradeable * @title CrossDomainMessenger * @notice CrossDomainMessenger is a base contract that provides the core logic for the L1 and L2 * cross-chain messenger contracts. It's designed to be a universal interface that only * needs to be extended slightly to provide low-level message passing functionality on each * chain it's deployed on. Currently only designed for message passing between two paired * chains and does not support one-to-many interactions. * * Any changes to this contract MUST result in a semver bump for contracts that inherit it. */ abstract contract CrossDomainMessenger is CrossDomainMessengerLegacySpacer0, Initializable, CrossDomainMessengerLegacySpacer1 { /** * @notice Current message version identifier. */ uint16 public constant MESSAGE_VERSION = 1; /** * @notice Constant overhead added to the base gas for a message. */ uint64 public constant RELAY_CONSTANT_OVERHEAD = 200_000; /** * @notice Numerator for dynamic overhead added to the base gas for a message. */ uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR = 64; /** * @notice Denominator for dynamic overhead added to the base gas for a message. */ uint64 public constant MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR = 63; /** * @notice Extra gas added to base gas for each byte of calldata in a message. */ uint64 public constant MIN_GAS_CALLDATA_OVERHEAD = 16; /** * @notice Gas reserved for performing the external call in `relayMessage`. */ uint64 public constant RELAY_CALL_OVERHEAD = 40_000; /** * @notice Gas reserved for finalizing the execution of `relayMessage` after the safe call. */ uint64 public constant RELAY_RESERVED_GAS = 40_000; /** * @notice Gas reserved for the execution between the `hasMinGas` check and the external * call in `relayMessage`. */ uint64 public constant RELAY_GAS_CHECK_BUFFER = 5_000; /** * @notice Address of the paired CrossDomainMessenger contract on the other chain. */ address public immutable OTHER_MESSENGER; /** * @notice Mapping of message hashes to boolean receipt values. Note that a message will only * be present in this mapping if it has successfully been relayed on this chain, and * can therefore not be relayed again. */ mapping(bytes32 => bool) public successfulMessages; uint256 public receiveNonce; /** * @notice Address of the sender of the currently executing message on the other chain. If the * value of this variable is the default value (0x00000000...dead) then no message is * currently being executed. Use the xDomainMessageSender getter which will throw an * error if this is the case. */ address internal xDomainMsgSender; /** * @notice Nonce for the next message to be sent, without the message version applied. Use the * messageNonce getter which will insert the message version into the nonce to give you * the actual nonce to be used for the message. */ uint240 internal msgNonce; /** * @notice Mapping of message hashes to a boolean if and only if the message has failed to be * executed at least once. A message will not be present in this mapping if it * successfully executed on the first attempt. */ mapping(bytes32 => bool) public failedMessages; /** * @notice Reserve extra slots in the storage layout for future upgrades. * A gap size of 41 was chosen here, so that the first slot used in a child contract * would be a multiple of 50. */ uint256[42] private __gap; /** * @notice Emitted whenever a message is sent to the other chain. * * @param target Address of the recipient of the message. * @param sender Address of the sender of the message. * @param message Message to trigger the recipient address with. * @param messageNonce Unique nonce attached to the message. * @param gasLimit Minimum gas limit that the message can be executed with. */ event SentMessage( address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit ); /** * @notice Additional event data to emit, required as of Bedrock. Cannot be merged with the * SentMessage event without breaking the ABI of this contract, this is good enough. * * @param sender Address of the sender of the message. * @param value ETH value sent along with the message to the recipient. */ event SentMessageExtension1(address indexed sender, uint256 value); /** * @notice Emitted whenever a message is successfully relayed on this chain. * * @param msgHash Hash of the message that was relayed. */ event RelayedMessage(bytes32 indexed msgHash); /** * @notice Emitted whenever a message fails to be relayed on this chain. * * @param msgHash Hash of the message that failed to be relayed. */ event FailedRelayedMessage(bytes32 indexed msgHash); /** * @notice Emitted a event associated with message relationship. * * @param messagerNonce Address of the withdrawer. * @param crossNonce Address of the recipient on L1. */ event MessageAssociation(uint256 messagerNonce, uint256 crossNonce); /** * @param _otherMessenger Address of the messenger on the paired chain. */ constructor(address _otherMessenger) { OTHER_MESSENGER = _otherMessenger; } /** * @notice Sends a message to some target address on the other chain. Note that if the call * always reverts, then the message will be unrelayable, and any ETH sent will be * permanently locked. The same will occur if the target on the other chain is * considered unsafe (see the _isUnsafeTarget() function). * * @param _target Target contract or wallet address. * @param _message Message to trigger the target address with. * @param _minGasLimit Minimum gas limit that the message can be executed with. */ function sendMessage( address _target, bytes calldata _message, uint32 _minGasLimit ) external payable { // Triggers a message to the other messenger. Note that the amount of gas provided to the // message is the amount of gas requested by the user PLUS the base gas value. We want to // guarantee the property that the call to the target contract will always have at least // the minimum gas limit specified by the user. _sendMessage( OTHER_MESSENGER, baseGas(_message, _minGasLimit), msg.value, abi.encodeWithSelector( this.relayMessage.selector, messageNonce(), msg.sender, _target, msg.value, _minGasLimit, _message ) ); emit SentMessage(_target, msg.sender, _message, messageNonce(), _minGasLimit); emit SentMessageExtension1(msg.sender, msg.value); unchecked { ++msgNonce; } } /** * @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only * be executed via cross-chain call from the other messenger OR if the message was * already received once and is currently being replayed. * * @param _nonce Nonce of the message being relayed. * @param _sender Address of the user who sent the message. * @param _target Address that the message is targeted at. * @param _value ETH value to send with the message. * @param _minGasLimit Minimum amount of gas that the message can be executed with. * @param _message Message to send to the target. */ function relayMessage( uint256 _nonce, address _sender, address _target, uint256 _value, uint256 _minGasLimit, bytes calldata _message ) external payable { (, uint16 version) = Encoding.decodeVersionedNonce(_nonce); require( version < 2, "CrossDomainMessenger: only version 0 or 1 messages are supported at this time" ); // If the message is version 0, then it's a migrated legacy withdrawal. We therefore need // to check that the legacy version of the message has not already been relayed. if (version == 0) { bytes32 oldHash = Hashing.hashCrossDomainMessageV0(_target, _sender, _message, _nonce); require( successfulMessages[oldHash] == false, "CrossDomainMessenger: legacy withdrawal already relayed" ); } // We use the v1 message hash as the unique identifier for the message because it commits // to the value and minimum gas limit of the message. bytes32 versionedHash = Hashing.hashCrossDomainMessageV1( _nonce, _sender, _target, _value, _minGasLimit, _message ); if (_isOtherMessenger()) { // These properties should always hold when the message is first submitted (as // opposed to being replayed). assert(msg.value == _value); assert(!failedMessages[versionedHash]); receiveNonce = _nonce; } else { require( msg.value == 0, "CrossDomainMessenger: value must be zero unless message is from a system address" ); require( failedMessages[versionedHash], "CrossDomainMessenger: message cannot be replayed" ); } require( _isUnsafeTarget(_target) == false, "CrossDomainMessenger: cannot send message to blocked system address" ); require( successfulMessages[versionedHash] == false, "CrossDomainMessenger: message has already been relayed" ); // If there is not enough gas left to perform the external call and finish the execution, // return early and assign the message to the failedMessages mapping. // We are asserting that we have enough gas to: // 1. Call the target contract (_minGasLimit + RELAY_CALL_OVERHEAD + RELAY_GAS_CHECK_BUFFER) // 1.a. The RELAY_CALL_OVERHEAD is included in `hasMinGas`. // 2. Finish the execution after the external call (RELAY_RESERVED_GAS). // // If `xDomainMsgSender` is not the default L2 sender, this function // is being re-entered. This marks the message as failed to allow it to be replayed. if ( !SafeCall.hasMinGas(_minGasLimit, RELAY_RESERVED_GAS + RELAY_GAS_CHECK_BUFFER) || xDomainMsgSender != Constants.DEFAULT_L2_SENDER ) { failedMessages[versionedHash] = true; emit FailedRelayedMessage(versionedHash); // Revert in this case if the transaction was triggered by the estimation address. This // should only be possible during gas estimation or we have bigger problems. Reverting // here will make the behavior of gas estimation change such that the gas limit // computed will be the amount required to relay the message, even if that amount is // greater than the minimum gas limit specified by the user. if (tx.origin == Constants.ESTIMATION_ADDRESS) { revert("CrossDomainMessenger: failed to relay message"); } return; } xDomainMsgSender = _sender; bool success = SafeCall.call(_target, gasleft() - RELAY_RESERVED_GAS, _value, _message); xDomainMsgSender = Constants.DEFAULT_L2_SENDER; if (success) { successfulMessages[versionedHash] = true; emit RelayedMessage(versionedHash); } else { failedMessages[versionedHash] = true; emit FailedRelayedMessage(versionedHash); // Revert in this case if the transaction was triggered by the estimation address. This // should only be possible during gas estimation or we have bigger problems. Reverting // here will make the behavior of gas estimation change such that the gas limit // computed will be the amount required to relay the message, even if that amount is // greater than the minimum gas limit specified by the user. if (tx.origin == Constants.ESTIMATION_ADDRESS) { revert("CrossDomainMessenger: failed to relay message"); } } } /** * @notice Retrieves the address of the contract or wallet that initiated the currently * executing message on the other chain. Will throw an error if there is no message * currently being executed. Allows the recipient of a call to see who triggered it. * * @return Address of the sender of the currently executing message on the other chain. */ function xDomainMessageSender() external view returns (address) { require( xDomainMsgSender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set" ); return xDomainMsgSender; } /** * @notice Retrieves the next message nonce. Message version will be added to the upper two * bytes of the message nonce. Message version allows us to treat messages as having * different structures. * * @return Nonce of the next message to be sent, with added message version. */ function messageNonce() public view returns (uint256) { return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION); } /** * @notice Computes the amount of gas required to guarantee that a given message will be * received on the other chain without running out of gas. Guaranteeing that a message * will not run out of gas is important because this ensures that a message can always * be replayed on the other chain if it fails to execute completely. * * @param _message Message to compute the amount of required gas for. * @param _minGasLimit Minimum desired gas limit when message goes to target. * * @return Amount of gas required to guarantee message receipt. */ function baseGas(bytes calldata _message, uint32 _minGasLimit) public pure returns (uint64) { return // Constant overhead RELAY_CONSTANT_OVERHEAD + // Calldata overhead (uint64(_message.length) * MIN_GAS_CALLDATA_OVERHEAD) + // Dynamic overhead (EIP-150) ((_minGasLimit * MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR) / MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR) + // Gas reserved for the worst-case cost of 3/5 of the `CALL` opcode's dynamic gas // factors. (Conservative) RELAY_CALL_OVERHEAD + // Relay reserved gas (to ensure execution of `relayMessage` completes after the // subcontext finishes executing) (Conservative) RELAY_RESERVED_GAS + // Gas reserved for the execution between the `hasMinGas` check and the `CALL` // opcode. (Conservative) RELAY_GAS_CHECK_BUFFER; } /** * @notice Intializer. */ // solhint-disable-next-line func-name-mixedcase function __CrossDomainMessenger_init() internal onlyInitializing { xDomainMsgSender = Constants.DEFAULT_L2_SENDER; } /** * @notice Sends a low-level message to the other messenger. Needs to be implemented by child * contracts because the logic for this depends on the network where the messenger is * being deployed. * * @param _to Recipient of the message on the other chain. * @param _gasLimit Minimum gas limit the message can be executed with. * @param _value Amount of ETH to send with the message. * @param _data Message data. */ function _sendMessage( address _to, uint64 _gasLimit, uint256 _value, bytes memory _data ) internal virtual; /** * @notice Checks whether the message is coming from the other messenger. Implemented by child * contracts because the logic for this depends on the network where the messenger is * being deployed. * * @return Whether the message is coming from the other messenger. */ function _isOtherMessenger() internal view virtual returns (bool); /** * @notice Checks whether a given call target is a system address that could cause the * messenger to peform an unsafe action. This is NOT a mechanism for blocking user * addresses. This is ONLY used to prevent the execution of messages to specific * system addresses that could cause security issues, e.g., having the * CrossDomainMessenger send messages to itself. * * @param _target Address of the contract to check. * * @return Whether or not the address is an unsafe system address. */ function _isUnsafeTarget(address _target) internal view virtual returns (bool); } abstract contract RollupMessage { /** * @notice Messenger contract on this domain. */ CrossDomainMessenger public immutable MESSENGER; /** * @notice Corresponding counterpart on the other domain. */ address public immutable COUNTERPART; /** * @notice Ensures that the caller is a cross-chain message from the L1 rollup. */ modifier onlyCounterpart() { require( msg.sender == address(MESSENGER) && MESSENGER.xDomainMessageSender() == COUNTERPART, "Rollup: function can only be called from the L1 rollup" ); _; } /** * @param _messenger Address of CrossDomainMessenger on this network. * @param _counterpart Address of the counterpart contract. */ constructor(address payable _messenger, address payable _counterpart) { MESSENGER = CrossDomainMessenger(_messenger); COUNTERPART = _counterpart; } /** * @notice Getter for messenger contract. * * @return Messenger contract on this domain. */ function messenger() external view returns (CrossDomainMessenger) { return MESSENGER; } } /** * @title Predeploys * @notice Contains constant addresses for contracts that are pre-deployed to the L2 system. */ library Predeploys { /** * @notice Address of the L2ToL1MessagePasser predeploy. */ address internal constant L2_TO_L1_MESSAGE_PASSER = 0x5300000000000000000000000000000000000001; /** * @notice Address of the GasPriceOracle predeploy. Includes fee information * and helpers for computing the L1 portion of the transaction fee. */ address internal constant GAS_PRICE_ORACLE = 0x530000000000000000000000000000000000000f; /** * @notice Address of the L2Sequencer predeploy. */ address internal constant L2_SEQUENCER = 0x5300000000000000000000000000000000000003; /** * @notice Address of the Gov predeploy. */ address internal constant L2_GOV = 0x5300000000000000000000000000000000000004; /** * @notice Address of the L2SUBMITTER predeploy. */ address internal constant L2_SUBMITTER = 0x5300000000000000000000000000000000000005; /** * @notice Address of the L2CrossDomainMessenger predeploy. */ address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; /** * @notice Address of the L2StandardBridge predeploy. */ address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; /** * @notice Address of the L2ERC721Bridge predeploy. */ address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014; /** * @notice Address of the SequencerFeeWallet predeploy. */ address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; /** * @notice Address of the MorphMintableERC20Factory predeploy. */ address internal constant Morph_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012; /** * @notice Address of the MorphMintableERC721Factory predeploy. */ address internal constant Morph_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017; /** * @notice Address of the L1Block predeploy. */ address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015; /** * @custom:legacy * @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger * or access tx.origin (or msg.sender) in a L1 to L2 transaction instead. */ address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; /** * @custom:legacy * @notice Address of the DeployerWhitelist predeploy. No longer active. */ address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; /** * @custom:legacy * @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the * state trie as of the Bedrock upgrade. Contract has been locked and write functions * can no longer be accessed. */ address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; /** * @custom:legacy * @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy * instead, which exposes more information about the L1 state. */ address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; /** * @custom:legacy * @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated * L2ToL1MessagePasser contract instead. */ address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; /** * @notice Address of the ProxyAdmin predeploy. */ address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018; /** * @notice Address of the BaseFeeVault predeploy. */ address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019; /** * @notice Address of the L1FeeVault predeploy. */ address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; /** * @notice Address of the GovernanceToken predeploy. */ address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042; } // solhint-disable no-inline-assembly /// @dev Below is the encoding for `BatchHeader` V0, total 89 + ceil(l1MessagePopped / 256) * 32 bytes. /// ```text /// * Field Bytes Type Index Comments /// * version 1 uint8 0 The batch version /// * batchIndex 8 uint64 1 The index of the batch /// * l1MessagePopped 8 uint64 9 Number of L1 messages popped in the batch /// * totalL1MessagePopped 8 uint64 17 Number of total L1 message popped after the batch /// * dataHash 32 bytes32 25 The data hash of the batch /// * parentBatchHash 32 bytes32 57 The parent batch hash /// * skippedL1MessageBitmap dynamic uint256[] 89 A bitmap to indicate which L1 messages are skipped in the batch /// ``` library BatchHeaderV0Codec { /// @notice Load batch header in calldata to memory. /// @param _batchHeader The encoded batch header bytes in calldata. /// @return batchPtr The start memory offset of the batch header in memory. /// @return length The length in bytes of the batch header. function loadAndValidate(bytes calldata _batchHeader) internal pure returns (uint256 batchPtr, uint256 length) { length = _batchHeader.length; require(length >= 89, "batch header length too small"); // copy batch header to memory. assembly { batchPtr := mload(0x40) calldatacopy(batchPtr, _batchHeader.offset, length) mstore(0x40, add(batchPtr, length)) } // check batch header length uint256 _l1MessagePopped = BatchHeaderV0Codec.l1MessagePopped(batchPtr); unchecked { require(length == 89 + ((_l1MessagePopped + 255) / 256) * 32, "wrong bitmap length"); } } /// @notice Get the version of the batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _version The version of the batch header. function version(uint256 batchPtr) internal pure returns (uint256 _version) { assembly { _version := shr(248, mload(batchPtr)) } } /// @notice Get the batch index of the batch. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _batchIndex The batch index of the batch. function batchIndex(uint256 batchPtr) internal pure returns (uint256 _batchIndex) { assembly { _batchIndex := shr(192, mload(add(batchPtr, 1))) } } /// @notice Get the number of L1 messages of the batch. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _l1MessagePopped The number of L1 messages of the batch. function l1MessagePopped(uint256 batchPtr) internal pure returns (uint256 _l1MessagePopped) { assembly { _l1MessagePopped := shr(192, mload(add(batchPtr, 9))) } } /// @notice Get the number of L1 messages popped before this batch. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _totalL1MessagePopped The the number of L1 messages popped before this batch. function totalL1MessagePopped(uint256 batchPtr) internal pure returns (uint256 _totalL1MessagePopped) { assembly { _totalL1MessagePopped := shr(192, mload(add(batchPtr, 17))) } } /// @notice Get the data hash of the batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _dataHash The data hash of the batch header. function dataHash(uint256 batchPtr) internal pure returns (bytes32 _dataHash) { assembly { _dataHash := mload(add(batchPtr, 25)) } } /// @notice Get the parent batch hash of the batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @return _parentBatchHash The parent batch hash of the batch header. function parentBatchHash(uint256 batchPtr) internal pure returns (bytes32 _parentBatchHash) { assembly { _parentBatchHash := mload(add(batchPtr, 57)) } } /// @notice Get the skipped L1 messages bitmap. /// @param batchPtr The start memory offset of the batch header in memory. /// @param index The index of bitmap to load. /// @return _bitmap The bitmap from bits `index * 256` to `index * 256 + 255`. function skippedBitmap(uint256 batchPtr, uint256 index) internal pure returns (uint256 _bitmap) { assembly { batchPtr := add(batchPtr, 89) _bitmap := mload(add(batchPtr, mul(index, 32))) } } /// @notice Store the version of batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _version The version of batch header. function storeVersion(uint256 batchPtr, uint256 _version) internal pure { assembly { mstore8(batchPtr, _version) } } /// @notice Store the batch index of batch header. /// @dev Because this function can overwrite the subsequent fields, it must be called before /// `storeL1MessagePopped`, `storeTotalL1MessagePopped`, and `storeDataHash`. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _batchIndex The batch index. function storeBatchIndex(uint256 batchPtr, uint256 _batchIndex) internal pure { assembly { mstore(add(batchPtr, 1), shl(192, _batchIndex)) } } /// @notice Store the number of L1 messages popped in current batch to batch header. /// @dev Because this function can overwrite the subsequent fields, it must be called before /// `storeTotalL1MessagePopped` and `storeDataHash`. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _l1MessagePopped The number of L1 messages popped in current batch. function storeL1MessagePopped(uint256 batchPtr, uint256 _l1MessagePopped) internal pure { assembly { mstore(add(batchPtr, 9), shl(192, _l1MessagePopped)) } } /// @notice Store the total number of L1 messages popped after current batch to batch header. /// @dev Because this function can overwrite the subsequent fields, it must be called before /// `storeDataHash`. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _totalL1MessagePopped The total number of L1 messages popped after current batch. function storeTotalL1MessagePopped(uint256 batchPtr, uint256 _totalL1MessagePopped) internal pure { assembly { mstore(add(batchPtr, 17), shl(192, _totalL1MessagePopped)) } } /// @notice Store the data hash of batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _dataHash The data hash. function storeDataHash(uint256 batchPtr, bytes32 _dataHash) internal pure { assembly { mstore(add(batchPtr, 25), _dataHash) } } /// @notice Store the parent batch hash of batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _parentBatchHash The parent batch hash. function storeParentBatchHash(uint256 batchPtr, bytes32 _parentBatchHash) internal pure { assembly { mstore(add(batchPtr, 57), _parentBatchHash) } } /// @notice Store the skipped L1 message bitmap of batch header. /// @param batchPtr The start memory offset of the batch header in memory. /// @param _skippedL1MessageBitmap The skipped L1 message bitmap. function storeSkippedBitmap(uint256 batchPtr, bytes calldata _skippedL1MessageBitmap) internal pure { assembly { calldatacopy(add(batchPtr, 89), _skippedL1MessageBitmap.offset, _skippedL1MessageBitmap.length) } } /// @notice Compute the batch hash. /// @dev Caller should make sure that the encoded batch header is correct. /// /// @param batchPtr The memory offset of the encoded batch header. /// @param length The length of the batch. /// @return _batchHash The hash of the corresponding batch. function computeBatchHash(uint256 batchPtr, uint256 length) internal pure returns (bytes32 _batchHash) { // in the current version, the hash is: keccak(BatchHeader without timestamp) assembly { _batchHash := keccak256(batchPtr, length) } } } /// @dev Below is the encoding for `Chunk`, total 60*n+1+m bytes. /// ```text /// * Field Bytes Type Index Comments /// * numBlocks 1 uint8 0 The number of blocks in this chunk /// * block[0] 60 BlockContext 1 The first block in this chunk /// * ...... /// * block[i] 60 BlockContext 60*i+1 The (i+1)'th block in this chunk /// * ...... /// * block[n-1] 60 BlockContext 60*n-59 The last block in this chunk /// * l2Transactions dynamic bytes 60*n+1 /// ``` /// /// @dev Below is the encoding for `BlockContext`, total 60 bytes. /// ```text /// * Field Bytes Type Index Comments /// * blockNumber 8 uint64 0 The height of this block. /// * timestamp 8 uint64 8 The timestamp of this block. /// * baseFee 32 uint256 16 The base fee of this block. Currently, it is always 0, because we disable EIP-1559. /// * gasLimit 8 uint64 48 The gas limit of this block. /// * numTransactions 2 uint16 56 The number of transactions in this block, both L1 & L2 txs. /// * numL1Messages 2 uint16 58 The number of l1 messages in this block. /// ``` library ChunkCodec { uint256 internal constant BLOCK_CONTEXT_LENGTH = 60; /// @notice Validate the length of chunk. /// @param chunkPtr The start memory offset of the chunk in memory. /// @param _length The length of the chunk. /// @return _numBlocks The number of blocks in current chunk. function validateChunkLength( uint256 chunkPtr, uint256 _length ) internal pure returns (uint256 _numBlocks) { _numBlocks = numBlocks(chunkPtr); // should contain at least one block require(_numBlocks > 0, "no block in chunk"); // should contain at least the number of the blocks and block contexts require( _length >= 1 + _numBlocks * BLOCK_CONTEXT_LENGTH, "invalid chunk length" ); } /// @notice Return the start memory offset of `l2Transactions`. /// @dev The caller should make sure `_numBlocks` is correct. /// @param chunkPtr The start memory offset of the chunk in memory. /// @param _numBlocks The number of blocks in current chunk. /// @return _l2TxPtr the start memory offset of `l2Transactions`. function l2TxPtr( uint256 chunkPtr, uint256 _numBlocks ) internal pure returns (uint256 _l2TxPtr) { unchecked { _l2TxPtr = chunkPtr + 1 + _numBlocks * BLOCK_CONTEXT_LENGTH; } } /// @notice Return the number of blocks in current chunk. /// @param chunkPtr The start memory offset of the chunk in memory. /// @return _numBlocks The number of blocks in current chunk. function numBlocks( uint256 chunkPtr ) internal pure returns (uint256 _numBlocks) { assembly { _numBlocks := shr(248, mload(chunkPtr)) } } /// @notice Copy the block context to another memory. /// @param chunkPtr The start memory offset of the chunk in memory. /// @param dstPtr The destination memory offset to store the block context. /// @param index The index of block context to copy. /// @return uint256 The new destination memory offset after copy. function copyBlockContext( uint256 chunkPtr, uint256 dstPtr, uint256 index ) internal pure returns (uint256) { // only first 58 bytes is needed. assembly { chunkPtr := add(chunkPtr, add(1, mul(BLOCK_CONTEXT_LENGTH, index))) mstore(dstPtr, mload(chunkPtr)) // first 32 bytes mstore( add(dstPtr, 0x20), and( mload(add(chunkPtr, 0x20)), 0xffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000 ) ) // next 26 bytes dstPtr := add(dstPtr, 58) } return dstPtr; } /// @notice Return the number of transactions in current block. /// @param blockPtr The start memory offset of the block context in memory. /// @return _numTransactions The number of transactions in current block. function numTransactions( uint256 blockPtr ) internal pure returns (uint256 _numTransactions) { assembly { _numTransactions := shr(240, mload(add(blockPtr, 56))) } } /// @notice Return the number of L1 messages in current block. /// @param blockPtr The start memory offset of the block context in memory. /// @return _numL1Messages The number of L1 messages in current block. function numL1Messages( uint256 blockPtr ) internal pure returns (uint256 _numL1Messages) { assembly { _numL1Messages := shr(240, mload(add(blockPtr, 58))) } } /// @notice Return the number of the block. /// @param blockPtr The start memory offset of the block context in memory. /// @return _blockNumber The block number of blockPtr in current block. function blockNumber( uint256 blockPtr ) internal pure returns (uint256 _blockNumber) { assembly { _blockNumber := shr(192, mload(blockPtr)) } } /// @notice Compute and load the transaction hash. /// @param _l2TxPtr The start memory offset of the transaction in memory. /// @return bytes32 The transaction hash of the transaction. /// @return uint256 The start memory offset of the next transaction in memory. function loadL2TxHash( uint256 _l2TxPtr ) internal pure returns (bytes32, uint256) { bytes32 txHash; assembly { // first 4 bytes indicate the length let txPayloadLength := shr(224, mload(_l2TxPtr)) _l2TxPtr := add(_l2TxPtr, 4) txHash := keccak256(_l2TxPtr, txPayloadLength) _l2TxPtr := add(_l2TxPtr, txPayloadLength) } return (txHash, _l2TxPtr); } } interface IRollupVerifier { /// @notice Verify aggregate zk proof. /// @param batchIndex The batch index to verify. /// @param aggrProof The aggregated proof. /// @param publicInputHash The public input hash. function verifyAggregateProof( uint256 batchIndex, bytes calldata aggrProof, bytes32 publicInputHash ) external view; } // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } } /** * @title Semver * @notice Semver is a simple contract for managing contract versions. */ contract Semver { /** * @notice Contract version number (major). */ uint256 private immutable MAJOR_VERSION; /** * @notice Contract version number (minor). */ uint256 private immutable MINOR_VERSION; /** * @notice Contract version number (patch). */ uint256 private immutable PATCH_VERSION; /** * @param _major Version number (major). * @param _minor Version number (minor). * @param _patch Version number (patch). */ constructor( uint256 _major, uint256 _minor, uint256 _patch ) { MAJOR_VERSION = _major; MINOR_VERSION = _minor; PATCH_VERSION = _patch; } /** * @notice Returns the full semver contract version. * * @return Semver contract version as a string. */ function version() public view returns (string memory) { return string( abi.encodePacked( Strings.toString(MAJOR_VERSION), ".", Strings.toString(MINOR_VERSION), ".", Strings.toString(PATCH_VERSION) ) ); } } abstract contract Sequencer { /** * @notice Messenger contract on this domain. */ CrossDomainMessenger public immutable MESSENGER; /** * @notice Corresponding sequencer on the other domain. */ Sequencer public immutable OTHER_SEQUENCER; /** * @notice Ensures that the caller is a cross-chain message from the other sequencer. */ modifier onlyOtherSequencer() { require( msg.sender == address(MESSENGER) && MESSENGER.xDomainMessageSender() == address(OTHER_SEQUENCER), "Sequencer: function can only be called from the other sequencer" ); _; } /** * @param _messenger Address of CrossDomainMessenger on this network. * @param _otherSequencer Address of the other Sequencer contract. */ constructor(address payable _messenger, address payable _otherSequencer) { MESSENGER = CrossDomainMessenger(_messenger); OTHER_SEQUENCER = Sequencer(_otherSequencer); } /** * @notice Getter for messenger contract. * * @return Messenger contract on this domain. */ function messenger() external view returns (CrossDomainMessenger) { return MESSENGER; } } interface ISubmitter { /** * @notice next batch index */ function nextBatchIndex() external view returns (uint256); /** * @notice next batch start block */ function nextBatchStartBlock() external view returns (uint256); /** * @notice get confirmed batch info */ function getConfirmedBatch( uint256 batchIndex ) external view returns (Types.BatchInfo memory batchInfo); /** * @notice get epoch info */ function getEpoch( uint256 epochIndex ) external view returns (Types.EpochInfo memory epochInfo); /** * @notice get the current sequencer's turn */ function getTurn( address submitter ) external view returns (uint256 startTime, uint256 endTime); /** * @notice get next submitter */ function getNextSubmitter() external view returns (address nextSubmitter, uint256 startTime, uint256 endTime); // ============================================================================ /** * @notice set rollup acknowledge, only call by bridge */ function ackRollup( uint256 batchIndex, address submitter, uint256 batchStartBlock, uint256 batchEndBlock, uint256 rollupTime ) external; /** * @notice notify epoch updated */ function epochUpdated(uint256 epoch) external; /** * @notice notify sequencers updated */ function sequencersUpdated(address[] memory sequencers) external; } interface IL2Sequencer { /** * @notice current sequencers version */ function currentVersion() external view returns (uint256); /** * @notice current sequencers version height */ function currentVersionHeight() external view returns (uint256); /** * @notice pre sequencers version */ function preVersion() external view returns (uint256); /** * @notice pre sequencers version height */ function preVersionHeight() external view returns (uint256); /** * @notice get sequencers addresses */ function sequencerAddresses(uint256 index) external view returns (address); /** * @notice get pre sequencers addresses */ function preSequencerAddresses( uint256 index ) external view returns (address); /** * @notice get sequencers addresses */ function getSequencerAddresses( bool previous ) external view returns (address[] memory); /** * @notice get sequencers addresses */ function getSequencerInfos( bool previous ) external view returns (Types.SequencerInfo[] memory); /** * @notice get address is in sequencers set */ function inSequencersSet( bool previous, address addr ) external view returns (bool, uint256); /** * @notice get the index of address in sequencers set */ function sequencerIndex( bool previous, address addr ) external view returns (uint256, uint256); /** * @notice get the length of sequencerAddresses */ function sequencersLen( bool previous ) external view returns (uint256, uint256); } interface IGov { /** * @notice batch block interval */ function batchBlockInterval() external view returns (uint256); /** * @notice batch max bytes */ function batchMaxBytes() external view returns (uint256); /** * @notice next batch index */ function batchTimeout() external view returns (uint256); /** * @notice next batch index */ function rollupEpoch() external view returns (uint256); /** * @notice max chunks */ function maxChunks() external view returns (uint256); } contract Submitter is Initializable, Semver, ISubmitter, RollupMessage { // l2SequencerContract address address public immutable L2_SEQUENCER_CONTRACT; // GovContract address address public immutable L2_GOV_CONTRACT; // uint256 public override nextSubmitterIndex; uint256 public override nextBatchIndex; // next batch start block uint256 public override nextBatchStartBlock; // bathcIndex => batchInfo mapping(uint256 => Types.BatchInfo) public confirmedBatchs; // next epoch start time uint256 public nextEpochStart; // next submitter index uint256 public nextSubmitterIndex; // calculated epoch index uint256 public calculatedEpochIndex; // epoch info mapping(uint256 => Types.EpochInfo) public epochs; /** * @notice ack rollup */ event ACKRollup( uint256 batchIndex, address submitter, uint256 batchStartBlock, uint256 batchEndBlock, uint256 rollupTime ); /** * @notice epoch updated */ event EpochUpdated(uint256 interval, uint256 sequencersLen); /** * @notice constructor */ constructor( address payable _rollup ) Semver(1, 1, 0) RollupMessage(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _rollup) { L2_SEQUENCER_CONTRACT = Predeploys.L2_SEQUENCER; L2_GOV_CONTRACT = Predeploys.L2_GOV; } /** * @notice Initializer. * @param _nextEpochStart next epoch start time */ function initialize(uint256 _nextEpochStart) public initializer { require(_nextEpochStart > 0, "invalid firstEpochStart"); nextEpochStart = _nextEpochStart; } /** * @notice set rollup acknowledge, only call by bridge */ function ackRollup( uint256 batchIndex, address submitter, uint256 batchStartBlock, uint256 batchEndBlock, uint256 rollupTime ) public onlyCounterpart { require(batchIndex == nextBatchIndex, "invalid batchIndex"); require( batchStartBlock == nextBatchStartBlock, "invalid batchStartBlock" ); require(true); confirmedBatchs[batchIndex] = Types.BatchInfo( submitter, batchStartBlock, batchEndBlock, rollupTime ); emit ACKRollup( batchIndex, submitter, batchStartBlock, batchEndBlock, rollupTime ); nextBatchIndex++; nextBatchStartBlock = batchEndBlock + 1; } /** * @notice epoch updated */ function epochUpdated(uint256 epoch) public { require(msg.sender == L2_GOV_CONTRACT, "only gov contract"); address[] memory sequencers = IL2Sequencer(L2_SEQUENCER_CONTRACT) .getSequencerAddresses(false); updateEpoch(epoch, sequencers); } /** * @notice sequencers updated */ function sequencersUpdated(address[] memory sequencers) public { require( msg.sender == L2_SEQUENCER_CONTRACT, "only l2 sequencer contract" ); uint256 epoch = IGov(L2_GOV_CONTRACT).rollupEpoch(); nextSubmitterIndex = 0; updateEpoch(epoch, sequencers); } /** * @notice statistics timeout behavior */ function updateEpoch(uint256 epoch, address[] memory sequencers) internal { uint256 sequencersLen = sequencers.length; while (nextEpochStart + epoch <= block.timestamp) { calculatedEpochIndex++; epochs[calculatedEpochIndex] = Types.EpochInfo( sequencers[nextSubmitterIndex], nextEpochStart, nextEpochStart + epoch ); nextSubmitterIndex++; if (nextSubmitterIndex == sequencersLen) { nextSubmitterIndex = 0; } nextEpochStart += epoch; } emit EpochUpdated(epoch, sequencersLen); } /** * @notice update epoch external */ function updateEpochExternal() public { // update epoch address[] memory sequencers = IL2Sequencer(L2_SEQUENCER_CONTRACT) .getSequencerAddresses(false); uint256 epoch = IGov(L2_GOV_CONTRACT).rollupEpoch(); updateEpoch(epoch, sequencers); } // ============================================================================ /** * @notice get the current sequencer's turn */ function getTurn( address submitter ) external view returns (uint256, uint256) { // update epoch address[] memory sequencers = IL2Sequencer(L2_SEQUENCER_CONTRACT) .getSequencerAddresses(false); uint256 epoch = IGov(L2_GOV_CONTRACT).rollupEpoch(); uint256 sequencersLen = sequencers.length; bool exist = false; uint256 submitterIndex = 0; while (submitterIndex < sequencersLen) { if (submitter == sequencers[submitterIndex]) { exist = true; break; } submitterIndex++; } require(exist, "invalid submitter"); uint256 _nextEpochStart = nextEpochStart; uint256 _nextSubmitterIndex = nextSubmitterIndex; while (_nextEpochStart + epoch <= block.timestamp) { _nextSubmitterIndex++; if (_nextSubmitterIndex == sequencersLen) { _nextSubmitterIndex = 0; } _nextEpochStart += epoch; } if (submitterIndex > _nextSubmitterIndex) { uint256 startTime = (submitterIndex - _nextSubmitterIndex) * epoch; return (startTime, startTime + epoch); } else if (submitterIndex < _nextSubmitterIndex) { uint256 startTime = (sequencersLen - _nextSubmitterIndex + submitterIndex) * epoch; return (startTime, startTime + epoch); } return (nextEpochStart, nextEpochStart + epoch); } /** * @notice get next submitter */ function getNextSubmitter() external view returns (address, uint256, uint256) { // update epoch address[] memory sequencers = IL2Sequencer(L2_SEQUENCER_CONTRACT) .getSequencerAddresses(false); uint256 epoch = IGov(L2_GOV_CONTRACT).rollupEpoch(); uint256 sequencersLen = sequencers.length; uint256 _nextEpochStart = nextEpochStart; uint256 _nextSubmitterIndex = nextSubmitterIndex; while (_nextEpochStart + epoch <= block.timestamp) { _nextSubmitterIndex++; if (_nextSubmitterIndex == sequencersLen) { _nextSubmitterIndex = 0; } _nextEpochStart += epoch; } return ( sequencers[_nextSubmitterIndex], _nextEpochStart, _nextEpochStart + epoch ); } /** * @notice get confirmed batch info */ function getConfirmedBatch( uint256 batchIndex ) external view returns (Types.BatchInfo memory batchInfo) { return confirmedBatchs[batchIndex]; } /** * @notice get epoch info */ function getEpoch( uint256 epochIndex ) external view returns (Types.EpochInfo memory epochInfo) { return epochs[epochIndex]; } } interface IL1MessageQueue { /// @notice Return the message of in `queueIndex`. /// @param queueIndex The index to query. function getCrossDomainMessage(uint256 queueIndex) external view returns (bytes32); /// @notice Pop finalized messages from queue. /// /// @dev We can pop at most 256 messages each time. And if the message is not skipped, /// the corresponding entry will be cleared. /// /// @param startIndex The start index to pop. /// @param count The number of messages to pop. /// @param skippedBitmap A bitmap indicates whether a message is skipped. function popCrossDomainMessage( uint256 startIndex, uint256 count, uint256 skippedBitmap ) external; } interface IRollup { /********** * Events * **********/ /// @notice Emitted when a new batch is committed. /// @param batchIndex The index of the batch. /// @param batchHash The hash of the batch. event CommitBatch(uint256 indexed batchIndex, bytes32 indexed batchHash); /// @notice revert a pending batch. /// @param batchIndex The index of the batch. /// @param batchHash The hash of the batch event RevertBatch(uint256 indexed batchIndex, bytes32 indexed batchHash); /// @notice Emitted when a batch is finalized. /// @param batchIndex The index of the batch. /// @param batchHash The hash of the batch /// @param stateRoot The state root on layer 2 after this batch. /// @param withdrawRoot The merkle root on layer2 after this batch. event FinalizeBatch( uint256 indexed batchIndex, bytes32 indexed batchHash, bytes32 stateRoot, bytes32 withdrawRoot ); /// @notice Emitted when owner updates the status of sequencer. /// @param account The address of account updated. /// @param status The status of the account updated. event UpdateSequencer(address indexed account, bool status); /// @notice Emitted when owner updates the status of prover. /// @param account The address of account updated. /// @param status The status of the account updated. event UpdateProver(address indexed account, bool status); /// @notice Emitted when owner updates the status of prover. /// @param account The address of account updated. /// @param status The status of the account updated. event UpdateChallenger(address indexed account, bool status); /// @notice Emitted when the address of rollup verifier is updated. /// @param oldVerifier The address of old rollup verifier. /// @param newVerifier The address of new rollup verifier. event UpdateVerifier( address indexed oldVerifier, address indexed newVerifier ); /// @notice Emitted when the value of `maxNumTxInChunk` is updated. /// @param oldMaxNumTxInChunk The old value of `maxNumTxInChunk`. /// @param newMaxNumTxInChunk The new value of `maxNumTxInChunk`. event UpdateMaxNumTxInChunk( uint256 oldMaxNumTxInChunk, uint256 newMaxNumTxInChunk ); /// @notice Emitted when the state of Chanllenge is updated. /// @param batchIndex The index of the batch. /// @param challenger The address of challenger. /// @param challengeDeposit The deposit of challenger. event ChallengeState( uint64 indexed batchIndex, address challenger, uint256 challengeDeposit ); /// @notice Emitted when the result of Chanllenge is updated. /// @param batchIndex The index of the batch. /// @param winner The address of winner. /// @param res The result of challenge. event ChallengeRes(uint64 indexed batchIndex, address winner, string res); /************************* * Public View Functions * *************************/ /// @notice The latest finalized batch index. function lastFinalizedBatchIndex() external view returns (uint256); /// @notice The latest finalized batch index. function lastCommittedBatchIndex() external view returns (uint256); /// @notice Return the batch hash of a committed batch. /// @param batchIndex The index of the batch. function committedBatches( uint256 batchIndex ) external view returns (bytes32); /// @notice Return the state root of a committed batch. /// @param batchIndex The index of the batch. function finalizedStateRoots( uint256 batchIndex ) external view returns (bytes32); /// @notice Return the the committed batch of withdrawalRoot. /// @param withdrawalRoot The withdrawal root. function withdrawalRoots( bytes32 withdrawalRoot ) external view returns (uint256); /// @notice Return whether the batch is finalized by batch index. /// @param batchIndex The index of the batch. function isBatchFinalized(uint256 batchIndex) external view returns (bool); /***************************** * Public Mutating Functions * *****************************/ /// @notice Commit a batch of transactions on layer 1. /// /// @param batchData The BatchData struct /// @param minGasLimit The min gas limit. function commitBatch( BatchData calldata batchData, uint32 minGasLimit ) payable external; /// @notice Revert a pending batch. /// @dev one can only revert unfinalized batches. /// @param batchHeader The header of current batch, see the encoding in comments of `commitBatch`. /// @param count The number of subsequent batches to revert, including current batch. function revertBatch(bytes calldata batchHeader, uint256 count) external; /// @param version The version of current batch. /// @param parentBatchHeader The header of parent batch, see the comments of `BatchHeaderV0Codec`. /// @param chunks The list of encoded chunks, see the comments of `ChunkCodec`. /// @param skippedL1MessageBitmap The bitmap indicates whether each L1 message is skipped or not. /// @param prevStateRoot The state root of parent batch. /// @param postStateRoot The state root of current batch. /// @param withdrawalRoot The withdraw trie root of current batch. /// @param signature The signature of current batch. struct BatchData { uint8 version; bytes parentBatchHeader; bytes[] chunks; bytes skippedL1MessageBitmap; bytes32 prevStateRoot; bytes32 postStateRoot; bytes32 withdrawalRoot; BatchSignature signature; } /// @param version the version of staking contract /// @param signers The index list of signers of current batch. /// @param signature The bls signature. struct BatchSignature { uint256 version; uint256[] signers; bytes signature; } } // solhint-disable no-inline-assembly // solhint-disable reason-string /// @title Rollup /// @notice This contract maintains data for the Morph rollup. contract Rollup is OwnableUpgradeable, PausableUpgradeable, IRollup { /************* * Constants * *************/ /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable layer2ChainId; /** * @notice Messenger contract on this domain. */ CrossDomainMessenger public immutable MESSENGER; /************* * Variables * *************/ /// @notice The maximum number of transactions allowed in each chunk. uint256 public maxNumTxInChunk; /// @notice The address of L1MessageQueue. address public messageQueue; /// @notice The address of RollupVerifier. address public verifier; /// @notice Whether an account is a sequencer. mapping(address => bool) public isSequencer; /// @notice Whether an account is a prover. mapping(address => bool) public isProver; /// @notice Whether an account is a challenger. mapping(address => bool) public isChallenger; /// @inheritdoc IRollup uint256 public override lastFinalizedBatchIndex; /// @inheritdoc IRollup uint256 public override lastCommittedBatchIndex; uint256 public latestL2BlockNumber; struct BatchStore { bytes32 batchHash; uint256 originTimestamp; bytes32 prevStateRoot; bytes32 postStateRoot; bytes32 withdrawalRoot; bytes32 dataHash; address sequencer; uint256 l1MessagePopped; uint256 totalL1MessagePopped; bytes skippedL1MessageBitmap; uint256 blockNumber; } mapping(uint256 => BatchStore) public committedBatchStores; /// @inheritdoc IRollup mapping(uint256 => bytes32) public override finalizedStateRoots; /** * @notice Store the withdrawalRoot of each batch. */ mapping(bytes32 => uint256) public withdrawalRoots; /** * @notice Batch challenge time. */ uint256 public FINALIZATION_PERIOD_SECONDS; /** * @notice The time when zkproof was generated and executed. */ uint256 public PROOF_WINDOW; /** * @notice The minimum value of staking. */ uint256 public MIN_DEPOSIT; /** * @notice User pledge record. */ mapping(address => uint256) public deposits; /** * @notice Store Challenge Information.(batchIndex => BatchChallenge) */ mapping(uint256 => BatchChallenge) public challenges; struct BatchChallenge { uint64 batchIndex; address challenger; uint256 challengeDeposit; uint256 startTime; bool finished; } /********************** * Function Modifiers * **********************/ modifier OnlySequencer() { // @note In the decentralized mode, it should be only called by a list of validator. require(isSequencer[_msgSender()], "caller not sequencer"); _; } modifier OnlyProver() { require(isProver[_msgSender()], "caller not prover"); _; } modifier onlyChallenger() { require(isChallenger[_msgSender()], "caller not challenger"); _; } /*************** * Constructor * ***************/ constructor(uint64 _chainId, address payable _messenger) { layer2ChainId = _chainId; MESSENGER = CrossDomainMessenger(_messenger); } function initialize( address _messageQueue, address _verifier, uint256 _maxNumTxInChunk, uint256 _minDeposit, uint256 _finalizationPeriodSeconds, uint256 _proofWindow ) public initializer { OwnableUpgradeable.__Ownable_init(); messageQueue = _messageQueue; verifier = _verifier; maxNumTxInChunk = _maxNumTxInChunk; FINALIZATION_PERIOD_SECONDS = _finalizationPeriodSeconds; PROOF_WINDOW = _proofWindow; MIN_DEPOSIT = _minDeposit; emit UpdateVerifier(address(0), _verifier); emit UpdateMaxNumTxInChunk(0, _maxNumTxInChunk); } /************************* * Public View Functions * *************************/ /// @inheritdoc IRollup function isBatchFinalized( uint256 _batchIndex ) external view override returns (bool) { return _batchIndex <= lastFinalizedBatchIndex; } /// @inheritdoc IRollup function committedBatches( uint256 batchIndex ) external view override returns (bytes32) { return committedBatchStores[batchIndex].batchHash; } /***************************** * Public Mutating Functions * *****************************/ /// @notice Sequencer stake function stake() external payable OnlySequencer { require( deposits[_msgSender()] + msg.value >= MIN_DEPOSIT, "do not have enough deposit" ); deposits[_msgSender()] += msg.value; } /// @notice Import layer 2 genesis block function importGenesisBatch( bytes calldata _batchHeader, bytes32 _postStateRoot, bytes32 _withdrawalRoot ) external { // check genesis batch header length require(_postStateRoot != bytes32(0), "zero state root"); // check whether the genesis batch is imported require(finalizedStateRoots[0] == bytes32(0), "genesis batch imported"); (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); bytes32 _dataHash = BatchHeaderV0Codec.dataHash(memPtr); // check all fields except `dataHash` and `lastBlockHash` are zero unchecked { uint256 sum = BatchHeaderV0Codec.version(memPtr) + BatchHeaderV0Codec.batchIndex(memPtr) + BatchHeaderV0Codec.l1MessagePopped(memPtr) + BatchHeaderV0Codec.totalL1MessagePopped(memPtr); require(sum == 0, "not all fields are zero"); } require( BatchHeaderV0Codec.dataHash(memPtr) != bytes32(0), "zero data hash" ); require( BatchHeaderV0Codec.parentBatchHash(memPtr) == bytes32(0), "nonzero parent batch hash" ); committedBatchStores[0] = BatchStore( _batchHash, block.timestamp, bytes32(0), _postStateRoot, _withdrawalRoot, _dataHash, _msgSender(), 0, 0, "", 0 ); finalizedStateRoots[0] = _postStateRoot; emit CommitBatch(0, _batchHash); emit FinalizeBatch(0, _batchHash, _postStateRoot, bytes32(0)); } /// @inheritdoc IRollup function commitBatch( BatchData calldata batchData, uint32 minGasLimit ) external payable override OnlySequencer whenNotPaused { require( deposits[_msgSender()] >= MIN_DEPOSIT, "insufficient staking amount" ); require(batchData.version == 0, "invalid version"); // check whether the batch is empty uint256 _chunksLength = batchData.chunks.length; require(_chunksLength > 0, "batch is empty"); require( batchData.prevStateRoot != bytes32(0), "previous state root is zero" ); require( batchData.postStateRoot != bytes32(0), "new state root is zero" ); // The overall memory layout in this function is organized as follows // +---------------------+-------------------+------------------+ // | parent batch header | chunk data hashes | new batch header | // +---------------------+-------------------+------------------+ // ^ ^ ^ // batchPtr dataPtr newBatchPtr (re-use var batchPtr) // // 1. We copy the parent batch header from calldata to memory starting at batchPtr // 2. We store `_chunksLength` number of Keccak hashes starting at `dataPtr`. Each Keccak // hash corresponds to the data hash of a chunk. So we reserve the memory region from // `dataPtr` to `dataPtr + _chunkLength * 32` for the chunk data hashes. // 3. The memory starting at `newBatchPtr` is used to store the new batch header and compute // the batch hash. // the variable `batchPtr` will be reused later for the current batch (uint256 batchPtr, bytes32 _parentBatchHash) = _loadBatchHeader( batchData.parentBatchHeader ); uint256 _batchIndex = BatchHeaderV0Codec.batchIndex(batchPtr); uint256 _totalL1MessagesPoppedOverall = BatchHeaderV0Codec .totalL1MessagePopped(batchPtr); require( committedBatchStores[_batchIndex].batchHash == _parentBatchHash, "incorrect parent batch hash" ); require( committedBatchStores[_batchIndex + 1].batchHash == bytes32(0), "batch already committed" ); require( _batchIndex == lastCommittedBatchIndex, "incorrect batch index" ); require( committedBatchStores[_batchIndex].postStateRoot == batchData.prevStateRoot, "incorrect previous state root" ); // load `dataPtr` and reserve the memory region for chunk data hashes uint256 dataPtr; assembly { dataPtr := mload(0x40) mstore(0x40, add(dataPtr, mul(_chunksLength, 32))) } // compute the data hash for each chunk uint256 _totalL1MessagesPoppedInBatch; for (uint256 i = 0; i < _chunksLength; i++) { uint256 _totalNumL1MessagesInChunk = _commitChunk( dataPtr, batchData.chunks[i], _totalL1MessagesPoppedInBatch, _totalL1MessagesPoppedOverall, batchData.skippedL1MessageBitmap ); if (i == _chunksLength - 1) { setLatestL2BlockNumber(batchData.chunks[i]); } unchecked { _totalL1MessagesPoppedInBatch += _totalNumL1MessagesInChunk; _totalL1MessagesPoppedOverall += _totalNumL1MessagesInChunk; dataPtr += 32; } } // check the length of bitmap unchecked { require( ((_totalL1MessagesPoppedInBatch + 255) / 256) * 32 == batchData.skippedL1MessageBitmap.length, "wrong bitmap length" ); } // compute the data hash for current batch bytes32 _dataHash; assembly { let dataLen := mul(_chunksLength, 0x20) _dataHash := keccak256(sub(dataPtr, dataLen), dataLen) batchPtr := mload(0x40) // reset batchPtr _batchIndex := add(_batchIndex, 1) // increase batch index } // store entries, the order matters BatchHeaderV0Codec.storeVersion(batchPtr, batchData.version); BatchHeaderV0Codec.storeBatchIndex(batchPtr, _batchIndex); BatchHeaderV0Codec.storeL1MessagePopped( batchPtr, _totalL1MessagesPoppedInBatch ); BatchHeaderV0Codec.storeTotalL1MessagePopped( batchPtr, _totalL1MessagesPoppedOverall ); BatchHeaderV0Codec.storeDataHash(batchPtr, _dataHash); BatchHeaderV0Codec.storeParentBatchHash(batchPtr, _parentBatchHash); BatchHeaderV0Codec.storeSkippedBitmap( batchPtr, batchData.skippedL1MessageBitmap ); // compute batch hash bytes32 _batchHash = BatchHeaderV0Codec.computeBatchHash( batchPtr, 89 + batchData.skippedL1MessageBitmap.length ); committedBatchStores[_batchIndex] = BatchStore( _batchHash, block.timestamp, batchData.prevStateRoot, batchData.postStateRoot, batchData.withdrawalRoot, _dataHash, _msgSender(), _totalL1MessagesPoppedInBatch, _totalL1MessagesPoppedOverall, batchData.skippedL1MessageBitmap, latestL2BlockNumber ); if (withdrawalRoots[batchData.withdrawalRoot] == 0) { withdrawalRoots[batchData.withdrawalRoot] = _batchIndex; } lastCommittedBatchIndex = _batchIndex; emit CommitBatch(_batchIndex, _batchHash); // abi encode updateSequencers data // bytes memory data = abi.encodeWithSelector( // Submitter.ackRollup.selector, // _batchIndex, // _msgSender(), // committedBatchStores[_batchIndex - 1].blockNumber + 1, // latestL2BlockNumber, // block.timestamp // ); // MESSENGER.sendMessage( // address(Predeploys.L2_SUBMITTER), // data, // minGasLimit // ); } /// @inheritdoc IRollup /// @dev If the owner want to revert a sequence of batches by sending multiple transactions, /// make sure to revert recent batches first. function revertBatch( bytes calldata _batchHeader, uint256 _count ) external onlyOwner { require(_count > 0, "count must be nonzero"); (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); // check batch hash uint256 _batchIndex = BatchHeaderV0Codec.batchIndex(memPtr); require( committedBatchStores[_batchIndex].batchHash == _batchHash, "incorrect batch hash" ); // make sure no gap is left when reverting from the ending to the beginning. require( committedBatchStores[_batchIndex + _count].batchHash == bytes32(0), "reverting must start from the ending" ); // check finalization require( _batchIndex > lastFinalizedBatchIndex, "can only revert unfinalized batch" ); while (_count > 0) { committedBatchStores[_batchIndex].batchHash = bytes32(0); emit RevertBatch(_batchIndex, _batchHash); unchecked { _batchIndex += 1; _count -= 1; } _batchHash = committedBatchStores[_batchIndex].batchHash; if (_batchHash == bytes32(0)) break; } lastCommittedBatchIndex = _batchIndex; } // challengeState challenges a batch by submitting a deposit. function challengeState(uint64 batchIndex) external payable onlyChallenger { require( lastFinalizedBatchIndex < batchIndex, "batch already finalized" ); require( committedBatchStores[batchIndex].batchHash != 0, "batch not exist" ); require( challenges[batchIndex].challenger == address(0), "already has challenge" ); // check challenge window // todo get finalization period from output oracle bool insideChallengeWindow = committedBatchStores[batchIndex] .originTimestamp + FINALIZATION_PERIOD_SECONDS > block.timestamp; require( insideChallengeWindow, "cannot challenge batch outside the challenge window" ); // check challenge amount require(msg.value >= MIN_DEPOSIT); deposits[_msgSender()] += msg.value; challenges[batchIndex] = BatchChallenge( batchIndex, _msgSender(), msg.value, block.timestamp, false ); emit ChallengeState(batchIndex, _msgSender(), msg.value); } // proveState proves a batch by submitting a proof. function proveState( uint64 _batchIndex, bytes calldata _aggrProof ) external { // check challenge exists require( challenges[_batchIndex].challenger != address(0), "challenge not exist" ); require( !challenges[_batchIndex].finished, "challenge already finished" ); bool insideChallengeWindow = challenges[_batchIndex].startTime + PROOF_WINDOW > block.timestamp; if (!insideChallengeWindow) { _challengerWin( _batchIndex, committedBatchStores[_batchIndex].sequencer, "timeout" ); // todo pause PORTAL contracts // PORTAL.pause(); } else { // check proof require(_aggrProof.length > 0, "invalid proof"); // compute public input hash bytes32 _publicInputHash = keccak256( abi.encodePacked( layer2ChainId, committedBatchStores[_batchIndex].prevStateRoot, committedBatchStores[_batchIndex].postStateRoot, committedBatchStores[_batchIndex].withdrawalRoot, committedBatchStores[_batchIndex].dataHash ) ); // verify batch IRollupVerifier(verifier).verifyAggregateProof( _batchIndex, _aggrProof, _publicInputHash ); _defenderWin( _batchIndex, committedBatchStores[_batchIndex].sequencer, "prove success" ); } challenges[_batchIndex].finished = true; } function _defenderWin( uint64 batchIndex, address sequencer, string memory _type ) internal { address challengerAddr = challenges[batchIndex].challenger; uint256 challengeDeposit = challenges[batchIndex].challengeDeposit; deposits[challengerAddr] -= challengeDeposit; deposits[sequencer] += challengeDeposit; emit ChallengeRes(batchIndex, sequencer, _type); } function _challengerWin( uint64 batchIndex, address sequencer, string memory _type ) internal { address challengerAddr = challenges[batchIndex].challenger; deposits[sequencer] -= MIN_DEPOSIT; uint256 challengeDeposit = challenges[batchIndex].challengeDeposit; deposits[challengerAddr] -= challengeDeposit; uint256 refundAmt = challengeDeposit + MIN_DEPOSIT; _transfer(challengerAddr, refundAmt); emit ChallengeRes(batchIndex, challengerAddr, _type); } function withdraw(uint256 amount) public OnlySequencer { address sequencer = _msgSender(); uint256 value = deposits[sequencer]; require(amount > 0, "withdraw amount should be positive"); require(amount + MIN_DEPOSIT > value, "insufficient funds"); deposits[sequencer] -= amount; _transfer(sequencer, amount); } function _transfer(address _to, uint256 _amount) internal { if (_amount > 0) { bool success = SafeCall.call(_to, gasleft(), _amount, hex""); require(success, "Rollup: ETH transfer failed"); } } function finalizeBatchs() public whenNotPaused { uint256 lastFinalizedBatchIndexCache = lastFinalizedBatchIndex; for ( uint256 i = lastFinalizedBatchIndexCache + 1; i <= lastCommittedBatchIndex; i++ ) { if ( // TODO publicnet needs to recover following batchInChallenge. // batchInChallenge(i) || batchInsideChallengeWindow(i) || !batchExist(i) ) { break; } finalizeBatch(i); } } function finalizeBatchsByNum(uint256 num) public whenNotPaused { require(num > 1, "finalize batch must bigger than 1"); uint256 lastFinalizedBatchIndexCache = lastFinalizedBatchIndex; for ( uint256 i = lastFinalizedBatchIndexCache + 1; i <= lastFinalizedBatchIndexCache + num; i++ ) { if ( // TODO publicnet needs to recover following batchInChallenge. // batchInChallenge(i) || batchInsideChallengeWindow(i) || !batchExist(i) ) { break; } finalizeBatch(i); } } function finalizeBatch(uint256 _batchIndex) public whenNotPaused { require(batchExist(_batchIndex), "batch not exist"); // TODO publicnet needs to recover following batchInChallenge. // require(!batchInChallenge(_batchIndex), "batch in challenge"); require( !batchInsideChallengeWindow(_batchIndex), "batch in challenge window" ); // verify previous state root. require( finalizedStateRoots[_batchIndex - 1] == committedBatchStores[_batchIndex].prevStateRoot, "incorrect previous state root" ); // avoid duplicated verification require( finalizedStateRoots[_batchIndex] == bytes32(0), "batch already verified" ); // check and update lastFinalizedBatchIndex unchecked { require( lastFinalizedBatchIndex + 1 == _batchIndex, "incorrect batch index" ); lastFinalizedBatchIndex = _batchIndex; } // record state root and withdrawal root finalizedStateRoots[_batchIndex] = committedBatchStores[_batchIndex] .postStateRoot; // Pop finalized and non-skipped message from L1MessageQueue. uint256 _l1MessagePopped = committedBatchStores[_batchIndex] .l1MessagePopped; if (_l1MessagePopped > 0) { IL1MessageQueue _queue = IL1MessageQueue(messageQueue); bytes memory _skippedL1MessageBitmap = committedBatchStores[ _batchIndex ].skippedL1MessageBitmap; uint256 bitmapPtr; assembly { bitmapPtr := add( _skippedL1MessageBitmap, /*BYTES_HEADER_SIZE*/ 32 ) } unchecked { uint256 _startIndex = committedBatchStores[_batchIndex] .totalL1MessagePopped - _l1MessagePopped; for (uint256 i = 0; i < _l1MessagePopped; i += 256) { uint256 _count = 256; if (_l1MessagePopped - i < _count) { _count = _l1MessagePopped - i; } uint256 _skippedBitmap; uint256 _index = i / 256; assembly { _skippedBitmap := mload(add(bitmapPtr, mul(_index, 32))) } _queue.popCrossDomainMessage( _startIndex, _count, _skippedBitmap ); _startIndex += 256; } } } emit FinalizeBatch( _batchIndex, committedBatchStores[_batchIndex].batchHash, committedBatchStores[_batchIndex].postStateRoot, committedBatchStores[_batchIndex].withdrawalRoot ); } /************************ * Restricted Functions * ************************/ /// @notice Update MIN_DEPOSIT. /// @param _newDepositAmount New min deposit amount. function updateMinDepositAmount( uint256 _newDepositAmount ) external onlyOwner { MIN_DEPOSIT = _newDepositAmount; } /// @notice Update PROOF_WINDOW. /// @param _newWindow New proof window. function updateProofWindow(uint256 _newWindow) external onlyOwner { PROOF_WINDOW = _newWindow; } /// @notice Update FINALIZATION_PERIOD_SECONDS. /// @param _newPeriod New finalize period sencdonds. function updateFinalizePeriodSeconds( uint256 _newPeriod ) external onlyOwner { FINALIZATION_PERIOD_SECONDS = _newPeriod; } /// @notice Add an account to the sequencer list. /// @param _account The address of account to add. function addSequencer(address _account) external onlyOwner { isSequencer[_account] = true; emit UpdateSequencer(_account, true); } /// @notice Remove an account from the sequencer list. /// @param _account The address of account to remove. function removeSequencer(address _account) external onlyOwner { isSequencer[_account] = false; deposits[_account] = 0; _transfer(_account, deposits[_account]); emit UpdateSequencer(_account, false); } /// @notice Add an account to the prover list. /// @param _account The address of account to add. function addProver(address _account) external onlyOwner { isProver[_account] = true; emit UpdateProver(_account, true); } /// @notice Remove an account from the prover list. /// @param _account The address of account to remove. function removeProver(address _account) external onlyOwner { isProver[_account] = false; emit UpdateProver(_account, false); } /// @notice Add an account to the challenger list. /// @param _account The address of account to add. function addChallenger(address _account) external onlyOwner { isChallenger[_account] = true; emit UpdateChallenger(_account, true); } /// @notice Remove an account from the challenger list. /// @param _account The address of account to remove. function removeChallenger(address _account) external onlyOwner { isChallenger[_account] = false; emit UpdateChallenger(_account, false); } /// @notice Update the address verifier contract. /// @param _newVerifier The address of new verifier contract. function updateVerifier(address _newVerifier) external onlyOwner { address _oldVerifier = verifier; verifier = _newVerifier; emit UpdateVerifier(_oldVerifier, _newVerifier); } /// @notice Update the value of `maxNumTxInChunk`. /// @param _maxNumTxInChunk The new value of `maxNumTxInChunk`. function updateMaxNumTxInChunk( uint256 _maxNumTxInChunk ) external onlyOwner { uint256 _oldMaxNumTxInChunk = maxNumTxInChunk; maxNumTxInChunk = _maxNumTxInChunk; emit UpdateMaxNumTxInChunk(_oldMaxNumTxInChunk, _maxNumTxInChunk); } /// @notice Pause the contract /// @param _status The pause status to update. function setPause(bool _status) external onlyOwner { if (_status) { _pause(); } else { _unpause(); } } /********************** * Internal Functions * **********************/ /// @dev Internal function to load batch header from calldata to memory. /// @param _batchHeader The batch header in calldata. /// @return memPtr The start memory offset of loaded batch header. /// @return _batchHash The hash of the loaded batch header. function _loadBatchHeader( bytes calldata _batchHeader ) internal pure returns (uint256 memPtr, bytes32 _batchHash) { // load to memory uint256 _length; (memPtr, _length) = BatchHeaderV0Codec.loadAndValidate(_batchHeader); // compute batch hash _batchHash = BatchHeaderV0Codec.computeBatchHash(memPtr, _length); } function setLatestL2BlockNumber(bytes memory _chunk) internal { uint256 blockPtr; uint256 chunkPtr; assembly { chunkPtr := add(_chunk, 0x20) blockPtr := add(chunkPtr, 1) } uint256 _numBlocks = ChunkCodec.validateChunkLength( chunkPtr, _chunk.length ); for (uint256 i = 0; i < _numBlocks - 1; i++) { unchecked { blockPtr += ChunkCodec.BLOCK_CONTEXT_LENGTH; } } latestL2BlockNumber = ChunkCodec.blockNumber(blockPtr); } /// @dev Internal function to commit a chunk. /// @param memPtr The start memory offset to store list of `dataHash`. /// @param _chunk The encoded chunk to commit. /// @param _totalL1MessagesPoppedInBatch The total number of L1 messages popped in current batch. /// @param _totalL1MessagesPoppedOverall The total number of L1 messages popped in all batches including current batch. /// @param _skippedL1MessageBitmap The bitmap indicates whether each L1 message is skipped or not. /// @return _totalNumL1MessagesInChunk The total number of L1 message popped in current chunk function _commitChunk( uint256 memPtr, bytes memory _chunk, uint256 _totalL1MessagesPoppedInBatch, uint256 _totalL1MessagesPoppedOverall, bytes calldata _skippedL1MessageBitmap ) internal view returns (uint256 _totalNumL1MessagesInChunk) { uint256 chunkPtr; uint256 startDataPtr; uint256 dataPtr; uint256 blockPtr; assembly { dataPtr := mload(0x40) startDataPtr := dataPtr chunkPtr := add(_chunk, 0x20) // skip chunkLength blockPtr := add(chunkPtr, 1) // skip numBlocks } uint256 _numBlocks = ChunkCodec.validateChunkLength( chunkPtr, _chunk.length ); // concatenate block contexts, use scope to avoid stack too deep { uint256 _totalTransactionsInChunk; for (uint256 i = 0; i < _numBlocks; i++) { dataPtr = ChunkCodec.copyBlockContext(chunkPtr, dataPtr, i); uint256 _numTransactionsInBlock = ChunkCodec.numTransactions( blockPtr ); unchecked { _totalTransactionsInChunk += _numTransactionsInBlock; blockPtr += ChunkCodec.BLOCK_CONTEXT_LENGTH; } } assembly { mstore(0x40, add(dataPtr, mul(_totalTransactionsInChunk, 0x20))) // reserve memory for tx hashes } } // It is used to compute the actual number of transactions in chunk. uint256 txHashStartDataPtr; assembly { txHashStartDataPtr := dataPtr blockPtr := add(chunkPtr, 1) // reset block ptr } // concatenate tx hashes uint256 l2TxPtr = ChunkCodec.l2TxPtr(chunkPtr, _numBlocks); while (_numBlocks > 0) { // concatenate l1 message hashes uint256 _numL1MessagesInBlock = ChunkCodec.numL1Messages(blockPtr); dataPtr = _loadL1MessageHashes( dataPtr, _numL1MessagesInBlock, _totalL1MessagesPoppedInBatch, _totalL1MessagesPoppedOverall, _skippedL1MessageBitmap ); // concatenate l2 transaction hashes uint256 _numTransactionsInBlock = ChunkCodec.numTransactions( blockPtr ); require( _numTransactionsInBlock >= _numL1MessagesInBlock, "num txs less than num L1 msgs" ); for ( uint256 j = _numL1MessagesInBlock; j < _numTransactionsInBlock; j++ ) { bytes32 txHash; (txHash, l2TxPtr) = ChunkCodec.loadL2TxHash(l2TxPtr); assembly { mstore(dataPtr, txHash) dataPtr := add(dataPtr, 0x20) } } unchecked { _totalNumL1MessagesInChunk += _numL1MessagesInBlock; _totalL1MessagesPoppedInBatch += _numL1MessagesInBlock; _totalL1MessagesPoppedOverall += _numL1MessagesInBlock; _numBlocks -= 1; blockPtr += ChunkCodec.BLOCK_CONTEXT_LENGTH; } } // check the actual number of transactions in the chunk require( (dataPtr - txHashStartDataPtr) / 32 <= maxNumTxInChunk, "too many txs in one chunk" ); // check chunk has correct length require( l2TxPtr - chunkPtr == _chunk.length, "incomplete l2 transaction data" ); // compute data hash and store to memory assembly { let dataHash := keccak256(startDataPtr, sub(dataPtr, startDataPtr)) mstore(memPtr, dataHash) } return _totalNumL1MessagesInChunk; } /// @dev Internal function to load L1 message hashes from the message queue. /// @param _ptr The memory offset to store the transaction hash. /// @param _numL1Messages The number of L1 messages to load. /// @param _totalL1MessagesPoppedInBatch The total number of L1 messages popped in current batch. /// @param _totalL1MessagesPoppedOverall The total number of L1 messages popped in all batches including current batch. /// @param _skippedL1MessageBitmap The bitmap indicates whether each L1 message is skipped or not. /// @return uint256 The new memory offset after loading. function _loadL1MessageHashes( uint256 _ptr, uint256 _numL1Messages, uint256 _totalL1MessagesPoppedInBatch, uint256 _totalL1MessagesPoppedOverall, bytes calldata _skippedL1MessageBitmap ) internal view returns (uint256) { if (_numL1Messages == 0) return _ptr; IL1MessageQueue _messageQueue = IL1MessageQueue(messageQueue); unchecked { uint256 _bitmap; uint256 rem; for (uint256 i = 0; i < _numL1Messages; i++) { uint256 quo = _totalL1MessagesPoppedInBatch >> 8; rem = _totalL1MessagesPoppedInBatch & 0xff; // load bitmap every 256 bits if (i == 0 || rem == 0) { assembly { _bitmap := calldataload( add(_skippedL1MessageBitmap.offset, mul(0x20, quo)) ) } } if (((_bitmap >> rem) & 1) == 0) { // message not skipped bytes32 _hash = _messageQueue.getCrossDomainMessage( _totalL1MessagesPoppedOverall ); assembly { mstore(_ptr, _hash) _ptr := add(_ptr, 0x20) } } _totalL1MessagesPoppedInBatch += 1; _totalL1MessagesPoppedOverall += 1; } // check last L1 message is not skipped, _totalL1MessagesPoppedInBatch must > 0 rem = (_totalL1MessagesPoppedInBatch - 1) & 0xff; require(((_bitmap >> rem) & 1) == 0, "cannot skip last L1 message"); } return _ptr; } function batchInChallenge(uint256 batchIndex) public view returns (bool) { return challenges[batchIndex].challenger != address(0) && !challenges[batchIndex].finished; } function batchExist(uint256 batchIndex) public view returns (bool) { return committedBatchStores[batchIndex].originTimestamp > 0; } function batchInsideChallengeWindow( uint256 batchIndex ) public view returns (bool) { return committedBatchStores[batchIndex].originTimestamp + FINALIZATION_PERIOD_SECONDS > block.timestamp; } }
[{"inputs":[{"internalType":"uint64","name":"_chainId","type":"uint64"},{"internalType":"address payable","name":"_messenger","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"batchIndex","type":"uint64"},{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"string","name":"res","type":"string"}],"name":"ChallengeRes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"batchIndex","type":"uint64"},{"indexed":false,"internalType":"address","name":"challenger","type":"address"},{"indexed":false,"internalType":"uint256","name":"challengeDeposit","type":"uint256"}],"name":"ChallengeState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchIndex","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"}],"name":"CommitBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchIndex","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"withdrawRoot","type":"bytes32"}],"name":"FinalizeBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchIndex","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"batchHash","type":"bytes32"}],"name":"RevertBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UpdateChallenger","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxNumTxInChunk","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxNumTxInChunk","type":"uint256"}],"name":"UpdateMaxNumTxInChunk","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UpdateProver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UpdateSequencer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVerifier","type":"address"},{"indexed":true,"internalType":"address","name":"newVerifier","type":"address"}],"name":"UpdateVerifier","type":"event"},{"inputs":[],"name":"FINALIZATION_PERIOD_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MESSENGER","outputs":[{"internalType":"contract CrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEPOSIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROOF_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addChallenger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addProver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addSequencer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"batchIndex","type":"uint256"}],"name":"batchExist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"batchIndex","type":"uint256"}],"name":"batchInChallenge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"batchIndex","type":"uint256"}],"name":"batchInsideChallengeWindow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"batchIndex","type":"uint64"}],"name":"challengeState","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"challenges","outputs":[{"internalType":"uint64","name":"batchIndex","type":"uint64"},{"internalType":"address","name":"challenger","type":"address"},{"internalType":"uint256","name":"challengeDeposit","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"bool","name":"finished","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"bytes","name":"parentBatchHeader","type":"bytes"},{"internalType":"bytes[]","name":"chunks","type":"bytes[]"},{"internalType":"bytes","name":"skippedL1MessageBitmap","type":"bytes"},{"internalType":"bytes32","name":"prevStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"postStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256[]","name":"signers","type":"uint256[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IRollup.BatchSignature","name":"signature","type":"tuple"}],"internalType":"struct IRollup.BatchData","name":"batchData","type":"tuple"},{"internalType":"uint32","name":"minGasLimit","type":"uint32"}],"name":"commitBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"committedBatchStores","outputs":[{"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"internalType":"uint256","name":"originTimestamp","type":"uint256"},{"internalType":"bytes32","name":"prevStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"postStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"address","name":"sequencer","type":"address"},{"internalType":"uint256","name":"l1MessagePopped","type":"uint256"},{"internalType":"uint256","name":"totalL1MessagePopped","type":"uint256"},{"internalType":"bytes","name":"skippedL1MessageBitmap","type":"bytes"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"batchIndex","type":"uint256"}],"name":"committedBatches","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_batchIndex","type":"uint256"}],"name":"finalizeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizeBatchs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"finalizeBatchsByNum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"finalizedStateRoots","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_batchHeader","type":"bytes"},{"internalType":"bytes32","name":"_postStateRoot","type":"bytes32"},{"internalType":"bytes32","name":"_withdrawalRoot","type":"bytes32"}],"name":"importGenesisBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_messageQueue","type":"address"},{"internalType":"address","name":"_verifier","type":"address"},{"internalType":"uint256","name":"_maxNumTxInChunk","type":"uint256"},{"internalType":"uint256","name":"_minDeposit","type":"uint256"},{"internalType":"uint256","name":"_finalizationPeriodSeconds","type":"uint256"},{"internalType":"uint256","name":"_proofWindow","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_batchIndex","type":"uint256"}],"name":"isBatchFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isChallenger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isProver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isSequencer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastCommittedBatchIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastFinalizedBatchIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestL2BlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"layer2ChainId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxNumTxInChunk","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_batchIndex","type":"uint64"},{"internalType":"bytes","name":"_aggrProof","type":"bytes"}],"name":"proveState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeChallenger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeProver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeSequencer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_batchHeader","type":"bytes"},{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"revertBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPeriod","type":"uint256"}],"name":"updateFinalizePeriodSeconds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNumTxInChunk","type":"uint256"}],"name":"updateMaxNumTxInChunk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDepositAmount","type":"uint256"}],"name":"updateMinDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newWindow","type":"uint256"}],"name":"updateProofWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVerifier","type":"address"}],"name":"updateVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"withdrawalRoots","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b506040516200469b3803806200469b833981016040819052620000349162000054565b6001600160401b039091166080526001600160a01b031660a052620000a9565b600080604083850312156200006857600080fd5b82516001600160401b03811681146200008057600080fd5b60208401519092506001600160a01b03811681146200009e57600080fd5b809150509250929050565b60805160a0516145c5620000d6600039600061091301526000818161034b015261225001526145c56000f3fe6080604052600436106103345760003560e01c80635c975abb116101b0578063a415d8dc116100ec578063e33491a711610095578063ef6602ba1161006f578063ef6602ba14610a66578063f2fde38b14610a7c578063f4daa29114610a9c578063fc7e286d14610ab257600080fd5b8063e33491a714610a10578063e3fff1dd14610a30578063eb1ec18f14610a5057600080fd5b8063bedb86fb116100c6578063bedb86fb146109ba578063de8b3035146109da578063e1e158a5146109fa57600080fd5b8063a415d8dc14610955578063aeb5440d14610985578063b571d3dd1461099a57600080fd5b806386489ba9116101595780638da5cb5b116101335780638da5cb5b1461081a5780638f1d377614610845578063927ede2d1461090157806397fc007c1461093557600080fd5b806386489ba9146107c75780638a336231146107e75780638d644bb71461080757600080fd5b80636d46e9871161018a5780636d46e98714610762578063715018a61461079257806384780205146107a757600080fd5b80635c975abb1461070a5780636989ca7c146107225780636c578c1d1461074257600080fd5b806321e2f9e01161027f5780633a4b66f1116102285780634c4b9e4f116102025780634c4b9e4f1461069757806357e0af6c146106b757806359b70310146106d757806359ef1120146106ea57600080fd5b80633a4b66f11461064c5780633b70c18a146106545780633e9e82ca1461068157600080fd5b80632571098d116102595780632571098d146105ad5780632b7ac3f3146105da5780632e1a7d4d1461062c57600080fd5b806321e2f9e01461052e57806322b75477146105605780632362f03e1461058057600080fd5b806310d44583116102e157806318af3b2b116102bb57806318af3b2b146104ce5780631d49e457146104ee5780631e2283021461050e57600080fd5b806310d4458314610475578063116a1f4214610495578063121dcd50146104b857600080fd5b80630a245924116103125780630a245924146103dc5780630b79cdda1461041c5780630ceb67801461045357600080fd5b806303c7f4af1461033957806304d772151461038b578063059def61146103c6575b600080fd5b34801561034557600080fd5b5061036d7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561039757600080fd5b506103b86103a6366004613db9565b60a26020526000908152604090205481565b604051908152602001610382565b3480156103d257600080fd5b506103b8609d5481565b3480156103e857600080fd5b5061040c6103f7366004613dfb565b609b6020526000908152604090205460ff1681565b6040519015158152602001610382565b34801561042857600080fd5b5061043c610437366004613db9565b610adf565b6040516103829b9a99989796959493929190613e81565b34801561045f57600080fd5b5061047361046e366004613dfb565b610bd9565b005b34801561048157600080fd5b50610473610490366004613f46565b610c4c565b3480156104a157600080fd5b5061040c6104b0366004613db9565b609d54101590565b3480156104c457600080fd5b506103b8609e5481565b3480156104da57600080fd5b5061040c6104e9366004613db9565b610ea0565b3480156104fa57600080fd5b50610473610509366004613dfb565b610eca565b34801561051a57600080fd5b50610473610529366004613db9565b610f36565b34801561053a57600080fd5b5061040c610549366004613db9565b600090815260a06020526040902060010154151590565b34801561056c57600080fd5b5061047361057b366004613db9565b610f83565b34801561058c57600080fd5b506103b861059b366004613db9565b600090815260a0602052604090205490565b3480156105b957600080fd5b506103b86105c8366004613db9565b60a16020526000908152604090205481565b3480156105e657600080fd5b506099546106079073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610382565b34801561063857600080fd5b50610473610647366004613db9565b61106b565b6104736111ee565b34801561066057600080fd5b506098546106079073ffffffffffffffffffffffffffffffffffffffff1681565b34801561068d57600080fd5b506103b8609f5481565b3480156106a357600080fd5b506104736106b2366004613f92565b6112df565b3480156106c357600080fd5b506104736106d2366004613db9565b6117df565b6104736106e5366004613fe3565b6117ec565b3480156106f657600080fd5b5061047361070536600461405c565b612006565b34801561071657600080fd5b5060655460ff1661040c565b34801561072e57600080fd5b5061047361073d366004613dfb565b612402565b34801561074e57600080fd5b5061047361075d366004613dfb565b612498565b34801561076e57600080fd5b5061040c61077d366004613dfb565b609a6020526000908152604090205460ff1681565b34801561079e57600080fd5b506104736124fc565b3480156107b357600080fd5b506104736107c2366004613db9565b612510565b3480156107d357600080fd5b506104736107e23660046140af565b61251d565b3480156107f357600080fd5b50610473610802366004613dfb565b612749565b610473610815366004614104565b6127b5565b34801561082657600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610607565b34801561085157600080fd5b506108b7610860366004613db9565b60a760205260009081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff1685565b6040805167ffffffffffffffff909616865273ffffffffffffffffffffffffffffffffffffffff90941660208601529284019190915260608301521515608082015260a001610382565b34801561090d57600080fd5b506106077f000000000000000000000000000000000000000000000000000000000000000081565b34801561094157600080fd5b50610473610950366004613dfb565b612b35565b34801561096157600080fd5b5061040c610970366004613dfb565b609c6020526000908152604090205460ff1681565b34801561099157600080fd5b50610473612bb4565b3480156109a657600080fd5b506104736109b5366004613dfb565b612c1e565b3480156109c657600080fd5b506104736109d536600461411f565b612c82565b3480156109e657600080fd5b5061040c6109f5366004613db9565b612ca3565b348015610a0657600080fd5b506103b860a55481565b348015610a1c57600080fd5b50610473610a2b366004613db9565b612cfa565b348015610a3c57600080fd5b50610473610a4b366004613db9565b61311f565b348015610a5c57600080fd5b506103b860a45481565b348015610a7257600080fd5b506103b860975481565b348015610a8857600080fd5b50610473610a97366004613dfb565b61312c565b348015610aa857600080fd5b506103b860a35481565b348015610abe57600080fd5b506103b8610acd366004613dfb565b60a66020526000908152604090205481565b60a060205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a018054999a9899979896979596949573ffffffffffffffffffffffffffffffffffffffff909416949293919291610b5090614141565b80601f0160208091040260200160405190810160405280929190818152602001828054610b7c90614141565b8015610bc95780601f10610b9e57610100808354040283529160200191610bc9565b820191906000526020600020905b815481529060010190602001808311610bac57829003601f168201915b50505050509080600a015490508b565b610be16131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609c6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c546131c6565b60008111610ca95760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f000000000000000000000060448201526064015b60405180910390fd5b600080610cb6858561322d565b915091506000610cca836001015160c01c90565b600081815260a060205260409020549091508214610d2a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca0565b600060a081610d3987856141c3565b81526020019081526020016000206000015414610dbd5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b609d548111610e345760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e66696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b5b8315610e9657600081815260a0602052604080822082905551839183917ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb47101469190a3600101600081815260a0602052604090205460001990940193915081610e35575b609e555050505050565b60a354600082815260a0602052604081206001015490914291610ec391906141c3565b1192915050565b610ed26131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609b6020908152604091829020805460ff1916600190811790915591519182527f967f99d5d403870e4356ff46556df3a6b6ba1f50146639aaedfb9f248eb8661e9101610c41565b610f3e6131c6565b609780549082905560408051828152602081018490527f6d0f49971e462a2f78a25906f145cb29cd5e7bd01ebf681ac8f58cb814e5877a910160405180910390a15050565b610f8b61324a565b600181116110015760405162461bcd60e51b815260206004820152602160248201527f66696e616c697a65206261746368206d75737420626967676572207468616e2060448201527f31000000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b609d5460006110118260016141c3565b90505b61101e83836141c3565b81116110665761102d81610ea0565b806110475750600081815260a06020526040902060010154155b6110665761105481612cfa565b8061105e816141d6565b915050611014565b505050565b336000908152609a602052604090205460ff166110ca5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b33600081815260a660205260409020548261114d5760405162461bcd60e51b815260206004820152602260248201527f776974686472617720616d6f756e742073686f756c6420626520706f7369746960448201527f76650000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b8060a5548461115c91906141c3565b116111a95760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610ca0565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260a66020526040812080548592906111de9084906141f0565b909155506110669050828461329d565b336000908152609a602052604090205460ff1661124d5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b60a55433600090815260a6602052604090205461126b9034906141c3565b10156112b95760405162461bcd60e51b815260206004820152601a60248201527f646f206e6f74206861766520656e6f756768206465706f7369740000000000006044820152606401610ca0565b33600090815260a66020526040812080543492906112d89084906141c3565b9091555050565b8161132c5760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610ca0565b6000805260a16020527f32ae1b88a7d4f92d7e214b63c8ea04cd13e2faaa60c50f499f2254336d98f88254156113a45760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610ca0565b6000806113b1868661322d565b9150915060006113c2836019015190565b905060006113d4846011015160c01c90565b600985015160c01c600186015160c01c865160f81c0101019050801561143c5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420616c6c206669656c647320617265207a65726f0000000000000000006044820152606401610ca0565b50600061144a846019015190565b036114975760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610ca0565b60006114a4846039015190565b146114f15760405162461bcd60e51b815260206004820152601960248201527f6e6f6e7a65726f20706172656e742062617463682068617368000000000000006044820152606401610ca0565b6040518061016001604052808381526020014281526020016000801b815260200186815260200185815260200182815260200161152b3390565b73ffffffffffffffffffffffffffffffffffffffff908116825260006020808401829052604080850183905280518083018252838152606080870191909152608095860184905292805260a080835286517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea908155928701517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808eb55908601517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ec55918501517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ed55928401517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ee558301517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ef5560c08301517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905560e08201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f1556101008201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f2556101208201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f39061172f9082614280565b506101409190910151600a90910155600080805260a16020527f32ae1b88a7d4f92d7e214b63c8ea04cd13e2faaa60c50f499f2254336d98f8828690556040518391907f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f908290a360408051868152600060208201819052849290917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a350505050505050565b6117e76131c6565b60a455565b336000908152609a602052604090205460ff1661184b5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b61185361324a565b60a55433600090815260a6602052604090205410156118b45760405162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e74207374616b696e6720616d6f756e7400000000006044820152606401610ca0565b6118c1602083018361435e565b60ff16156119115760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610ca0565b60006119206040840184614381565b915050806119705760405162461bcd60e51b815260206004820152600e60248201527f626174636820697320656d7074790000000000000000000000000000000000006044820152606401610ca0565b60808301356119c15760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610ca0565b60a0830135611a125760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610ca0565b600080611a2a611a2560208701876143e9565b61322d565b915091506000611a3e836001015160c01c90565b90506000611a50846011015160c01c90565b600083815260a060205260409020549091508314611ab05760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610ca0565b600060a081611ac08560016141c3565b81526020019081526020016000206000015414611b1f5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610ca0565b609e548214611b705760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca0565b600082815260a06020526040902060030154608088013514611bd45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca0565b604080516020870281019091526000805b87811015611d1d576000611c7c84611c0060408e018e614381565b85818110611c1057611c1061444e565b9050602002810190611c2291906143e9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505085888f8060600190611c7791906143e9565b61330f565b9050611c8960018a6141f0565b8203611cfb57611cfb611c9f60408d018d614381565b84818110611caf57611caf61444e565b9050602002810190611cc191906143e9565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061358992505050565b9384019360209390930192919091019080611d15816141d6565b915050611be5565b50611d2b60608a018a6143e9565b905061010060ff83010460200214611d855760405162461bcd60e51b815260206004820152601360248201527f77726f6e67206269746d6170206c656e677468000000000000000000000000006044820152606401610ca0565b60208781028084032060405197506001959095019490611db5908890611dad908d018d61435e565b60ff166135e1565b60c085811b600189015282811b600989015284901b60118801526019870181905260398701869052611df387611dee60608d018d6143e9565b6135e8565b6000611e1788611e0660608e018e6143e9565b611e12915060596141c3565b902090565b90506040518061016001604052808281526020014281526020018c6080013581526020018c60a0013581526020018c60c001358152602001838152602001611e5c3390565b73ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018681526020018c8060600190611e9391906143e9565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509385525050609f546020938401525088815260a0808352604091829020845181559284015160018401559083015160028301556060830151600383015560808301516004830155820151600582015560c08201516006820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560e0820151600782015561010082015160088201556101208201516009820190611f879082614280565b506101409190910151600a9091015560c08b0135600090815260a260205260408120549003611fc75760c08b0135600090815260a2602052604090208690555b609e869055604051819087907f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f90600090a35050505050505050505050565b67ffffffffffffffff8316600090815260a7602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661208e5760405162461bcd60e51b815260206004820152601360248201527f6368616c6c656e6765206e6f74206578697374000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8316600090815260a7602052604090206003015460ff16156120fb5760405162461bcd60e51b815260206004820152601a60248201527f6368616c6c656e676520616c72656164792066696e69736865640000000000006044820152606401610ca0565b60a45467ffffffffffffffff8416600090815260a760205260408120600201549091429161212991906141c3565b119050806121ad5767ffffffffffffffff8416600090815260a06020908152604091829020600601548251808401909352600783527f74696d656f757400000000000000000000000000000000000000000000000000918301919091526121a891869173ffffffffffffffffffffffffffffffffffffffff16906135f4565b6123d7565b816121fa5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8416600090815260a06020908152604080832060028101546003820154600483015460059093015493517fffffffffffffffff0000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060c01b1695810195909552602885019190915260488401526068830152608882015260a801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020909101206099547fcc780aa100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063cc780aa19061232590889088908890879060040161447d565b60006040518083038186803b15801561233d57600080fd5b505afa158015612351573d6000803e3d6000fd5b505050506123d58560a060008867ffffffffffffffff16815260200190815260200160002060060160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518060400160405280600d81526020017f70726f766520737563636573730000000000000000000000000000000000000081525061371b565b505b50505067ffffffffffffffff16600090815260a760205260409020600301805460ff19166001179055565b61240a6131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000908152609a60209081526040808320805460ff1916905560a6909152812081905561244f90829061329d565b6040516000815273ffffffffffffffffffffffffffffffffffffffff8216907f631cb110fbe6a87fba5414d6b2cff02264480535cd1f5abdbc4fa638bc0b569290602001610c41565b6124a06131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609c60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c41565b6125046131c6565b61250e600061380d565b565b6125186131c6565b60a555565b600054610100900460ff161580801561253d5750600054600160ff909116105b806125575750303b158015612557575060005460ff166001145b6125c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca0565b6000805460ff19166001179055801561260957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b612611613884565b6098805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609980549289169290911682179055609786905560a384905560a483905560a58590556040516000907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a36040805160008152602081018790527f6d0f49971e462a2f78a25906f145cb29cd5e7bd01ebf681ac8f58cb814e5877a910160405180910390a1801561274057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6127516131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609a6020908152604091829020805460ff1916600190811790915591519182527f631cb110fbe6a87fba5414d6b2cff02264480535cd1f5abdbc4fa638bc0b56929101610c41565b336000908152609c602052604090205460ff166128145760405162461bcd60e51b815260206004820152601560248201527f63616c6c6572206e6f74206368616c6c656e67657200000000000000000000006044820152606401610ca0565b8067ffffffffffffffff16609d541061286f5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610ca0565b67ffffffffffffffff8116600090815260a0602052604081205490036128d75760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8116600090815260a7602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16156129605760405162461bcd60e51b815260206004820152601560248201527f616c726561647920686173206368616c6c656e676500000000000000000000006044820152606401610ca0565b60a35467ffffffffffffffff8216600090815260a060205260408120600101549091429161298e91906141c3565b11905080612a045760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610ca0565b60a554341015612a1357600080fd5b33600090815260a6602052604081208054349290612a329084906141c3565b90915550506040805160a08101825267ffffffffffffffff848116808352336020808501828152348688018181524260608901908152600060808a0181815288825260a78752908b902099518a54955173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009096169916989098179390931788555160018801559051600287015593516003909501805495151560ff1990961695909517909455845190815292830191909152825190927f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976928290030190a25050565b612b3d6131c6565b6099805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd9690600090a35050565b612bbc61324a565b609d546000612bcc8260016141c3565b90505b609e548111612c1a57612be181610ea0565b80612bfb5750600081815260a06020526040902060010154155b612c1a57612c0881612cfa565b80612c12816141d6565b915050612bcf565b5050565b612c266131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609b60209081526040808320805460ff19169055519182527f967f99d5d403870e4356ff46556df3a6b6ba1f50146639aaedfb9f248eb8661e9101610c41565b612c8a6131c6565b8015612c9b57612c98613909565b50565b612c98613970565b600081815260a7602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590612cf45750600082815260a7602052604090206003015460ff16155b92915050565b612d0261324a565b600081815260a06020526040902060010154612d605760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca0565b612d6981610ea0565b15612db65760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610ca0565b600081815260a060205260408120600201549060a190612dd76001856141f0565b81526020019081526020016000205414612e335760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca0565b600081815260a1602052604090205415612e8f5760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610ca0565b80609d5460010114612ee35760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca0565b609d819055600081815260a060208181526040808420600381015460a184529190942055526007015480156130bb57609854600083815260a060205260408120600901805473ffffffffffffffffffffffffffffffffffffffff90931692612f4a90614141565b80601f0160208091040260200160405190810160405280929190818152602001828054612f7690614141565b8015612fc35780601f10612f9857610100808354040283529160200191612fc3565b820191906000526020600020905b815481529060010190602001808311612fa657829003601f168201915b505050600087815260a060209081526040822060080154949550850193879003925090505b858110156130b55761010081870381111561300257508086035b6101008204602081028501516040517f55f613ce00000000000000000000000000000000000000000000000000000000815260048101869052602481018490526044810182905290919073ffffffffffffffffffffffffffffffffffffffff8916906355f613ce90606401600060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b505050506101008501945050505061010081019050612fe8565b50505050505b600082815260a0602052604090819020805460038201546004909201549251909285927f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d926131139290918252602082015260400190565b60405180910390a35050565b6131276131c6565b60a355565b6131346131c6565b73ffffffffffffffffffffffffffffffffffffffff81166131bd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ca0565b612c988161380d565b60335473ffffffffffffffffffffffffffffffffffffffff16331461250e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca0565b600080600061323c85856139a9565b812090969095509350505050565b60655460ff161561250e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610ca0565b8015612c1a5760006132c0835a8460405180602001604052806000815250613a82565b9050806110665760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610ca0565b60405185516000916020880191819060218a01908590613330908690613a9c565b90506000805b828110156133ab57603c8102870160018101518652602101517fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000166020860152603a85019450600061338c856038015160f01c90565b603c9590950194929092019150806133a3816141d6565b915050613336565b5060200283016040526001850191508260006133cc8784603c020160010190565b90505b82156134b25760006133e585603a015160f01c90565b90506133f586828f8f8f8f613b60565b95506000613407866038015160f01c90565b9050818110156134595760405162461bcd60e51b815260206004820152601d60248201527f6e756d20747873206c657373207468616e206e756d204c31206d7367730000006044820152606401610ca0565b815b8181101561349057835160e01c60048086018290208a5260209099019894019093019280613488816141d6565b91505061345b565b50509b8c019b9a8b019a9790970196603c9390930192600019909201916133cf565b60975460206134c184886141f0565b6134cb91906144e5565b11156135195760405162461bcd60e51b815260206004820152601960248201527f746f6f206d616e792074787320696e206f6e65206368756e6b000000000000006044820152606401610ca0565b8c5161352588836141f0565b146135725760405162461bcd60e51b815260206004820152601e60248201527f696e636f6d706c657465206c32207472616e73616374696f6e206461746100006044820152606401610ca0565b5050505081900390208852505b9695505050505050565b8051602182019060208301906000906135a3908390613a9c565b905060005b6135b36001836141f0565b8110156135d357603c8401935080806135cb906141d6565b9150506135a8565b5050905160c01c609f555050565b8082535050565b80826059850137505050565b67ffffffffffffffff8316600090815260a7602090815260408083205460a55473ffffffffffffffffffffffffffffffffffffffff878116865260a690945291842080546801000000000000000090920490931693919291906136589084906141f0565b909155505067ffffffffffffffff8416600090815260a7602090815260408083206001015473ffffffffffffffffffffffffffffffffffffffff8516845260a690925282208054919283926136ae9084906141f0565b909155505060a5546000906136c390836141c3565b90506136cf838261329d565b8567ffffffffffffffff167f1e66d5dca70bf28588ef2f5cb3c299e65e2e7bdef2767823d3ae47a9caff95c6848660405161370b929190614520565b60405180910390a2505050505050565b67ffffffffffffffff8316600090815260a76020908152604080832080546001909101546801000000000000000090910473ffffffffffffffffffffffffffffffffffffffff1680855260a69093529083208054929391928392906137819084906141f0565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600090815260a66020526040812080548392906137bb9084906141c3565b925050819055508467ffffffffffffffff167f1e66d5dca70bf28588ef2f5cb3c299e65e2e7bdef2767823d3ae47a9caff95c685856040516137fe929190614520565b60405180910390a25050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166139015760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca0565b61250e613ce1565b61391161324a565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139463390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b613978613d67565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613946565b60008160598110156139fd5760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610ca0565b6040519150808483378082016040526000613a1c836009015160c01c90565b905061010060ff8201046020026059018214613a7a5760405162461bcd60e51b815260206004820152601360248201527f77726f6e67206269746d6170206c656e677468000000000000000000000000006044820152606401610ca0565b509250929050565b600080600080845160208601878a8af19695505050505050565b6000613aa9835160f81c90565b905060008111613afb5760405162461bcd60e51b815260206004820152601160248201527f6e6f20626c6f636b20696e206368756e6b0000000000000000000000000000006044820152606401610ca0565b613b06603c82614557565b613b119060016141c3565b821015612cf45760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206368756e6b206c656e6774680000000000000000000000006044820152606401610ca0565b600085600003613b7157508561357f565b60985473ffffffffffffffffffffffffffffffffffffffff16600080805b89811015613c765760ff89169150600889901c811580613bad575082155b15613bbc578060200288013593505b600184841c16600003613c65576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018a905260009073ffffffffffffffffffffffffffffffffffffffff87169063ae453cd590602401602060405180830381865afa158015613c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c5b9190614576565b8d52506020909b019a5b506001988901989788019701613b8f565b505060ff60001988011681811c60011615613cd35760405162461bcd60e51b815260206004820152601b60248201527f63616e6e6f7420736b6970206c617374204c31206d65737361676500000000006044820152606401610ca0565b509798975050505050505050565b600054610100900460ff16613d5e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca0565b61250e3361380d565b60655460ff1661250e5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610ca0565b600060208284031215613dcb57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114613df657600080fd5b919050565b600060208284031215613e0d57600080fd5b613e1682613dd2565b9392505050565b6000815180845260005b81811015613e4357602081850181015186830182015201613e27565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60006101608d83528c60208401528b60408401528a60608401528960808401528860a084015273ffffffffffffffffffffffffffffffffffffffff881660c08401528660e08401528561010084015280610120840152613ee381840186613e1d565b915050826101408301529c9b505050505050505050505050565b60008083601f840112613f0f57600080fd5b50813567ffffffffffffffff811115613f2757600080fd5b602083019150836020828501011115613f3f57600080fd5b9250929050565b600080600060408486031215613f5b57600080fd5b833567ffffffffffffffff811115613f7257600080fd5b613f7e86828701613efd565b909790965060209590950135949350505050565b60008060008060608587031215613fa857600080fd5b843567ffffffffffffffff811115613fbf57600080fd5b613fcb87828801613efd565b90989097506020870135966040013595509350505050565b60008060408385031215613ff657600080fd5b823567ffffffffffffffff81111561400d57600080fd5b8301610100818603121561402057600080fd5b9150602083013563ffffffff8116811461403957600080fd5b809150509250929050565b803567ffffffffffffffff81168114613df657600080fd5b60008060006040848603121561407157600080fd5b61407a84614044565b9250602084013567ffffffffffffffff81111561409657600080fd5b6140a286828701613efd565b9497909650939450505050565b60008060008060008060c087890312156140c857600080fd5b6140d187613dd2565b95506140df60208801613dd2565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561411657600080fd5b613e1682614044565b60006020828403121561413157600080fd5b81358015158114613e1657600080fd5b600181811c9082168061415557607f821691505b60208210810361418e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612cf457612cf4614194565b600060001982036141e9576141e9614194565b5060010190565b81810381811115612cf457612cf4614194565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f82111561106657600081815260208120601f850160051c810160208610156142595750805b601f850160051c820191505b8181101561427857828155600101614265565b505050505050565b815167ffffffffffffffff81111561429a5761429a614203565b6142ae816142a88454614141565b84614232565b602080601f8311600181146142e357600084156142cb5750858301515b600019600386901b1c1916600185901b178555614278565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561433057888601518255948401946001909101908401614311565b508582101561434e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561437057600080fd5b813560ff81168114613e1657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126143b657600080fd5b83018035915067ffffffffffffffff8211156143d157600080fd5b6020019150600581901b3603821315613f3f57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261441e57600080fd5b83018035915067ffffffffffffffff82111561443957600080fd5b602001915036819003821315613f3f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff851681526060602082015282606082015282846080830137600060808483010152600060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905082604083015295945050505050565b60008261451b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061454f6040830184613e1d565b949350505050565b600081600019048311821515161561457157614571614194565b500290565b60006020828403121561458857600080fd5b505191905056fea264697066735822122067c2a5601257bceecf78922d6cda335fbcdcc053ae51ded734a35f4e1563a1ed64736f6c634300081000330000000000000000000000000000000000000000000000000000000000000a96000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
Deployed Bytecode
0x6080604052600436106103345760003560e01c80635c975abb116101b0578063a415d8dc116100ec578063e33491a711610095578063ef6602ba1161006f578063ef6602ba14610a66578063f2fde38b14610a7c578063f4daa29114610a9c578063fc7e286d14610ab257600080fd5b8063e33491a714610a10578063e3fff1dd14610a30578063eb1ec18f14610a5057600080fd5b8063bedb86fb116100c6578063bedb86fb146109ba578063de8b3035146109da578063e1e158a5146109fa57600080fd5b8063a415d8dc14610955578063aeb5440d14610985578063b571d3dd1461099a57600080fd5b806386489ba9116101595780638da5cb5b116101335780638da5cb5b1461081a5780638f1d377614610845578063927ede2d1461090157806397fc007c1461093557600080fd5b806386489ba9146107c75780638a336231146107e75780638d644bb71461080757600080fd5b80636d46e9871161018a5780636d46e98714610762578063715018a61461079257806384780205146107a757600080fd5b80635c975abb1461070a5780636989ca7c146107225780636c578c1d1461074257600080fd5b806321e2f9e01161027f5780633a4b66f1116102285780634c4b9e4f116102025780634c4b9e4f1461069757806357e0af6c146106b757806359b70310146106d757806359ef1120146106ea57600080fd5b80633a4b66f11461064c5780633b70c18a146106545780633e9e82ca1461068157600080fd5b80632571098d116102595780632571098d146105ad5780632b7ac3f3146105da5780632e1a7d4d1461062c57600080fd5b806321e2f9e01461052e57806322b75477146105605780632362f03e1461058057600080fd5b806310d44583116102e157806318af3b2b116102bb57806318af3b2b146104ce5780631d49e457146104ee5780631e2283021461050e57600080fd5b806310d4458314610475578063116a1f4214610495578063121dcd50146104b857600080fd5b80630a245924116103125780630a245924146103dc5780630b79cdda1461041c5780630ceb67801461045357600080fd5b806303c7f4af1461033957806304d772151461038b578063059def61146103c6575b600080fd5b34801561034557600080fd5b5061036d7f0000000000000000000000000000000000000000000000000000000000000a9681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561039757600080fd5b506103b86103a6366004613db9565b60a26020526000908152604090205481565b604051908152602001610382565b3480156103d257600080fd5b506103b8609d5481565b3480156103e857600080fd5b5061040c6103f7366004613dfb565b609b6020526000908152604090205460ff1681565b6040519015158152602001610382565b34801561042857600080fd5b5061043c610437366004613db9565b610adf565b6040516103829b9a99989796959493929190613e81565b34801561045f57600080fd5b5061047361046e366004613dfb565b610bd9565b005b34801561048157600080fd5b50610473610490366004613f46565b610c4c565b3480156104a157600080fd5b5061040c6104b0366004613db9565b609d54101590565b3480156104c457600080fd5b506103b8609e5481565b3480156104da57600080fd5b5061040c6104e9366004613db9565b610ea0565b3480156104fa57600080fd5b50610473610509366004613dfb565b610eca565b34801561051a57600080fd5b50610473610529366004613db9565b610f36565b34801561053a57600080fd5b5061040c610549366004613db9565b600090815260a06020526040902060010154151590565b34801561056c57600080fd5b5061047361057b366004613db9565b610f83565b34801561058c57600080fd5b506103b861059b366004613db9565b600090815260a0602052604090205490565b3480156105b957600080fd5b506103b86105c8366004613db9565b60a16020526000908152604090205481565b3480156105e657600080fd5b506099546106079073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610382565b34801561063857600080fd5b50610473610647366004613db9565b61106b565b6104736111ee565b34801561066057600080fd5b506098546106079073ffffffffffffffffffffffffffffffffffffffff1681565b34801561068d57600080fd5b506103b8609f5481565b3480156106a357600080fd5b506104736106b2366004613f92565b6112df565b3480156106c357600080fd5b506104736106d2366004613db9565b6117df565b6104736106e5366004613fe3565b6117ec565b3480156106f657600080fd5b5061047361070536600461405c565b612006565b34801561071657600080fd5b5060655460ff1661040c565b34801561072e57600080fd5b5061047361073d366004613dfb565b612402565b34801561074e57600080fd5b5061047361075d366004613dfb565b612498565b34801561076e57600080fd5b5061040c61077d366004613dfb565b609a6020526000908152604090205460ff1681565b34801561079e57600080fd5b506104736124fc565b3480156107b357600080fd5b506104736107c2366004613db9565b612510565b3480156107d357600080fd5b506104736107e23660046140af565b61251d565b3480156107f357600080fd5b50610473610802366004613dfb565b612749565b610473610815366004614104565b6127b5565b34801561082657600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610607565b34801561085157600080fd5b506108b7610860366004613db9565b60a760205260009081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff1685565b6040805167ffffffffffffffff909616865273ffffffffffffffffffffffffffffffffffffffff90941660208601529284019190915260608301521515608082015260a001610382565b34801561090d57600080fd5b506106077f000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e81565b34801561094157600080fd5b50610473610950366004613dfb565b612b35565b34801561096157600080fd5b5061040c610970366004613dfb565b609c6020526000908152604090205460ff1681565b34801561099157600080fd5b50610473612bb4565b3480156109a657600080fd5b506104736109b5366004613dfb565b612c1e565b3480156109c657600080fd5b506104736109d536600461411f565b612c82565b3480156109e657600080fd5b5061040c6109f5366004613db9565b612ca3565b348015610a0657600080fd5b506103b860a55481565b348015610a1c57600080fd5b50610473610a2b366004613db9565b612cfa565b348015610a3c57600080fd5b50610473610a4b366004613db9565b61311f565b348015610a5c57600080fd5b506103b860a45481565b348015610a7257600080fd5b506103b860975481565b348015610a8857600080fd5b50610473610a97366004613dfb565b61312c565b348015610aa857600080fd5b506103b860a35481565b348015610abe57600080fd5b506103b8610acd366004613dfb565b60a66020526000908152604090205481565b60a060205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a018054999a9899979896979596949573ffffffffffffffffffffffffffffffffffffffff909416949293919291610b5090614141565b80601f0160208091040260200160405190810160405280929190818152602001828054610b7c90614141565b8015610bc95780601f10610b9e57610100808354040283529160200191610bc9565b820191906000526020600020905b815481529060010190602001808311610bac57829003601f168201915b50505050509080600a015490508b565b610be16131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609c6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c546131c6565b60008111610ca95760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f000000000000000000000060448201526064015b60405180910390fd5b600080610cb6858561322d565b915091506000610cca836001015160c01c90565b600081815260a060205260409020549091508214610d2a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca0565b600060a081610d3987856141c3565b81526020019081526020016000206000015414610dbd5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b609d548111610e345760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e66696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b5b8315610e9657600081815260a0602052604080822082905551839183917ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb47101469190a3600101600081815260a0602052604090205460001990940193915081610e35575b609e555050505050565b60a354600082815260a0602052604081206001015490914291610ec391906141c3565b1192915050565b610ed26131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609b6020908152604091829020805460ff1916600190811790915591519182527f967f99d5d403870e4356ff46556df3a6b6ba1f50146639aaedfb9f248eb8661e9101610c41565b610f3e6131c6565b609780549082905560408051828152602081018490527f6d0f49971e462a2f78a25906f145cb29cd5e7bd01ebf681ac8f58cb814e5877a910160405180910390a15050565b610f8b61324a565b600181116110015760405162461bcd60e51b815260206004820152602160248201527f66696e616c697a65206261746368206d75737420626967676572207468616e2060448201527f31000000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b609d5460006110118260016141c3565b90505b61101e83836141c3565b81116110665761102d81610ea0565b806110475750600081815260a06020526040902060010154155b6110665761105481612cfa565b8061105e816141d6565b915050611014565b505050565b336000908152609a602052604090205460ff166110ca5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b33600081815260a660205260409020548261114d5760405162461bcd60e51b815260206004820152602260248201527f776974686472617720616d6f756e742073686f756c6420626520706f7369746960448201527f76650000000000000000000000000000000000000000000000000000000000006064820152608401610ca0565b8060a5548461115c91906141c3565b116111a95760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610ca0565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260a66020526040812080548592906111de9084906141f0565b909155506110669050828461329d565b336000908152609a602052604090205460ff1661124d5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b60a55433600090815260a6602052604090205461126b9034906141c3565b10156112b95760405162461bcd60e51b815260206004820152601a60248201527f646f206e6f74206861766520656e6f756768206465706f7369740000000000006044820152606401610ca0565b33600090815260a66020526040812080543492906112d89084906141c3565b9091555050565b8161132c5760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610ca0565b6000805260a16020527f32ae1b88a7d4f92d7e214b63c8ea04cd13e2faaa60c50f499f2254336d98f88254156113a45760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610ca0565b6000806113b1868661322d565b9150915060006113c2836019015190565b905060006113d4846011015160c01c90565b600985015160c01c600186015160c01c865160f81c0101019050801561143c5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420616c6c206669656c647320617265207a65726f0000000000000000006044820152606401610ca0565b50600061144a846019015190565b036114975760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610ca0565b60006114a4846039015190565b146114f15760405162461bcd60e51b815260206004820152601960248201527f6e6f6e7a65726f20706172656e742062617463682068617368000000000000006044820152606401610ca0565b6040518061016001604052808381526020014281526020016000801b815260200186815260200185815260200182815260200161152b3390565b73ffffffffffffffffffffffffffffffffffffffff908116825260006020808401829052604080850183905280518083018252838152606080870191909152608095860184905292805260a080835286517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea908155928701517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808eb55908601517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ec55918501517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ed55928401517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ee558301517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ef5560c08301517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905560e08201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f1556101008201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f2556101208201517fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808f39061172f9082614280565b506101409190910151600a90910155600080805260a16020527f32ae1b88a7d4f92d7e214b63c8ea04cd13e2faaa60c50f499f2254336d98f8828690556040518391907f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f908290a360408051868152600060208201819052849290917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a350505050505050565b6117e76131c6565b60a455565b336000908152609a602052604090205460ff1661184b5760405162461bcd60e51b815260206004820152601460248201527f63616c6c6572206e6f742073657175656e6365720000000000000000000000006044820152606401610ca0565b61185361324a565b60a55433600090815260a6602052604090205410156118b45760405162461bcd60e51b815260206004820152601b60248201527f696e73756666696369656e74207374616b696e6720616d6f756e7400000000006044820152606401610ca0565b6118c1602083018361435e565b60ff16156119115760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610ca0565b60006119206040840184614381565b915050806119705760405162461bcd60e51b815260206004820152600e60248201527f626174636820697320656d7074790000000000000000000000000000000000006044820152606401610ca0565b60808301356119c15760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610ca0565b60a0830135611a125760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610ca0565b600080611a2a611a2560208701876143e9565b61322d565b915091506000611a3e836001015160c01c90565b90506000611a50846011015160c01c90565b600083815260a060205260409020549091508314611ab05760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610ca0565b600060a081611ac08560016141c3565b81526020019081526020016000206000015414611b1f5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610ca0565b609e548214611b705760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca0565b600082815260a06020526040902060030154608088013514611bd45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca0565b604080516020870281019091526000805b87811015611d1d576000611c7c84611c0060408e018e614381565b85818110611c1057611c1061444e565b9050602002810190611c2291906143e9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505085888f8060600190611c7791906143e9565b61330f565b9050611c8960018a6141f0565b8203611cfb57611cfb611c9f60408d018d614381565b84818110611caf57611caf61444e565b9050602002810190611cc191906143e9565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061358992505050565b9384019360209390930192919091019080611d15816141d6565b915050611be5565b50611d2b60608a018a6143e9565b905061010060ff83010460200214611d855760405162461bcd60e51b815260206004820152601360248201527f77726f6e67206269746d6170206c656e677468000000000000000000000000006044820152606401610ca0565b60208781028084032060405197506001959095019490611db5908890611dad908d018d61435e565b60ff166135e1565b60c085811b600189015282811b600989015284901b60118801526019870181905260398701869052611df387611dee60608d018d6143e9565b6135e8565b6000611e1788611e0660608e018e6143e9565b611e12915060596141c3565b902090565b90506040518061016001604052808281526020014281526020018c6080013581526020018c60a0013581526020018c60c001358152602001838152602001611e5c3390565b73ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018681526020018c8060600190611e9391906143e9565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509385525050609f546020938401525088815260a0808352604091829020845181559284015160018401559083015160028301556060830151600383015560808301516004830155820151600582015560c08201516006820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560e0820151600782015561010082015160088201556101208201516009820190611f879082614280565b506101409190910151600a9091015560c08b0135600090815260a260205260408120549003611fc75760c08b0135600090815260a2602052604090208690555b609e869055604051819087907f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f90600090a35050505050505050505050565b67ffffffffffffffff8316600090815260a7602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661208e5760405162461bcd60e51b815260206004820152601360248201527f6368616c6c656e6765206e6f74206578697374000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8316600090815260a7602052604090206003015460ff16156120fb5760405162461bcd60e51b815260206004820152601a60248201527f6368616c6c656e676520616c72656164792066696e69736865640000000000006044820152606401610ca0565b60a45467ffffffffffffffff8416600090815260a760205260408120600201549091429161212991906141c3565b119050806121ad5767ffffffffffffffff8416600090815260a06020908152604091829020600601548251808401909352600783527f74696d656f757400000000000000000000000000000000000000000000000000918301919091526121a891869173ffffffffffffffffffffffffffffffffffffffff16906135f4565b6123d7565b816121fa5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8416600090815260a06020908152604080832060028101546003820154600483015460059093015493517fffffffffffffffff0000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000a9660c01b1695810195909552602885019190915260488401526068830152608882015260a801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020909101206099547fcc780aa100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063cc780aa19061232590889088908890879060040161447d565b60006040518083038186803b15801561233d57600080fd5b505afa158015612351573d6000803e3d6000fd5b505050506123d58560a060008867ffffffffffffffff16815260200190815260200160002060060160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518060400160405280600d81526020017f70726f766520737563636573730000000000000000000000000000000000000081525061371b565b505b50505067ffffffffffffffff16600090815260a760205260409020600301805460ff19166001179055565b61240a6131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000908152609a60209081526040808320805460ff1916905560a6909152812081905561244f90829061329d565b6040516000815273ffffffffffffffffffffffffffffffffffffffff8216907f631cb110fbe6a87fba5414d6b2cff02264480535cd1f5abdbc4fa638bc0b569290602001610c41565b6124a06131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609c60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c41565b6125046131c6565b61250e600061380d565b565b6125186131c6565b60a555565b600054610100900460ff161580801561253d5750600054600160ff909116105b806125575750303b158015612557575060005460ff166001145b6125c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca0565b6000805460ff19166001179055801561260957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b612611613884565b6098805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609980549289169290911682179055609786905560a384905560a483905560a58590556040516000907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a36040805160008152602081018790527f6d0f49971e462a2f78a25906f145cb29cd5e7bd01ebf681ac8f58cb814e5877a910160405180910390a1801561274057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6127516131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609a6020908152604091829020805460ff1916600190811790915591519182527f631cb110fbe6a87fba5414d6b2cff02264480535cd1f5abdbc4fa638bc0b56929101610c41565b336000908152609c602052604090205460ff166128145760405162461bcd60e51b815260206004820152601560248201527f63616c6c6572206e6f74206368616c6c656e67657200000000000000000000006044820152606401610ca0565b8067ffffffffffffffff16609d541061286f5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610ca0565b67ffffffffffffffff8116600090815260a0602052604081205490036128d75760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca0565b67ffffffffffffffff8116600090815260a7602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16156129605760405162461bcd60e51b815260206004820152601560248201527f616c726561647920686173206368616c6c656e676500000000000000000000006044820152606401610ca0565b60a35467ffffffffffffffff8216600090815260a060205260408120600101549091429161298e91906141c3565b11905080612a045760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610ca0565b60a554341015612a1357600080fd5b33600090815260a6602052604081208054349290612a329084906141c3565b90915550506040805160a08101825267ffffffffffffffff848116808352336020808501828152348688018181524260608901908152600060808a0181815288825260a78752908b902099518a54955173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009096169916989098179390931788555160018801559051600287015593516003909501805495151560ff1990961695909517909455845190815292830191909152825190927f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976928290030190a25050565b612b3d6131c6565b6099805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd9690600090a35050565b612bbc61324a565b609d546000612bcc8260016141c3565b90505b609e548111612c1a57612be181610ea0565b80612bfb5750600081815260a06020526040902060010154155b612c1a57612c0881612cfa565b80612c12816141d6565b915050612bcf565b5050565b612c266131c6565b73ffffffffffffffffffffffffffffffffffffffff81166000818152609b60209081526040808320805460ff19169055519182527f967f99d5d403870e4356ff46556df3a6b6ba1f50146639aaedfb9f248eb8661e9101610c41565b612c8a6131c6565b8015612c9b57612c98613909565b50565b612c98613970565b600081815260a7602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590612cf45750600082815260a7602052604090206003015460ff16155b92915050565b612d0261324a565b600081815260a06020526040902060010154612d605760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca0565b612d6981610ea0565b15612db65760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610ca0565b600081815260a060205260408120600201549060a190612dd76001856141f0565b81526020019081526020016000205414612e335760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca0565b600081815260a1602052604090205415612e8f5760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610ca0565b80609d5460010114612ee35760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca0565b609d819055600081815260a060208181526040808420600381015460a184529190942055526007015480156130bb57609854600083815260a060205260408120600901805473ffffffffffffffffffffffffffffffffffffffff90931692612f4a90614141565b80601f0160208091040260200160405190810160405280929190818152602001828054612f7690614141565b8015612fc35780601f10612f9857610100808354040283529160200191612fc3565b820191906000526020600020905b815481529060010190602001808311612fa657829003601f168201915b505050600087815260a060209081526040822060080154949550850193879003925090505b858110156130b55761010081870381111561300257508086035b6101008204602081028501516040517f55f613ce00000000000000000000000000000000000000000000000000000000815260048101869052602481018490526044810182905290919073ffffffffffffffffffffffffffffffffffffffff8916906355f613ce90606401600060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b505050506101008501945050505061010081019050612fe8565b50505050505b600082815260a0602052604090819020805460038201546004909201549251909285927f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d926131139290918252602082015260400190565b60405180910390a35050565b6131276131c6565b60a355565b6131346131c6565b73ffffffffffffffffffffffffffffffffffffffff81166131bd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ca0565b612c988161380d565b60335473ffffffffffffffffffffffffffffffffffffffff16331461250e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca0565b600080600061323c85856139a9565b812090969095509350505050565b60655460ff161561250e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610ca0565b8015612c1a5760006132c0835a8460405180602001604052806000815250613a82565b9050806110665760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610ca0565b60405185516000916020880191819060218a01908590613330908690613a9c565b90506000805b828110156133ab57603c8102870160018101518652602101517fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000166020860152603a85019450600061338c856038015160f01c90565b603c9590950194929092019150806133a3816141d6565b915050613336565b5060200283016040526001850191508260006133cc8784603c020160010190565b90505b82156134b25760006133e585603a015160f01c90565b90506133f586828f8f8f8f613b60565b95506000613407866038015160f01c90565b9050818110156134595760405162461bcd60e51b815260206004820152601d60248201527f6e756d20747873206c657373207468616e206e756d204c31206d7367730000006044820152606401610ca0565b815b8181101561349057835160e01c60048086018290208a5260209099019894019093019280613488816141d6565b91505061345b565b50509b8c019b9a8b019a9790970196603c9390930192600019909201916133cf565b60975460206134c184886141f0565b6134cb91906144e5565b11156135195760405162461bcd60e51b815260206004820152601960248201527f746f6f206d616e792074787320696e206f6e65206368756e6b000000000000006044820152606401610ca0565b8c5161352588836141f0565b146135725760405162461bcd60e51b815260206004820152601e60248201527f696e636f6d706c657465206c32207472616e73616374696f6e206461746100006044820152606401610ca0565b5050505081900390208852505b9695505050505050565b8051602182019060208301906000906135a3908390613a9c565b905060005b6135b36001836141f0565b8110156135d357603c8401935080806135cb906141d6565b9150506135a8565b5050905160c01c609f555050565b8082535050565b80826059850137505050565b67ffffffffffffffff8316600090815260a7602090815260408083205460a55473ffffffffffffffffffffffffffffffffffffffff878116865260a690945291842080546801000000000000000090920490931693919291906136589084906141f0565b909155505067ffffffffffffffff8416600090815260a7602090815260408083206001015473ffffffffffffffffffffffffffffffffffffffff8516845260a690925282208054919283926136ae9084906141f0565b909155505060a5546000906136c390836141c3565b90506136cf838261329d565b8567ffffffffffffffff167f1e66d5dca70bf28588ef2f5cb3c299e65e2e7bdef2767823d3ae47a9caff95c6848660405161370b929190614520565b60405180910390a2505050505050565b67ffffffffffffffff8316600090815260a76020908152604080832080546001909101546801000000000000000090910473ffffffffffffffffffffffffffffffffffffffff1680855260a69093529083208054929391928392906137819084906141f0565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600090815260a66020526040812080548392906137bb9084906141c3565b925050819055508467ffffffffffffffff167f1e66d5dca70bf28588ef2f5cb3c299e65e2e7bdef2767823d3ae47a9caff95c685856040516137fe929190614520565b60405180910390a25050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166139015760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca0565b61250e613ce1565b61391161324a565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139463390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b613978613d67565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613946565b60008160598110156139fd5760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610ca0565b6040519150808483378082016040526000613a1c836009015160c01c90565b905061010060ff8201046020026059018214613a7a5760405162461bcd60e51b815260206004820152601360248201527f77726f6e67206269746d6170206c656e677468000000000000000000000000006044820152606401610ca0565b509250929050565b600080600080845160208601878a8af19695505050505050565b6000613aa9835160f81c90565b905060008111613afb5760405162461bcd60e51b815260206004820152601160248201527f6e6f20626c6f636b20696e206368756e6b0000000000000000000000000000006044820152606401610ca0565b613b06603c82614557565b613b119060016141c3565b821015612cf45760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206368756e6b206c656e6774680000000000000000000000006044820152606401610ca0565b600085600003613b7157508561357f565b60985473ffffffffffffffffffffffffffffffffffffffff16600080805b89811015613c765760ff89169150600889901c811580613bad575082155b15613bbc578060200288013593505b600184841c16600003613c65576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018a905260009073ffffffffffffffffffffffffffffffffffffffff87169063ae453cd590602401602060405180830381865afa158015613c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c5b9190614576565b8d52506020909b019a5b506001988901989788019701613b8f565b505060ff60001988011681811c60011615613cd35760405162461bcd60e51b815260206004820152601b60248201527f63616e6e6f7420736b6970206c617374204c31206d65737361676500000000006044820152606401610ca0565b509798975050505050505050565b600054610100900460ff16613d5e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca0565b61250e3361380d565b60655460ff1661250e5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610ca0565b600060208284031215613dcb57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114613df657600080fd5b919050565b600060208284031215613e0d57600080fd5b613e1682613dd2565b9392505050565b6000815180845260005b81811015613e4357602081850181015186830182015201613e27565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60006101608d83528c60208401528b60408401528a60608401528960808401528860a084015273ffffffffffffffffffffffffffffffffffffffff881660c08401528660e08401528561010084015280610120840152613ee381840186613e1d565b915050826101408301529c9b505050505050505050505050565b60008083601f840112613f0f57600080fd5b50813567ffffffffffffffff811115613f2757600080fd5b602083019150836020828501011115613f3f57600080fd5b9250929050565b600080600060408486031215613f5b57600080fd5b833567ffffffffffffffff811115613f7257600080fd5b613f7e86828701613efd565b909790965060209590950135949350505050565b60008060008060608587031215613fa857600080fd5b843567ffffffffffffffff811115613fbf57600080fd5b613fcb87828801613efd565b90989097506020870135966040013595509350505050565b60008060408385031215613ff657600080fd5b823567ffffffffffffffff81111561400d57600080fd5b8301610100818603121561402057600080fd5b9150602083013563ffffffff8116811461403957600080fd5b809150509250929050565b803567ffffffffffffffff81168114613df657600080fd5b60008060006040848603121561407157600080fd5b61407a84614044565b9250602084013567ffffffffffffffff81111561409657600080fd5b6140a286828701613efd565b9497909650939450505050565b60008060008060008060c087890312156140c857600080fd5b6140d187613dd2565b95506140df60208801613dd2565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561411657600080fd5b613e1682614044565b60006020828403121561413157600080fd5b81358015158114613e1657600080fd5b600181811c9082168061415557607f821691505b60208210810361418e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612cf457612cf4614194565b600060001982036141e9576141e9614194565b5060010190565b81810381811115612cf457612cf4614194565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f82111561106657600081815260208120601f850160051c810160208610156142595750805b601f850160051c820191505b8181101561427857828155600101614265565b505050505050565b815167ffffffffffffffff81111561429a5761429a614203565b6142ae816142a88454614141565b84614232565b602080601f8311600181146142e357600084156142cb5750858301515b600019600386901b1c1916600185901b178555614278565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561433057888601518255948401946001909101908401614311565b508582101561434e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561437057600080fd5b813560ff81168114613e1657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126143b657600080fd5b83018035915067ffffffffffffffff8211156143d157600080fd5b6020019150600581901b3603821315613f3f57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261441e57600080fd5b83018035915067ffffffffffffffff82111561443957600080fd5b602001915036819003821315613f3f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff851681526060602082015282606082015282846080830137600060808483010152600060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905082604083015295945050505050565b60008261451b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff8316815260406020820152600061454f6040830184613e1d565b949350505050565b600081600019048311821515161561457157614571614194565b500290565b60006020828403121561458857600080fd5b505191905056fea264697066735822122067c2a5601257bceecf78922d6cda335fbcdcc053ae51ded734a35f4e1563a1ed64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000a96000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
-----Decoded View---------------
Arg [0] : _chainId (uint64): 2710
Arg [1] : _messenger (address): 0xFE26613A717A793560dF394928bcC22Ed0D8542e
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000a96
Arg [1] : 000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
Deployed Bytecode Sourcemap
184227:36828:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;184431:37;;;;;;;;;;;;;;;;;;188:18:1;176:31;;;158:50;;146:2;131:18;184431:37:0;;;;;;;;186096:50;;;;;;;;;;-1:-1:-1;186096:50:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;550:25:1;;;538:2;523:18;186096:50:0;404:177:1;185280:47:0;;;;;;;;;;;;;;;;185096:40;;;;;;;;;;-1:-1:-1;185096:40:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1143:14:1;;1136:22;1118:41;;1106:2;1091:18;185096:40:0;978:187:1;185854:58:0;;;;;;;;;;-1:-1:-1;185854:58:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;210514:158::-;;;;;;;;;;-1:-1:-1;210514:158:0;;;;;:::i;:::-;;:::i;:::-;;197819:1357;;;;;;;;;;-1:-1:-1;197819:1357:0;;;;;:::i;:::-;;:::i;188509:165::-;;;;;;;;;;-1:-1:-1;188509:165:0;;;;;:::i;:::-;188643:23;;-1:-1:-1;188628:38:0;;188509:165;185365:47;;;;;;;;;;;;;;;;220788:264;;;;;;;;;;-1:-1:-1;220788:264:0;;;;;:::i;:::-;;:::i;209973:146::-;;;;;;;;;;-1:-1:-1;209973:146:0;;;;;:::i;:::-;;:::i;211435:279::-;;;;;;;;;;-1:-1:-1;211435:279:0;;;;;:::i;:::-;;:::i;220635:145::-;;;;;;;;;;-1:-1:-1;220635:145:0;;;;;:::i;:::-;220696:4;220720:32;;;:20;:32;;;;;:48;;;:52;;;220635:145;204630:687;;;;;;;;;;-1:-1:-1;204630:687:0;;;;;:::i;:::-;;:::i;188711:171::-;;;;;;;;;;-1:-1:-1;188711:171:0;;;;;:::i;:::-;188805:7;188832:32;;;:20;:32;;;;;:42;;188711:171;185950:63;;;;;;;;;;-1:-1:-1;185950:63:0;;;;;:::i;:::-;;;;;;;;;;;;;;184911:23;;;;;;;;;;-1:-1:-1;184911:23:0;;;;;;;;;;;4045:42:1;4033:55;;;4015:74;;4003:2;3988:18;184911:23:0;3869:226:1;203395:373:0;;;;;;;;;;-1:-1:-1;203395:373:0;;;;;:::i;:::-;;:::i;189034:238::-;;;:::i;184827:27::-;;;;;;;;;;-1:-1:-1;184827:27:0;;;;;;;;185421:34;;;;;;;;;;;;;;;;189326:1723;;;;;;;;;;-1:-1:-1;189326:1723:0;;;;;:::i;:::-;;:::i;208831:110::-;;;;;;;;;;-1:-1:-1;208831:110:0;;;;;:::i;:::-;;:::i;191086:6542::-;;;;;;:::i;:::-;;:::i;200562:1815::-;;;;;;;;;;-1:-1:-1;200562:1815:0;;;;;:::i;:::-;;:::i;22475:86::-;;;;;;;;;;-1:-1:-1;22546:7:0;;;;22475:86;;209612:245;;;;;;;;;;-1:-1:-1;209612:245:0;;;;;:::i;:::-;;:::i;210800:163::-;;;;;;;;;;-1:-1:-1;210800:163:0;;;;;:::i;:::-;;:::i;184995:43::-;;;;;;;;;;-1:-1:-1;184995:43:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;19583:103;;;;;;;;;;;;;:::i;208596:144::-;;;;;;;;;;-1:-1:-1;208596:144:0;;;;;:::i;:::-;;:::i;187699:674::-;;;;;;;;;;-1:-1:-1;187699:674:0;;;;;:::i;:::-;;:::i;209330:155::-;;;;;;;;;;-1:-1:-1;209330:155:0;;;;;:::i;:::-;;:::i;199251:1246::-;;;;;;:::i;:::-;;:::i;18942:87::-;;;;;;;;;;-1:-1:-1;19015:6:0;;;;18942:87;;186680:52;;;;;;;;;;-1:-1:-1;186680:52:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6880:18:1;6868:31;;;6850:50;;6948:42;6936:55;;;6931:2;6916:18;;6909:83;7008:18;;;7001:34;;;;7066:2;7051:18;;7044:34;7122:14;7115:22;7109:3;7094:19;;7087:51;6837:3;6822:19;186680:52:0;6599:545:1;184546:47:0;;;;;;;;;;;;;;;211093:209;;;;;;;;;;-1:-1:-1;211093:209:0;;;;;:::i;:::-;;:::i;185198:44::-;;;;;;;;;;-1:-1:-1;185198:44:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;204026:596;;;;;;;;;;;;;:::i;210243:151::-;;;;;;;;;;-1:-1:-1;210243:151:0;;;;;:::i;:::-;;:::i;211810:160::-;;;;;;;;;;-1:-1:-1;211810:160:0;;;;;:::i;:::-;;:::i;220419:208::-;;;;;;;;;;-1:-1:-1;220419:208:0;;;;;:::i;:::-;;:::i;186446:26::-;;;;;;;;;;;;;;;;205325:3072;;;;;;;;;;-1:-1:-1;205325:3072:0;;;;;:::i;:::-;;:::i;209060:151::-;;;;;;;;;;-1:-1:-1;209060:151:0;;;;;:::i;:::-;;:::i;186346:27::-;;;;;;;;;;;;;;;;184740:30;;;;;;;;;;;;;;;;19841:201;;;;;;;;;;-1:-1:-1;19841:201:0;;;;;:::i;:::-;;:::i;186211:42::-;;;;;;;;;;;;;;;;186535:43;;;;;;;;;;-1:-1:-1;186535:43:0;;;;;:::i;:::-;;;;;;;;;;;;;;185854:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;210514:158::-;18828:13;:11;:13::i;:::-;210585:22:::1;::::0;::::1;;::::0;;;:12:::1;:22;::::0;;;;;;;;:29;;-1:-1:-1;;210585:29:0::1;210610:4;210585:29:::0;;::::1;::::0;;;210632:32;;1118:41:1;;;210632:32:0::1;::::0;1091:18:1;210632:32:0::1;;;;;;;;210514:158:::0;:::o;197819:1357::-;18828:13;:11;:13::i;:::-;197957:1:::1;197948:6;:10;197940:44;;;::::0;-1:-1:-1;;;197940:44:0;;8331:2:1;197940:44:0::1;::::0;::::1;8313:21:1::0;8370:2;8350:18;;;8343:30;8409:23;8389:18;;;8382:51;8450:18;;197940:44:0::1;;;;;;;;;197998:14;198014:18:::0;198036:30:::1;198053:12;;198036:16;:30::i;:::-;197997:69;;;;198108:19;198130:37;198160:6;147092:1:::0;147078:16;147072:23;147067:3;147063:33;;146931:183;198130:37:::1;198200:33;::::0;;;:20:::1;:33;::::0;;;;:43;198108:59;;-1:-1:-1;198200:57:0;::::1;198178:127;;;::::0;-1:-1:-1;;;198178:127:0;;8681:2:1;198178:127:0::1;::::0;::::1;8663:21:1::0;8720:2;8700:18;;;8693:30;8759:22;8739:18;;;8732:50;8799:18;;198178:127:0::1;8479:344:1::0;198178:127:0::1;198488:1;198424:20;198488:1:::0;198445:20:::1;198459:6:::0;198445:11;:20:::1;:::i;:::-;198424:42;;;;;;;;;;;:52;;;:66;198402:152;;;::::0;-1:-1:-1;;;198402:152:0;;9349:2:1;198402:152:0::1;::::0;::::1;9331:21:1::0;9388:2;9368:18;;;9361:30;9427:34;9407:18;;;9400:62;9498:6;9478:18;;;9471:34;9522:19;;198402:152:0::1;9147:400:1::0;198402:152:0::1;198634:23;;198620:11;:37;198598:120;;;::::0;-1:-1:-1;;;198598:120:0;;9754:2:1;198598:120:0::1;::::0;::::1;9736:21:1::0;9793:2;9773:18;;;9766:30;9832:34;9812:18;;;9805:62;9903:3;9883:18;;;9876:31;9924:19;;198598:120:0::1;9552:397:1::0;198598:120:0::1;198731:390;198738:10:::0;;198731:390:::1;;198819:1;198765:33:::0;;;:20:::1;:33;::::0;;;;;:56;;;198843:36;198868:10;;198786:11;;198843:36:::1;::::0;198819:1;198843:36:::1;198940:1;198925:16;199016:33;::::0;;;:20:::1;:33;::::0;;;;:43;-1:-1:-1;;198960:11:0;;;;199016:43;-1:-1:-1;199074:35:0;198731:390:::1;199074:35;198731:390;199131:23;:37:::0;-1:-1:-1;;;;;197819:1357:0:o;220788:264::-;220986:27;;220881:4;220918:32;;;:20;:32;;;;;:48;;;220881:4;;221029:15;;220918:95;;220986:27;220918:95;:::i;:::-;:126;;220788:264;-1:-1:-1;;220788:264:0:o;209973:146::-;18828:13;:11;:13::i;:::-;210040:18:::1;::::0;::::1;;::::0;;;:8:::1;:18;::::0;;;;;;;;:25;;-1:-1:-1;;210040:25:0::1;210061:4;210040:25:::0;;::::1;::::0;;;210083:28;;1118:41:1;;;210083:28:0::1;::::0;1091:18:1;210083:28:0::1;978:187:1::0;211435:279:0;18828:13;:11;:13::i;:::-;211568:15:::1;::::0;;211594:34;;;;211646:60:::1;::::0;;10128:25:1;;;10184:2;10169:18;;10162:34;;;211646:60:0::1;::::0;10101:18:1;211646:60:0::1;;;;;;;211527:187;211435:279:::0;:::o;204630:687::-;22080:19;:17;:19::i;:::-;204718:1:::1;204712:3;:7;204704:53;;;::::0;-1:-1:-1;;;204704:53:0;;10409:2:1;204704:53:0::1;::::0;::::1;10391:21:1::0;10448:2;10428:18;;;10421:30;10487:34;10467:18;;;10460:62;10558:3;10538:18;;;10531:31;10579:19;;204704:53:0::1;10207:397:1::0;204704:53:0::1;204807:23;::::0;204768:36:::1;204872:32;204807:23:::0;204903:1:::1;204872:32;:::i;:::-;204860:44;;204841:469;204924:34;204955:3:::0;204924:28;:34:::1;:::i;:::-;204919:1;:39;204841:469;;205148:29;205175:1;205148:26;:29::i;:::-;:64;;;-1:-1:-1::0;220696:4:0;220720:32;;;:20;:32;;;;;:48;;;:52;205148:64:::1;205247:5;205003:265;205282:16;205296:1;205282:13;:16::i;:::-;204973:3:::0;::::1;::::0;::::1;:::i;:::-;;;;204841:469;;;;204693:624;204630:687:::0;:::o;203395:373::-;17243:10;187151:25;;;;:11;:25;;;;;;;;187143:58;;;;-1:-1:-1;;;187143:58:0;;11011:2:1;187143:58:0;;;10993:21:1;11050:2;11030:18;;;11023:30;11089:22;11069:18;;;11062:50;11129:18;;187143:58:0;10809:344:1;187143:58:0;17243:10;203461:17:::1;203522:19:::0;;;:8:::1;:19;::::0;;;;;203560:10;203552:57:::1;;;::::0;-1:-1:-1;;;203552:57:0;;11360:2:1;203552:57:0::1;::::0;::::1;11342:21:1::0;11399:2;11379:18;;;11372:30;11438:34;11418:18;;;11411:62;11509:4;11489:18;;;11482:32;11531:19;;203552:57:0::1;11158:398:1::0;203552:57:0::1;203651:5;203637:11;;203628:6;:20;;;;:::i;:::-;:28;203620:59;;;::::0;-1:-1:-1;;;203620:59:0;;11763:2:1;203620:59:0::1;::::0;::::1;11745:21:1::0;11802:2;11782:18;;;11775:30;11841:20;11821:18;;;11814:48;11879:18;;203620:59:0::1;11561:342:1::0;203620:59:0::1;203692:19;::::0;::::1;;::::0;;;:8:::1;:19;::::0;;;;:29;;203715:6;;203692:19;:29:::1;::::0;203715:6;;203692:29:::1;:::i;:::-;::::0;;;-1:-1:-1;203732:28:0::1;::::0;-1:-1:-1;203742:9:0;203753:6;203732:9:::1;:28::i;189034:238::-:0;17243:10;187151:25;;;;:11;:25;;;;;;;;187143:58;;;;-1:-1:-1;;;187143:58:0;;11011:2:1;187143:58:0;;;10993:21:1;11050:2;11030:18;;;11023:30;11089:22;11069:18;;;11062:50;11129:18;;187143:58:0;10809:344:1;187143:58:0;189153:11:::1;::::0;17243:10;189115:22:::1;::::0;;;:8:::1;:22;::::0;;;;;:34:::1;::::0;189140:9:::1;::::0;189115:34:::1;:::i;:::-;:49;;189093:125;;;::::0;-1:-1:-1;;;189093:125:0;;12243:2:1;189093:125:0::1;::::0;::::1;12225:21:1::0;12282:2;12262:18;;;12255:30;12321:28;12301:18;;;12294:56;12367:18;;189093:125:0::1;12041:350:1::0;189093:125:0::1;17243:10:::0;189229:22:::1;::::0;;;:8:::1;:22;::::0;;;;:35;;189255:9:::1;::::0;189229:22;:35:::1;::::0;189255:9;;189229:35:::1;:::i;:::-;::::0;;;-1:-1:-1;;189034:238:0:o;189326:1723::-;189540:14;189532:56;;;;-1:-1:-1;;;189532:56:0;;12598:2:1;189532:56:0;;;12580:21:1;12637:2;12617:18;;;12610:30;12676:17;12656:18;;;12649:45;12711:18;;189532:56:0;12396:339:1;189532:56:0;189699:1;189665:22;;:19;:22;;;;:36;189657:71;;;;-1:-1:-1;;;189657:71:0;;12942:2:1;189657:71:0;;;12924:21:1;12981:2;12961:18;;;12954:30;13020:24;13000:18;;;12993:52;13062:18;;189657:71:0;12740:346:1;189657:71:0;189742:14;189758:18;189780:30;189797:12;;189780:16;:30::i;:::-;189741:69;;;;189821:17;189841:35;189869:6;148357:2;148343:17;148337:24;;148211:168;189841:35;189821:55;;189990:11;190177:47;190217:6;147982:2;147968:17;147962:24;147957:3;147953:34;;147791:214;190177:47;147513:1;147499:16;;147493:23;147488:3;147484:33;147092:1;147078:16;;147072:23;147067:3;147063:33;146699:15;;146694:3;146690:25;190004:91;:153;:220;;-1:-1:-1;190247:8:0;;190239:44;;;;-1:-1:-1;;;190239:44:0;;13293:2:1;190239:44:0;;;13275:21:1;13332:2;13312:18;;;13305:30;13371:25;13351:18;;;13344:53;13414:18;;190239:44:0;13091:347:1;190239:44:0;-1:-1:-1;190374:1:0;190327:35;190355:6;148357:2;148343:17;148337:24;;148211:168;190327:35;:49;190305:113;;;;-1:-1:-1;;;190305:113:0;;13645:2:1;190305:113:0;;;13627:21:1;13684:2;13664:18;;;13657:30;13723:16;13703:18;;;13696:44;13757:18;;190305:113:0;13443:338:1;190305:113:0;190505:1;190451:42;190486:6;148775:2;148761:17;148755:24;;148608:189;190451:42;:56;190429:131;;;;-1:-1:-1;;;190429:131:0;;13988:2:1;190429:131:0;;;13970:21:1;14027:2;14007:18;;;14000:30;14066:27;14046:18;;;14039:55;14111:18;;190429:131:0;13786:349:1;190429:131:0;190599:276;;;;;;;;190624:10;190599:276;;;;190649:15;190599:276;;;;190687:1;190679:10;;190599:276;;;;190704:14;190599:276;;;;190733:15;190599:276;;;;190763:9;190599:276;;;;190787:12;17243:10;;17163:98;190787:12;190599:276;;;;;;190814:1;190599:276;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;190573:23;;;:20;:23;;;:302;;:23;:302;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;190573:302:0;;;;;;;;;;;190886:22;;;;:19;:22;;;:39;;;:22;190943:26;190958:10;;190886:22;190943:26;;190886:22;;190943:26;190985:56;;;10128:25:1;;;190999:1:0;10184:2:1;10169:18;;10162:34;;;191002:10:0;;190999:1;;190985:56;;10101:18:1;190985:56:0;;;;;;;189475:1574;;;189326:1723;;;;:::o;208831:110::-;18828:13;:11;:13::i;:::-;208908:12:::1;:25:::0;208831:110::o;191086:6542::-;17243:10;187151:25;;;;:11;:25;;;;;;;;187143:58;;;;-1:-1:-1;;;187143:58:0;;11011:2:1;187143:58:0;;;10993:21:1;11050:2;11030:18;;;11023:30;11089:22;11069:18;;;11062:50;11129:18;;187143:58:0;10809:344:1;187143:58:0;22080:19:::1;:17;:19::i;:::-;191295:11:::2;::::0;17243:10;191269:22:::2;::::0;;;:8:::2;:22;::::0;;;;;:37:::2;;191247:114;;;::::0;-1:-1:-1;;;191247:114:0;;17161:2:1;191247:114:0::2;::::0;::::2;17143:21:1::0;17200:2;17180:18;;;17173:30;17239:29;17219:18;;;17212:57;17286:18;;191247:114:0::2;16959:351:1::0;191247:114:0::2;191380:17;;::::0;::::2;:9:::0;:17:::2;:::i;:::-;:22;;::::0;191372:50:::2;;;::::0;-1:-1:-1;;;191372:50:0;;17791:2:1;191372:50:0::2;::::0;::::2;17773:21:1::0;17830:2;17810:18;;;17803:30;17869:17;17849:18;;;17842:45;17904:18;;191372:50:0::2;17589:339:1::0;191372:50:0::2;191480:21;191504:16;;::::0;::::2;:9:::0;:16:::2;:::i;:::-;:23:::0;-1:-1:-1;;191546:17:0;191538:44:::2;;;::::0;-1:-1:-1;;;191538:44:0;;18755:2:1;191538:44:0::2;::::0;::::2;18737:21:1::0;18794:2;18774:18;;;18767:30;18833:16;18813:18;;;18806:44;18867:18;;191538:44:0::2;18553:338:1::0;191538:44:0::2;191617:23;::::0;::::2;;191595:114;;;::::0;-1:-1:-1;;;191595:114:0;;19098:2:1;191595:114:0::2;::::0;::::2;19080:21:1::0;19137:2;19117:18;;;19110:30;19176:29;19156:18;;;19149:57;19223:18;;191595:114:0::2;18896:351:1::0;191595:114:0::2;191742:23;::::0;::::2;;191720:109;;;::::0;-1:-1:-1;;;191720:109:0;;19454:2:1;191720:109:0::2;::::0;::::2;19436:21:1::0;19493:2;19473:18;;;19466:30;19532:24;19512:18;;;19505:52;19574:18;;191720:109:0::2;19252:346:1::0;191720:109:0::2;192891:16;::::0;192937:69:::2;192968:27;;::::0;::::2;:9:::0;:27:::2;:::i;:::-;192937:16;:69::i;:::-;192890:116;;;;193019:19;193041:39;193071:8;147092:1:::0;147078:16;147072:23;147067:3;147063:33;;146931:183;193041:39:::2;193019:61;;193091:37;193131:63;193185:8;147982:2:::0;147968:17;147962:24;147957:3;147953:34;;147791:214;193131:63:::2;193229:33;::::0;;;:20:::2;:33;::::0;;;;:43;193091:103;;-1:-1:-1;193229:63:0;::::2;193207:140;;;::::0;-1:-1:-1;;;193207:140:0;;20390:2:1;193207:140:0::2;::::0;::::2;20372:21:1::0;20429:2;20409:18;;;20402:30;20468:29;20448:18;;;20441:57;20515:18;;193207:140:0::2;20188:351:1::0;193207:140:0::2;193441:1;193382:20;193441:1:::0;193403:15:::2;:11:::0;193417:1:::2;193403:15;:::i;:::-;193382:37;;;;;;;;;;;:47;;;:61;193360:134;;;::::0;-1:-1:-1;;;193360:134:0;;20746:2:1;193360:134:0::2;::::0;::::2;20728:21:1::0;20785:2;20765:18;;;20758:30;20824:25;20804:18;;;20797:53;20867:18;;193360:134:0::2;20544:347:1::0;193360:134:0::2;193544:23;;193529:11;:38;193507:109;;;::::0;-1:-1:-1;;;193507:109:0;;21098:2:1;193507:109:0::2;::::0;::::2;21080:21:1::0;21137:2;21117:18;;;21110:30;21176:23;21156:18;;;21149:51;21217:18;;193507:109:0::2;20896:345:1::0;193507:109:0::2;193651:33;::::0;;;:20:::2;:33;::::0;;;;:47:::2;;::::0;193719:23:::2;::::0;::::2;;193651:91;193629:170;;;::::0;-1:-1:-1;;;193629:170:0;;21448:2:1;193629:170:0::2;::::0;::::2;21430:21:1::0;21487:2;21467:18;;;21460:30;21526:31;21506:18;;;21499:59;21575:18;;193629:170:0::2;21246:353:1::0;193629:170:0::2;193958:4;193952:11:::0;;194022:2:::2;194003:22:::0;::::2;193990:36:::0;::::2;193977:50:::0;;;193891:15:::2;::::0;194147:696:::2;194171:13;194167:1;:17;194147:696;;;194206:34;194243:238;194274:7:::0;194300:16:::2;;::::0;::::2;:9:::0;:16:::2;:::i;:::-;194317:1;194300:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;194243:238;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;194338:29;194386;194434:9;:32;;;;;;;;:::i;:::-;194243:12;:238::i;:::-;194206:275:::0;-1:-1:-1;194507:17:0::2;194523:1;194507:13:::0;:17:::2;:::i;:::-;194502:1;:22:::0;194498:106:::2;;194545:43;194568:16;;::::0;::::2;:9:::0;:16:::2;:::i;:::-;194585:1;194568:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;194545:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;194545:22:0::2;::::0;-1:-1:-1;;;194545:43:0:i:2;:::-;194725:59:::0;;::::2;::::0;194814:2:::2;194803:13:::0;;;::::2;::::0;194647:59;;;::::2;::::0;194186:3;::::2;::::0;::::2;:::i;:::-;;;;194147:696;;;-1:-1:-1::0;195020:32:0::2;;::::0;::::2;:9:::0;:32:::2;:::i;:::-;:39:::0;-1:-1:-1;194986:3:0::2;194979;194947:35:::0;::::2;194946:43;194993:2;194945:50;:114;194919:195;;;::::0;-1:-1:-1;;;194919:195:0;;22184:2:1;194919:195:0::2;::::0;::::2;22166:21:1::0;22223:2;22203:18;;;22196:30;22262:21;22242:18;;;22235:49;22301:18;;194919:195:0::2;21982:343:1::0;194919:195:0::2;195276:4;195257:24:::0;;::::2;195318:21:::0;;::::2;195308:41:::0;195383:4:::2;195377:11:::0;;-1:-1:-1;195452:1:0::2;195435:19:::0;;;::::2;::::0;195308:41;195546:60:::2;::::0;195377:11;;195588:17:::2;::::0;;::::2;:9:::0;:17:::2;:::i;:::-;195546:60;;:31;:60::i;:::-;150170:3:::0;150166:21;;;150162:1;150148:16;;150141:47;150772:26;;;150768:1;150754:16;;150747:52;151385:31;;;151380:2;151366:17;;151359:58;151748:2;151734:17;;151727:36;;;152131:2;152117:17;;152110:43;;;196088:118:::2;150148:16:::0;196163:32:::2;;::::0;::::2;::::0;::::2;:::i;:::-;196088:37;:118::i;:::-;196250:18;196271:128;196321:8:::0;196349:32:::2;;::::0;::::2;:9:::0;:32:::2;:::i;:::-;196344:44;::::0;-1:-1:-1;196344:2:0::2;:44;:::i;:::-;153210:27:::0;;;152971:284;196271:128:::2;196250:149;;196448:411;;;;;;;;196473:10;196448:411;;;;196498:15;196448:411;;;;196528:9;:23;;;196448:411;;;;196566:9;:23;;;196448:411;;;;196604:9;:24;;;196448:411;;;;196643:9;196448:411;;;;196667:12;17243:10:::0;;17163:98;196667:12:::2;196448:411;;;;;;196694:29;196448:411;;;;196738:29;196448:411;;;;196782:9;:32;;;;;;;;:::i;:::-;196448:411;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;-1:-1:-1;196448:411:0;;;-1:-1:-1;;196829:19:0::2;::::0;196448:411:::2;::::0;;::::2;::::0;-1:-1:-1;196412:33:0;;;:20:::2;:33:::0;;;;;;;;:447;;;;;;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;;::::0;;::::2;::::0;;;::::2;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;:::i;:::-;-1:-1:-1::0;196412:447:0::2;::::0;;;::::2;::::0;::::2;::::0;;::::2;::::0;196892:24:::2;::::0;::::2;;196876:41;::::0;;;:15:::2;:41;::::0;;;;;:46;;196872:134:::2;;196955:24;::::0;::::2;;196939:41;::::0;;;:15:::2;:41;::::0;;;;:55;;;196872:134:::2;197018:23;:37:::0;;;197071:36:::2;::::0;197096:10;;197044:11;;197071:36:::2;::::0;;;::::2;191236:6392;;;;;;;;;191086:6542:::0;;:::o;200562:1815::-;200731:23;;;200777:1;200731:23;;;:10;:23;;;;;:34;;;;:48;:34;200709:117;;;;-1:-1:-1;;;200709:117:0;;22532:2:1;200709:117:0;;;22514:21:1;22571:2;22551:18;;;22544:30;22610:21;22590:18;;;22583:49;22649:18;;200709:117:0;22330:343:1;200709:117:0;200860:23;;;;;;;:10;:23;;;;;:32;;;;;200859:33;200837:109;;;;-1:-1:-1;;;200837:109:0;;22880:2:1;200837:109:0;;;22862:21:1;22919:2;22899:18;;;22892:30;22958:28;22938:18;;;22931:56;23004:18;;200837:109:0;22678:350:1;200837:109:0;201035:12;;200986:23;;;200957:26;200986:23;;;:10;:23;;;;;:33;;;200957:26;;201063:15;;200986:61;;201035:12;200986:61;:::i;:::-;:92;200957:121;;201094:21;201089:1231;;201195:33;;;;;;;:20;:33;;;;;;;;;:43;;;201132:149;;;;;;;;;;;;;;;;;;;;;201165:11;;201195:43;;;201132:14;:149::i;:::-;201089:1231;;;201426:21;201418:47;;;;-1:-1:-1;;;201418:47:0;;23235:2:1;201418:47:0;;;23217:21:1;23274:2;23254:18;;;23247:30;23313:15;23293:18;;;23286:43;23346:18;;201418:47:0;23033:337:1;201418:47:0;201652:33;;;201522:24;201652:33;;;:20;:33;;;;;;;;:47;;;;201722;;;;201792:48;;;;201863:42;;;;;201577:347;;23648:66:1;201616:13:0;23634:3:1;23630:16;23626:89;201577:347:0;;;23614:102:1;;;;23732:11;;;23725:27;;;;23768:12;;;23761:28;23805:12;;;23798:28;23842:13;;;23835:29;23880:13;;201577:347:0;;;;;;;;;;;;;;201549:390;;201577:347;201549:390;;;;202001:8;;201985:155;;;201549:390;;-1:-1:-1;202001:8:0;;;201985:46;;:155;;202050:11;;202080:10;;;;201549:390;;201985:155;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;202155:153;202186:11;202216:20;:33;202237:11;202216:33;;;;;;;;;;;;;:43;;;;;;;;;;;;202155:153;;;;;;;;;;;;;;;;;:12;:153::i;:::-;201375:945;201089:1231;-1:-1:-1;;;202330:23:0;;;;;;:10;:23;;;;;:32;;:39;;-1:-1:-1;;202330:39:0;202365:4;202330:39;;;200562:1815::o;209612:245::-;18828:13;:11;:13::i;:::-;209685:21:::1;::::0;::::1;209709:5;209685:21:::0;;;:11:::1;:21;::::0;;;;;;;:29;;-1:-1:-1;;209685:29:0::1;::::0;;209725:8:::1;:18:::0;;;;;:22;;;209760:39:::1;::::0;209697:8;;209760:9:::1;:39::i;:::-;209817:32;::::0;209843:5:::1;1118:41:1::0;;209817:32:0::1;::::0;::::1;::::0;::::1;::::0;1106:2:1;1091:18;209817:32:0::1;978:187:1::0;210800:163:0;18828:13;:11;:13::i;:::-;210874:22:::1;::::0;::::1;210899:5;210874:22:::0;;;:12:::1;:22;::::0;;;;;;;:30;;-1:-1:-1;;210874:30:0::1;::::0;;210922:33;1118:41:1;;;210922:33:0::1;::::0;1091:18:1;210922:33:0::1;978:187:1::0;19583:103:0;18828:13;:11;:13::i;:::-;19648:30:::1;19675:1;19648:18;:30::i;:::-;19583:103::o:0;208596:144::-;18828:13;:11;:13::i;:::-;208701:11:::1;:31:::0;208596:144::o;187699:674::-;13005:19;13028:13;;;;;;13027:14;;13075:34;;;;-1:-1:-1;13093:12:0;;13108:1;13093:12;;;;:16;13075:34;13074:108;;;-1:-1:-1;13154:4:0;1969:19;:23;;;13115:66;;-1:-1:-1;13164:12:0;;;;;:17;13115:66;13052:204;;;;-1:-1:-1;;;13052:204:0;;24727:2:1;13052:204:0;;;24709:21:1;24766:2;24746:18;;;24739:30;24805:34;24785:18;;;24778:62;24876:16;24856:18;;;24849:44;24910:19;;13052:204:0;24525:410:1;13052:204:0;13267:12;:16;;-1:-1:-1;;13267:16:0;13282:1;13267:16;;;13294:67;;;;13329:13;:20;;;;;;;;13294:67;187957:35:::1;:33;:35::i;:::-;188005:12;:28:::0;;::::1;::::0;;::::1;::::0;;;::::1;;::::0;;;188044:8:::1;:20:::0;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;188075:15:::1;:34:::0;;;188122:27:::1;:56:::0;;;188189:12:::1;:27:::0;;;188227:11:::1;:25:::0;;;188270:37:::1;::::0;188005:12:::1;::::0;188270:37:::1;::::0;188005:12;;188270:37:::1;188323:42;::::0;;188345:1:::1;10128:25:1::0;;10184:2;10169:18;;10162:34;;;188323:42:0::1;::::0;10101:18:1;188323:42:0::1;;;;;;;13387:14:::0;13383:102;;;13434:5;13418:21;;;;;;13459:14;;-1:-1:-1;25353:36:1;;13459:14:0;;25341:2:1;25326:18;13459:14:0;;;;;;;13383:102;12994:498;187699:674;;;;;;:::o;209330:155::-;18828:13;:11;:13::i;:::-;209400:21:::1;::::0;::::1;;::::0;;;:11:::1;:21;::::0;;;;;;;;:28;;-1:-1:-1;;209400:28:0::1;209424:4;209400:28:::0;;::::1;::::0;;;209446:31;;1118:41:1;;;209446:31:0::1;::::0;1091:18:1;209446:31:0::1;978:187:1::0;199251:1246:0;17243:10;187387:26;;;;:12;:26;;;;;;;;187379:60;;;;-1:-1:-1;;;187379:60:0;;25602:2:1;187379:60:0;;;25584:21:1;25641:2;25621:18;;;25614:30;25680:23;25660:18;;;25653:51;25721:18;;187379:60:0;25400:345:1;187379:60:0;199385:10:::1;199359:36;;:23;;:36;199337:109;;;::::0;-1:-1:-1;;;199337:109:0;;25952:2:1;199337:109:0::1;::::0;::::1;25934:21:1::0;25991:2;25971:18;;;25964:30;26030:25;26010:18;;;26003:53;26073:18;;199337:109:0::1;25750:347:1::0;199337:109:0::1;199481:32;::::0;::::1;;::::0;;;:20:::1;:32;::::0;;;;:42;:47;;199459:112:::1;;;::::0;-1:-1:-1;;;199459:112:0;;26304:2:1;199459:112:0::1;::::0;::::1;26286:21:1::0;26343:2;26323:18;;;26316:30;26382:17;26362:18;;;26355:45;26417:18;;199459:112:0::1;26102:339:1::0;199459:112:0::1;199606:22;::::0;::::1;199651:1;199606:22:::0;;;:10:::1;:22;::::0;;;;:33;;;::::1;:47;:33;:47:::0;199584:118:::1;;;::::0;-1:-1:-1;;;199584:118:0;;26648:2:1;199584:118:0::1;::::0;::::1;26630:21:1::0;26687:2;26667:18;;;26660:30;26726:23;26706:18;;;26699:51;26767:18;;199584:118:0::1;26446:345:1::0;199584:118:0::1;199917:27;::::0;199839:32:::1;::::0;::::1;199810:26;199839:32:::0;;;:20:::1;:32;::::0;;;;:62:::1;;::::0;199810:26;;199960:15:::1;::::0;199839:105:::1;::::0;199917:27;199839:105:::1;:::i;:::-;:136;199810:165;;200008:21;199986:122;;;::::0;-1:-1:-1;;;199986:122:0;;26998:2:1;199986:122:0::1;::::0;::::1;26980:21:1::0;27037:2;27017:18;;;27010:30;27076:34;27056:18;;;27049:62;27147:21;27127:18;;;27120:49;27186:19;;199986:122:0::1;26796:415:1::0;199986:122:0::1;200177:11;;200164:9;:24;;200156:33;;;::::0;::::1;;17243:10:::0;200200:22:::1;::::0;;;:8:::1;:22;::::0;;;;:35;;200226:9:::1;::::0;200200:22;:35:::1;::::0;200226:9;;200200:35:::1;:::i;:::-;::::0;;;-1:-1:-1;;200271:151:0::1;::::0;;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;;;17243:10;200271:151:::1;::::0;;::::1;::::0;;;200352:9:::1;200271:151:::0;;;;;;200376:15:::1;200271:151:::0;;;;;;-1:-1:-1;200271:151:0;;;;;;200246:22;;;:10:::1;:22:::0;;;;;;:176;;;;;;200271:151:::1;200246:176;::::0;::::1;::::0;;;;;::::1;::::0;;;;;;;::::1;::::0;;;-1:-1:-1;200246:176:0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;::::1;;-1:-1:-1::0;;200246:176:0;;::::1;::::0;;;::::1;::::0;;;200438:51;;27390:74:1;;;27480:18;;;27473:34;;;;200438:51:0;;200271:151;;200438:51:::1;::::0;;;;;;::::1;199326:1171;199251:1246:::0;:::o;211093:209::-;18828:13;:11;:13::i;:::-;211192:8:::1;::::0;;::::1;211211:23:::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;211252:42:::1;::::0;211192:8;::::1;::::0;211211:23;211192:8;;211252:42:::1;::::0;211169:20:::1;::::0;211252:42:::1;211158:144;211093:209:::0;:::o;204026:596::-;22080:19;:17;:19::i;:::-;204123:23:::1;::::0;204084:36:::1;204188:32;204123:23:::0;204219:1:::1;204188:32;:::i;:::-;204176:44;;204157:458;204240:23;;204235:1;:28;204157:458;;204453:29;204480:1;204453:26;:29::i;:::-;:64;;;-1:-1:-1::0;220696:4:0;220720:32;;;:20;:32;;;;;:48;;;:52;204453:64:::1;204552:5;204308:265;204587:16;204601:1;204587:13;:16::i;:::-;204278:3:::0;::::1;::::0;::::1;:::i;:::-;;;;204157:458;;;;204073:549;204026:596::o:0;210243:151::-;18828:13;:11;:13::i;:::-;210313:18:::1;::::0;::::1;210334:5;210313:18:::0;;;:8:::1;:18;::::0;;;;;;;:26;;-1:-1:-1;;210313:26:0::1;::::0;;210357:29;1118:41:1;;;210357:29:0::1;::::0;1091:18:1;210357:29:0::1;978:187:1::0;211810:160:0;18828:13;:11;:13::i;:::-;211876:7:::1;211872:91;;;211900:8;:6;:8::i;:::-;211810:160:::0;:::o;211872:91::-:1;211941:10;:8;:10::i;220419:208::-:0;220486:4;220523:22;;;:10;:22;;;;;:33;;;;:47;:33;:47;;;;:96;;-1:-1:-1;220588:22:0;;;;:10;:22;;;;;:31;;;;;220587:32;220523:96;220503:116;220419:208;-1:-1:-1;;220419:208:0:o;205325:3072::-;22080:19;:17;:19::i;:::-;220696:4;220720:32;;;:20;:32;;;;;:48;;;205401:51:::1;;;::::0;-1:-1:-1;;;205401:51:0;;26304:2:1;205401:51:0::1;::::0;::::1;26286:21:1::0;26343:2;26323:18;;;26316:30;26382:17;26362:18;;;26355:45;26417:18;;205401:51:0::1;26102:339:1::0;205401:51:0::1;205633:39;205660:11;205633:26;:39::i;:::-;205632:40;205610:115;;;::::0;-1:-1:-1;;;205610:115:0;;27720:2:1;205610:115:0::1;::::0;::::1;27702:21:1::0;27759:2;27739:18;;;27732:30;27798:27;27778:18;;;27771:55;27843:18;;205610:115:0::1;27518:349:1::0;205610:115:0::1;205857:33;::::0;;;:20:::1;:33;::::0;;;;:47:::1;;::::0;;205800:19:::1;::::0;205820:15:::1;205834:1;205878:11:::0;205820:15:::1;:::i;:::-;205800:36;;;;;;;;;;;;:104;205778:183;;;::::0;-1:-1:-1;;;205778:183:0;;21448:2:1;205778:183:0::1;::::0;::::1;21430:21:1::0;21487:2;21467:18;;;21460:30;21526:31;21506:18;;;21499:59;21575:18;;205778:183:0::1;21246:353:1::0;205778:183:0::1;206082:1;206038:32:::0;;;:19:::1;:32;::::0;;;;;:46;206016:118:::1;;;::::0;-1:-1:-1;;;206016:118:0;;28074:2:1;206016:118:0::1;::::0;::::1;28056:21:1::0;28113:2;28093:18;;;28086:30;28152:24;28132:18;;;28125:52;28194:18;;206016:118:0::1;27872:346:1::0;206016:118:0::1;206282:11;206251:23;;206277:1;206251:27;:42;206225:125;;;::::0;-1:-1:-1;;;206225:125:0;;21098:2:1;206225:125:0::1;::::0;::::1;21080:21:1::0;21137:2;21117:18;;;21110:30;21176:23;21156:18;;;21149:51;21217:18;;206225:125:0::1;20896:345:1::0;206225:125:0::1;206365:23;:37:::0;;;206511:33:::1;::::0;;;:20:::1;:33;::::0;;;;;;;:61:::1;::::0;::::1;::::0;206476:19:::1;:32:::0;;;;;;:96;206683:33;:63:::1;;::::0;206761:20;;206757:1382:::1;;206839:12;::::0;206798:22:::1;206908:65:::0;;;:20:::1;:65;::::0;;;;:88:::1;;206869:127:::0;;206839:12:::1;::::0;;::::1;::::0;206869:127:::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;207013:17:0::1;207283:33:::0;;;:20:::1;207180:2;207283:33:::0;;;;;;:76:::1;;::::0;206869:127;;-1:-1:-1;207086:115:0;::::1;::::0;207283:95;;::::1;::::0;-1:-1:-1;207013:17:0;-1:-1:-1;207399:714:0::1;207423:16;207419:1;:20;207399:714;;;207491:3;207521:20:::0;;::::1;:29:::0;-1:-1:-1;207517:115:0::1;;;-1:-1:-1::0;207588:20:0;;::::1;207517:115;207722:3;207718:7:::0;::::1;207835:2;207823:15:::0;::::1;207808:31:::0;::::1;207802:38:::0;207887:163:::1;::::0;;;;::::1;::::0;::::1;28425:25:1::0;;;28466:18;;;28459:34;;;28509:18;;;28502:34;;;207802:38:0;;207718:7;207887:28:::1;::::0;::::1;::::0;::::1;::::0;28398:18:1;;207887:163:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;208090:3;208075:18;;;;207451:662;;;207446:3;207441:8;;;;207399:714;;;;207232:896;206783:1356;;;206757:1382;208210:33;::::0;;;:20:::1;:33;::::0;;;;;;:43;;208268:47:::1;::::0;::::1;::::0;208330:48:::1;::::0;;::::1;::::0;208156:233;;208210:43;;208231:11;;208156:233:::1;::::0;::::1;::::0;208330:48;10128:25:1;;;10184:2;10169:18;;10162:34;10116:2;10101:18;;9954:248;208156:233:0::1;;;;;;;;205390:3007;205325:3072:::0;:::o;209060:151::-;18828:13;:11;:13::i;:::-;209163:27:::1;:40:::0;209060:151::o;19841:201::-;18828:13;:11;:13::i;:::-;19930:22:::1;::::0;::::1;19922:73;;;::::0;-1:-1:-1;;;19922:73:0;;28749:2:1;19922:73:0::1;::::0;::::1;28731:21:1::0;28788:2;28768:18;;;28761:30;28827:34;28807:18;;;28800:62;28898:8;28878:18;;;28871:36;28924:19;;19922:73:0::1;28547:402:1::0;19922:73:0::1;20006:28;20025:8;20006:18;:28::i;19107:132::-:0;19015:6;;19171:23;19015:6;17243:10;19171:23;19163:68;;;;-1:-1:-1;;;19163:68:0;;29156:2:1;19163:68:0;;;29138:21:1;;;29175:18;;;29168:30;29234:34;29214:18;;;29207:62;29286:18;;19163:68:0;28954:356:1;212342:379:0;212436:14;212452:18;212510:15;212556:48;212591:12;;212556:34;:48::i;:::-;153210:27;;;;;;-1:-1:-1;212342:379:0;-1:-1:-1;;;;212342:379:0:o;22634:108::-;22546:7;;;;22704:9;22696:38;;;;-1:-1:-1;;;22696:38:0;;29517:2:1;22696:38:0;;;29499:21:1;29556:2;29536:18;;;29529:30;29595:18;29575;;;29568:46;29631:18;;22696:38:0;29315:340:1;203776:242:0;203849:11;;203845:166;;203877:12;203892:45;203906:3;203911:9;203922:7;203892:45;;;;;;;;;;;;:13;:45::i;:::-;203877:60;;203960:7;203952:47;;;;-1:-1:-1;;;203952:47:0;;29862:2:1;203952:47:0;;;29844:21:1;29901:2;29881:18;;;29874:30;29940:29;29920:18;;;29913:57;29987:18;;203952:47:0;29660:351:1;213945:4043:0;214398:4;214392:11;214675:13;;214197:34;;214478:4;214466:17;;;214392:11;;214529:16;;;;214197:34;;214607:92;;214466:17;;214607:30;:92::i;:::-;214586:113;-1:-1:-1;214801:33:0;;214849:453;214873:10;214869:1;:14;214849:453;;;157138:20;157134:32;;157113:55;;157131:1;157113:55;;157197:15;157182:31;;157338:19;;157332:26;157381:66;157306:160;157352:4;157270:17;;157245:236;157536:2;157524:15;;214909:59;;214987:31;215021:76;215070:8;158012:2;157998:17;157992:24;157987:3;157983:34;;157820:215;215021:76;154800:2;215224:43;;;;;215149:52;;;;;-1:-1:-1;214885:3:0;;;;:::i;:::-;;;;214849:453;;;-1:-1:-1;215401:4:0;215370:36;215357:50;;215351:4;215344:64;215686:1;215672:16;;;-1:-1:-1;215361:7:0;215556:26;215782:40;215676:8;215811:10;154800:2;156081:33;156066:48;156077:1;156066:48;;155898:235;215782:40;215764:58;;215833:1522;215840:14;;215833:1522;;215917:29;215949:34;215974:8;158454:2;158440:17;158434:24;158429:3;158425:34;;158268:209;215949:34;215917:66;;216008:239;216047:7;216073:21;216113:29;216161;216209:23;;216008:20;:239::i;:::-;215998:249;;216314:31;216348:68;216393:8;158012:2;157998:17;157992:24;157987:3;157983:34;;157820:215;216348:68;216314:102;;216484:21;216457:23;:48;;216431:139;;;;-1:-1:-1;;;216431:139:0;;30218:2:1;216431:139:0;;;30200:21:1;30257:2;30237:18;;;30230:30;30296:31;30276:18;;;30269:59;30345:18;;216431:139:0;30016:353:1;216431:139:0;216620:21;216585:403;216664:23;216660:1;:27;216585:403;;;159418:15;;159413:3;159409:25;159474:1;159460:16;;;159500:36;;;216880:23;;216949:4;216936:18;;;;159562:30;;;;;;216706:3;;;;:::i;:::-;;;;216585:403;;;-1:-1:-1;;217103:54:0;;;;217176;;;;217033:51;;;;;154800:2;217285:43;;;;;-1:-1:-1;;217251:15:0;;;;215833:1522;;;217493:15;;217487:2;217455:28;217465:18;217455:7;:28;:::i;:::-;217454:35;;;;:::i;:::-;:54;;217432:129;;;;-1:-1:-1;;;217432:129:0;;30855:2:1;217432:129:0;;;30837:21:1;30894:2;30874:18;;;30867:30;30933:27;30913:18;;;30906:55;30978:18;;217432:129:0;30653:349:1;217432:129:0;217661:13;;217639:18;217649:8;217639:7;:18;:::i;:::-;:35;217617:115;;;;-1:-1:-1;;;217617:115:0;;31209:2:1;217617:115:0;;;31191:21:1;31248:2;31228:18;;;31221:30;31287:32;31267:18;;;31260:60;31337:18;;217617:115:0;31007:354:1;217617:115:0;-1:-1:-1;;;;217859:26:0;;;217835:51;;217900:24;;-1:-1:-1;213945:4043:0;;;;;;;;;:::o;212729:598::-;213061:13;;212935:16;;;;212904:4;212892:17;;;212802:16;;212993:92;;212892:17;;212993:30;:92::i;:::-;212972:113;;213101:9;213096:159;213120:14;213133:1;213120:10;:14;:::i;:::-;213116:1;:18;213096:159;;;154800:2;213185:43;;;;213136:3;;;;;:::i;:::-;;;;213096:159;;;-1:-1:-1;;158852:15:0;;158847:3;158843:25;213265:19;:54;-1:-1:-1;;212729:598:0:o;149506:152::-;149631:8;149621;149613:27;149506:152;;:::o;152400:248::-;152599:30;152567;152562:2;152552:8;152548:17;152535:95;152400:248;;;:::o;202834:553::-;202996:22;;;202971;202996;;;:10;:22;;;;;;;;:33;203063:11;;202996:33;203040:19;;;;;:8;:19;;;;;;:34;;202996:33;;;;;;;;203063:11;;203040:19;202971:22;203040:34;;203063:11;;203040:34;:::i;:::-;;;;-1:-1:-1;;203114:22:0;;;203087:24;203114:22;;;:10;:22;;;;;;;;:39;;;203164:24;;;;;:8;:24;;;;;:44;;203114:39;;;;203164:44;;203114:39;;203164:44;:::i;:::-;;;;-1:-1:-1;;203258:11:0;;203219:17;;203239:30;;:16;:30;:::i;:::-;203219:50;;203280:36;203290:14;203306:9;203280;:36::i;:::-;203345:10;203332:47;;;203357:14;203373:5;203332:47;;;;;;;:::i;:::-;;;;;;;;202960:427;;;202834:553;;;:::o;202385:441::-;202545:22;;;202520;202545;;;:10;:22;;;;;;;;:33;;202616:39;;;;;202545:33;;;;;;202666:24;;;:8;:24;;;;;;:44;;202545:33;;202616:39;;;;202520:22;202666:44;;202616:39;;202666:44;:::i;:::-;;;;-1:-1:-1;;202721:19:0;;;;;;;:8;:19;;;;;:39;;202744:16;;202721:19;:39;;202744:16;;202721:39;:::i;:::-;;;;;;;;202789:10;202776:42;;;202801:9;202812:5;202776:42;;;;;;;:::i;:::-;;;;;;;;202509:317;;202385:441;;;:::o;20202:191::-;20295:6;;;;20312:17;;;;;;;;;;;20345:40;;20295:6;;;20312:17;20295:6;;20345:40;;20276:16;;20345:40;20265:128;20202:191;:::o;18485:97::-;15148:13;;;;;;;15140:69;;;;-1:-1:-1;;;15140:69:0;;31912:2:1;15140:69:0;;;31894:21:1;31951:2;31931:18;;;31924:30;31990:34;31970:18;;;31963:62;32061:13;32041:18;;;32034:41;32092:19;;15140:69:0;31710:407:1;15140:69:0;18548:26:::1;:24;:26::i;23071:118::-:0;22080:19;:17;:19::i;:::-;23131:7:::1;:14:::0;;-1:-1:-1;;23131:14:0::1;23141:4;23131:14;::::0;;23161:20:::1;23168:12;17243:10:::0;;17163:98;23168:12:::1;23161:20;::::0;4045:42:1;4033:55;;;4015:74;;4003:2;3988:18;23161:20:0::1;;;;;;;23071:118::o:0;23330:120::-;22339:16;:14;:16::i;:::-;23389:7:::1;:15:::0;;-1:-1:-1;;23389:15:0::1;::::0;;23420:22:::1;17243:10:::0;23429:12:::1;17163:98:::0;145663:703;145740:16;145794:12;145842:2;145832:12;;;145824:54;;;;-1:-1:-1;;;145824:54:0;;32324:2:1;145824:54:0;;;32306:21:1;32363:2;32343:18;;;32336:30;32402:31;32382:18;;;32375:59;32451:18;;145824:54:0;32122:353:1;145824:54:0;145974:4;145968:11;145956:23;;146037:6;146016:19;146006:8;145993:51;146085:6;146075:8;146071:21;146065:4;146058:35;146154:24;146181:44;146216:8;147513:1;147499:16;147493:23;147488:3;147484:33;;147337:198;146181:44;146154:71;-1:-1:-1;146314:3:0;146307;146288:22;;146287:30;146321:2;146286:37;146281:2;:42;146271:6;:52;146263:84;;;;-1:-1:-1;;;146263:84:0;;22184:2:1;146263:84:0;;;22166:21:1;22223:2;22203:18;;;22196:30;22262:21;22242:18;;;22235:49;22301:18;;146263:84:0;21982:343:1;146263:84:0;145774:592;145663:703;;;;;:::o;24965:545::-;25111:4;25128:13;25440:1;25410;25372:9;25366:16;25335:2;25324:9;25320:18;25280:6;25241:7;25211:4;25188:278;25176:290;24965:545;-1:-1:-1;;;;;;24965:545:0:o;155047:497::-;155159:18;155203:19;155213:8;146699:15;146694:3;146690:25;;146567:166;155203:19;155190:32;;155302:1;155289:10;:14;155281:44;;;;-1:-1:-1;;;155281:44:0;;32682:2:1;155281:44:0;;;32664:21:1;32721:2;32701:18;;;32694:30;32760:19;32740:18;;;32733:47;32797:18;;155281:44:0;32480:341:1;155281:44:0;155455:33;154800:2;155455:10;:33;:::i;:::-;155451:37;;:1;:37;:::i;:::-;155440:7;:48;;155418:118;;;;-1:-1:-1;;;155418:118:0;;33261:2:1;155418:118:0;;;33243:21:1;33300:2;33280:18;;;33273:30;33339:22;33319:18;;;33312:50;33379:18;;155418:118:0;33059:344:1;218608:1803:0;218869:7;218893:14;218911:1;218893:19;218889:36;;-1:-1:-1;218921:4:0;218914:11;;218889:36;218984:12;;;;218936:29;;;219091:1038;219115:14;219111:1;:18;219091:1038;;;219260:4;219228:36;;;-1:-1:-1;219202:1:0;219169:34;;;219336:6;;;:18;;-1:-1:-1;219346:8:0;;219336:18;219332:257;;;219515:3;219509:4;219505:14;219473:30;219469:51;219426:121;219415:132;;219332:257;219631:1;219613:14;;;219612:20;219637:1;219611:27;219607:399;;219723:114;;;;;;;;550:25:1;;;219707:13:0;;219723:35;;;;;;523:18:1;;219723:114:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;219896:19;;-1:-1:-1;219959:4:0;219949:15;;;;219607:399;-1:-1:-1;220059:1:0;220026:34;;;;220079;;;;219131:3;219091:1038;;;-1:-1:-1;;220282:4:0;-1:-1:-1;;220245:33:0;;220244:42;220311:14;;;220277:1;220310:20;220309:27;220301:67;;;;-1:-1:-1;;;220301:67:0;;33799:2:1;220301:67:0;;;33781:21:1;33838:2;33818:18;;;33811:30;33877:29;33857:18;;;33850:57;33924:18;;220301:67:0;33597:351:1;220301:67:0;-1:-1:-1;220399:4:0;;218608:1803;-1:-1:-1;;;;;;;;218608:1803:0:o;18590:113::-;15148:13;;;;;;;15140:69;;;;-1:-1:-1;;;15140:69:0;;31912:2:1;15140:69:0;;;31894:21:1;31951:2;31931:18;;;31924:30;31990:34;31970:18;;;31963:62;32061:13;32041:18;;;32034:41;32092:19;;15140:69:0;31710:407:1;15140:69:0;18663:32:::1;17243:10:::0;18663:18:::1;:32::i;22819:108::-:0;22546:7;;;;22878:41;;;;-1:-1:-1;;;22878:41:0;;34155:2:1;22878:41:0;;;34137:21:1;34194:2;34174:18;;;34167:30;34233:22;34213:18;;;34206:50;34273:18;;22878:41:0;33953:344:1;219:180;278:6;331:2;319:9;310:7;306:23;302:32;299:52;;;347:1;344;337:12;299:52;-1:-1:-1;370:23:1;;219:180;-1:-1:-1;219:180:1:o;586:196::-;654:20;;714:42;703:54;;693:65;;683:93;;772:1;769;762:12;683:93;586:196;;;:::o;787:186::-;846:6;899:2;887:9;878:7;874:23;870:32;867:52;;;915:1;912;905:12;867:52;938:29;957:9;938:29;:::i;:::-;928:39;787:186;-1:-1:-1;;;787:186:1:o;1355:481::-;1396:3;1434:5;1428:12;1461:6;1456:3;1449:19;1486:1;1496:162;1510:6;1507:1;1504:13;1496:162;;;1572:4;1628:13;;;1624:22;;1618:29;1600:11;;;1596:20;;1589:59;1525:12;1496:162;;;1500:3;1703:1;1696:4;1687:6;1682:3;1678:16;1674:27;1667:38;1825:4;1755:66;1750:2;1742:6;1738:15;1734:88;1729:3;1725:98;1721:109;1714:116;;;1355:481;;;;:::o;1841:1007::-;2232:4;2261:3;2291:6;2280:9;2273:25;2334:6;2329:2;2318:9;2314:18;2307:34;2377:6;2372:2;2361:9;2357:18;2350:34;2420:6;2415:2;2404:9;2400:18;2393:34;2464:6;2458:3;2447:9;2443:19;2436:35;2508:6;2502:3;2491:9;2487:19;2480:35;2564:42;2556:6;2552:55;2546:3;2535:9;2531:19;2524:84;2645:6;2639:3;2628:9;2624:19;2617:35;2689:6;2683:3;2672:9;2668:19;2661:35;2733:2;2727:3;2716:9;2712:19;2705:31;2753:44;2793:2;2782:9;2778:18;2770:6;2753:44;:::i;:::-;2745:52;;;2834:7;2828:3;2817:9;2813:19;2806:36;1841:1007;;;;;;;;;;;;;;:::o;2853:347::-;2904:8;2914:6;2968:3;2961:4;2953:6;2949:17;2945:27;2935:55;;2986:1;2983;2976:12;2935:55;-1:-1:-1;3009:20:1;;3052:18;3041:30;;3038:50;;;3084:1;3081;3074:12;3038:50;3121:4;3113:6;3109:17;3097:29;;3173:3;3166:4;3157:6;3149;3145:19;3141:30;3138:39;3135:59;;;3190:1;3187;3180:12;3135:59;2853:347;;;;;:::o;3205:477::-;3284:6;3292;3300;3353:2;3341:9;3332:7;3328:23;3324:32;3321:52;;;3369:1;3366;3359:12;3321:52;3409:9;3396:23;3442:18;3434:6;3431:30;3428:50;;;3474:1;3471;3464:12;3428:50;3513:58;3563:7;3554:6;3543:9;3539:22;3513:58;:::i;:::-;3590:8;;3487:84;;-1:-1:-1;3672:2:1;3657:18;;;;3644:32;;3205:477;-1:-1:-1;;;;3205:477:1:o;4100:545::-;4188:6;4196;4204;4212;4265:2;4253:9;4244:7;4240:23;4236:32;4233:52;;;4281:1;4278;4271:12;4233:52;4321:9;4308:23;4354:18;4346:6;4343:30;4340:50;;;4386:1;4383;4376:12;4340:50;4425:58;4475:7;4466:6;4455:9;4451:22;4425:58;:::i;:::-;4502:8;;4399:84;;-1:-1:-1;4584:2:1;4569:18;;4556:32;;4635:2;4620:18;4607:32;;-1:-1:-1;4100:545:1;-1:-1:-1;;;;4100:545:1:o;4650:553::-;4746:6;4754;4807:2;4795:9;4786:7;4782:23;4778:32;4775:52;;;4823:1;4820;4813:12;4775:52;4863:9;4850:23;4896:18;4888:6;4885:30;4882:50;;;4928:1;4925;4918:12;4882:50;4951:22;;5007:3;4989:16;;;4985:26;4982:46;;;5024:1;5021;5014:12;4982:46;5047:2;-1:-1:-1;5099:2:1;5084:18;;5071:32;5143:10;5132:22;;5122:33;;5112:61;;5169:1;5166;5159:12;5112:61;5192:5;5182:15;;;4650:553;;;;;:::o;5208:171::-;5275:20;;5335:18;5324:30;;5314:41;;5304:69;;5369:1;5366;5359:12;5384:481;5462:6;5470;5478;5531:2;5519:9;5510:7;5506:23;5502:32;5499:52;;;5547:1;5544;5537:12;5499:52;5570:28;5588:9;5570:28;:::i;:::-;5560:38;;5649:2;5638:9;5634:18;5621:32;5676:18;5668:6;5665:30;5662:50;;;5708:1;5705;5698:12;5662:50;5747:58;5797:7;5788:6;5777:9;5773:22;5747:58;:::i;:::-;5384:481;;5824:8;;-1:-1:-1;5721:84:1;;-1:-1:-1;;;;5384:481:1:o;5870:535::-;5974:6;5982;5990;5998;6006;6014;6067:3;6055:9;6046:7;6042:23;6038:33;6035:53;;;6084:1;6081;6074:12;6035:53;6107:29;6126:9;6107:29;:::i;:::-;6097:39;;6155:38;6189:2;6178:9;6174:18;6155:38;:::i;:::-;5870:535;;6145:48;;-1:-1:-1;;;;6240:2:1;6225:18;;6212:32;;6291:2;6276:18;;6263:32;;6342:3;6327:19;;6314:33;;-1:-1:-1;6394:3:1;6379:19;;;6366:33;;-1:-1:-1;5870:535:1:o;6410:184::-;6468:6;6521:2;6509:9;6500:7;6496:23;6492:32;6489:52;;;6537:1;6534;6527:12;6489:52;6560:28;6578:9;6560:28;:::i;7409:273::-;7465:6;7518:2;7506:9;7497:7;7493:23;7489:32;7486:52;;;7534:1;7531;7524:12;7486:52;7573:9;7560:23;7626:5;7619:13;7612:21;7605:5;7602:32;7592:60;;7648:1;7645;7638:12;7687:437;7766:1;7762:12;;;;7809;;;7830:61;;7884:4;7876:6;7872:17;7862:27;;7830:61;7937:2;7929:6;7926:14;7906:18;7903:38;7900:218;;7974:77;7971:1;7964:88;8075:4;8072:1;8065:15;8103:4;8100:1;8093:15;7900:218;;7687:437;;;:::o;8828:184::-;8880:77;8877:1;8870:88;8977:4;8974:1;8967:15;9001:4;8998:1;8991:15;9017:125;9082:9;;;9103:10;;;9100:36;;;9116:18;;:::i;10609:195::-;10648:3;-1:-1:-1;;10672:5:1;10669:77;10666:103;;10749:18;;:::i;:::-;-1:-1:-1;10796:1:1;10785:13;;10609:195::o;11908:128::-;11975:9;;;11996:11;;;11993:37;;;12010:18;;:::i;14140:184::-;14192:77;14189:1;14182:88;14289:4;14286:1;14279:15;14313:4;14310:1;14303:15;14454:544;14555:2;14550:3;14547:11;14544:448;;;14591:1;14616:5;14612:2;14605:17;14661:4;14657:2;14647:19;14731:2;14719:10;14715:19;14712:1;14708:27;14702:4;14698:38;14767:4;14755:10;14752:20;14749:47;;;-1:-1:-1;14790:4:1;14749:47;14845:2;14840:3;14836:12;14833:1;14829:20;14823:4;14819:31;14809:41;;14900:82;14918:2;14911:5;14908:13;14900:82;;;14963:17;;;14944:1;14933:13;14900:82;;;14904:3;;;14454:544;;;:::o;15234:1467::-;15358:3;15352:10;15385:18;15377:6;15374:30;15371:56;;;15407:18;;:::i;:::-;15436:96;15525:6;15485:38;15517:4;15511:11;15485:38;:::i;:::-;15479:4;15436:96;:::i;:::-;15587:4;;15651:2;15640:14;;15668:1;15663:781;;;;16488:1;16505:6;16502:89;;;-1:-1:-1;16557:19:1;;;16551:26;16502:89;-1:-1:-1;;15131:1:1;15127:11;;;15123:84;15119:89;15109:100;15215:1;15211:11;;;15106:117;16604:81;;15633:1062;;15663:781;14401:1;14394:14;;;14438:4;14425:18;;15711:66;15699:79;;;15875:236;15889:7;15886:1;15883:14;15875:236;;;15978:19;;;15972:26;15957:42;;16070:27;;;;16038:1;16026:14;;;;15905:19;;15875:236;;;15879:3;16139:6;16130:7;16127:19;16124:261;;;16200:19;;;16194:26;-1:-1:-1;;16283:1:1;16279:14;;;16295:3;16275:24;16271:97;16267:102;16252:118;16237:134;;16124:261;-1:-1:-1;;;;;16431:1:1;16415:14;;;16411:22;16398:36;;-1:-1:-1;15234:1467:1:o;17315:269::-;17372:6;17425:2;17413:9;17404:7;17400:23;17396:32;17393:52;;;17441:1;17438;17431:12;17393:52;17480:9;17467:23;17530:4;17523:5;17519:16;17512:5;17509:27;17499:55;;17550:1;17547;17540:12;17933:615;18037:4;18043:6;18103:11;18090:25;18193:66;18182:8;18166:14;18162:29;18158:102;18138:18;18134:127;18124:155;;18275:1;18272;18265:12;18124:155;18302:33;;18354:20;;;-1:-1:-1;18397:18:1;18386:30;;18383:50;;;18429:1;18426;18419:12;18383:50;18462:4;18450:17;;-1:-1:-1;18513:1:1;18509:14;;;18493;18489:35;18479:46;;18476:66;;;18538:1;18535;18528:12;19603:580;19680:4;19686:6;19746:11;19733:25;19836:66;19825:8;19809:14;19805:29;19801:102;19781:18;19777:127;19767:155;;19918:1;19915;19908:12;19767:155;19945:33;;19997:20;;;-1:-1:-1;20040:18:1;20029:30;;20026:50;;;20072:1;20069;20062:12;20026:50;20105:4;20093:17;;-1:-1:-1;20136:14:1;20132:27;;;20122:38;;20119:58;;;20173:1;20170;20163:12;21604:184;21656:77;21653:1;21646:88;21753:4;21750:1;21743:15;21777:4;21774:1;21767:15;23904:616;24128:18;24120:6;24116:31;24105:9;24098:50;24184:2;24179;24168:9;24164:18;24157:30;24223:6;24218:2;24207:9;24203:18;24196:34;24281:6;24273;24267:3;24256:9;24252:19;24239:49;24338:1;24332:3;24323:6;24312:9;24308:22;24304:32;24297:43;24079:4;24467:3;24397:66;24392:2;24384:6;24380:15;24376:88;24365:9;24361:104;24357:114;24349:122;;24507:6;24502:2;24491:9;24487:18;24480:34;23904:616;;;;;;;:::o;30374:274::-;30414:1;30440;30430:189;;30475:77;30472:1;30465:88;30576:4;30573:1;30566:15;30604:4;30601:1;30594:15;30430:189;-1:-1:-1;30633:9:1;;30374:274::o;31366:339::-;31555:42;31547:6;31543:55;31532:9;31525:74;31635:2;31630;31619:9;31615:18;31608:30;31506:4;31655:44;31695:2;31684:9;31680:18;31672:6;31655:44;:::i;:::-;31647:52;31366:339;-1:-1:-1;;;;31366:339:1:o;32826:228::-;32866:7;32992:1;-1:-1:-1;;32920:74:1;32917:1;32914:81;32909:1;32902:9;32895:17;32891:105;32888:131;;;32999:18;;:::i;:::-;-1:-1:-1;33039:9:1;;32826:228::o;33408:184::-;33478:6;33531:2;33519:9;33510:7;33506:23;33502:32;33499:52;;;33547:1;33544;33537:12;33499:52;-1:-1:-1;33570:16:1;;33408:184;-1:-1:-1;33408:184:1:o
Swarm Source
ipfs://67c2a5601257bceecf78922d6cda335fbcdcc053ae51ded734a35f4e1563a1ed
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.