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:
MorphPortal
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) (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); } } } /** * @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) || (!Address.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; } } /** * @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; } } // 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 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.9.0) (utils/Strings.sol) // 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); } } } // 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); } } } /** * @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) ) ); } } /** * @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))); } } /// @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 SystemConfig * @notice The SystemConfig contract is used to manage configuration of an Morph network. All * configuration is stored on L1 and picked up by L2 as part of the derviation of the L2 * chain. */ contract SystemConfig is OwnableUpgradeable, Semver { /** * @notice Enum representing different types of updates. * * @custom:value BATCHER Represents an update to the batcher hash. * @custom:value GAS_CONFIG Represents an update to txn fee config on L2. * @custom:value GAS_LIMIT Represents an update to gas limit on L2. * @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe * block distrubution. */ enum UpdateType { BATCHER, GAS_CONFIG, GAS_LIMIT, UNSAFE_BLOCK_SIGNER } /** * @notice Version identifier, used for upgrades. */ uint256 public constant VERSION = 0; /** * @notice Storage slot that the unsafe block signer is stored at. Storing it at this * deterministic storage slot allows for decoupling the storage layout from the way * that `solc` lays out storage. The `op-node` uses a storage proof to fetch this value. */ bytes32 public constant UNSAFE_BLOCK_SIGNER_SLOT = keccak256("systemconfig.unsafeblocksigner"); /** * @notice Fixed L2 gas overhead. Used as part of the L2 fee calculation. */ uint256 public overhead; /** * @notice Dynamic L2 gas overhead. Used as part of the L2 fee calculation. */ uint256 public scalar; /** * @notice Identifier for the batcher. For version 1 of this configuration, this is represented * as an address left-padded with zeros to 32 bytes. */ bytes32 public batcherHash; /** * @notice L2 block gas limit. */ uint64 public gasLimit; /** * @notice The configuration for the deposit fee market. Used by the MorphPortal * to meter the cost of buying L2 gas on L1. Set as internal and wrapped with a getter * so that the struct is returned instead of a tuple. */ ResourceMetering.ResourceConfig internal _resourceConfig; /** * @notice Emitted when configuration is updated * * @param version SystemConfig version. * @param updateType Type of update. * @param data Encoded update data. */ event ConfigUpdate( uint256 indexed version, UpdateType indexed updateType, bytes data ); /** * @custom:semver 1.3.0 * * @param _owner Initial owner of the contract. * @param _overhead Initial overhead value. * @param _scalar Initial scalar value. * @param _batcherHash Initial batcher hash. * @param _gasLimit Initial gas limit. * @param _unsafeBlockSigner Initial unsafe block signer address. * @param _config Initial resource config. */ constructor( address _owner, uint256 _overhead, uint256 _scalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, ResourceMetering.ResourceConfig memory _config ) Semver(1, 3, 0) { initialize({ _owner: _owner, _overhead: _overhead, _scalar: _scalar, _batcherHash: _batcherHash, _gasLimit: _gasLimit, _unsafeBlockSigner: _unsafeBlockSigner, _config: _config }); } /** * @notice Initializer. The resource config must be set before the * require check. * * @param _owner Initial owner of the contract. * @param _overhead Initial overhead value. * @param _scalar Initial scalar value. * @param _batcherHash Initial batcher hash. * @param _gasLimit Initial gas limit. * @param _unsafeBlockSigner Initial unsafe block signer address. * @param _config Initial ResourceConfig. */ function initialize( address _owner, uint256 _overhead, uint256 _scalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, ResourceMetering.ResourceConfig memory _config ) public initializer { __Ownable_init(); transferOwnership(_owner); overhead = _overhead; scalar = _scalar; batcherHash = _batcherHash; gasLimit = _gasLimit; _setUnsafeBlockSigner(_unsafeBlockSigner); _setResourceConfig(_config); require( _gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low" ); } /** * @notice Returns the minimum L2 gas limit that can be safely set for the system to * operate. The L2 gas limit must be larger than or equal to the amount of * gas that is allocated for deposits per block plus the amount of gas that * is allocated for the system transaction. * This function is used to determine if changes to parameters are safe. * * @return uint64 */ function minimumGasLimit() public view returns (uint64) { return uint64(_resourceConfig.maxResourceLimit) + uint64(_resourceConfig.systemTxMaxGas); } /** * @notice High level getter for the unsafe block signer address. Unsafe blocks can be * propagated across the p2p network if they are signed by the key corresponding to * this address. * * @return Address of the unsafe block signer. */ // solhint-disable-next-line ordering function unsafeBlockSigner() external view returns (address) { address addr; bytes32 slot = UNSAFE_BLOCK_SIGNER_SLOT; assembly { addr := sload(slot) } return addr; } /** * @notice Updates the unsafe block signer address. * * @param _unsafeBlockSigner New unsafe block signer address. */ function setUnsafeBlockSigner( address _unsafeBlockSigner ) external onlyOwner { _setUnsafeBlockSigner(_unsafeBlockSigner); bytes memory data = abi.encode(_unsafeBlockSigner); emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data); } /** * @notice Updates the batcher hash. * * @param _batcherHash New batcher hash. */ function setBatcherHash(bytes32 _batcherHash) external onlyOwner { batcherHash = _batcherHash; bytes memory data = abi.encode(_batcherHash); emit ConfigUpdate(VERSION, UpdateType.BATCHER, data); } /** * @notice Updates gas config. * * @param _overhead New overhead value. * @param _scalar New scalar value. */ function setGasConfig( uint256 _overhead, uint256 _scalar ) external onlyOwner { overhead = _overhead; scalar = _scalar; bytes memory data = abi.encode(_overhead, _scalar); emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data); } /** * @notice Updates the L2 gas limit. * * @param _gasLimit New gas limit. */ function setGasLimit(uint64 _gasLimit) external onlyOwner { require( _gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low" ); gasLimit = _gasLimit; bytes memory data = abi.encode(_gasLimit); emit ConfigUpdate(VERSION, UpdateType.GAS_LIMIT, data); } /** * @notice Low level setter for the unsafe block signer address. This function exists to * deduplicate code around storing the unsafeBlockSigner address in storage. * * @param _unsafeBlockSigner New unsafeBlockSigner value. */ function _setUnsafeBlockSigner(address _unsafeBlockSigner) internal { bytes32 slot = UNSAFE_BLOCK_SIGNER_SLOT; assembly { sstore(slot, _unsafeBlockSigner) } } /** * @notice A getter for the resource config. Ensures that the struct is * returned instead of a tuple. * * @return ResourceConfig */ function resourceConfig() external view returns (ResourceMetering.ResourceConfig memory) { return _resourceConfig; } /** * @notice An external setter for the resource config. In the future, this * method may emit an event that the `op-node` picks up for when the * resource config is changed. * * @param _config The new resource config values. */ function setResourceConfig( ResourceMetering.ResourceConfig memory _config ) external onlyOwner { _setResourceConfig(_config); } /** * @notice An internal setter for the resource config. Ensures that the * config is sane before storing it by checking for invariants. * * @param _config The new resource config. */ function _setResourceConfig( ResourceMetering.ResourceConfig memory _config ) internal { // Min base fee must be less than or equal to max base fee. require( _config.minimumBaseFee <= _config.maximumBaseFee, "SystemConfig: min base fee must be less than max base" ); // Base fee change denominator must be greater than 1. require( _config.baseFeeMaxChangeDenominator > 1, "SystemConfig: denominator must be larger than 1" ); // Max resource limit plus system tx gas must be less than or equal to the L2 gas limit. // The gas limit must be increased before these values can be increased. require( _config.maxResourceLimit + _config.systemTxMaxGas <= gasLimit, "SystemConfig: gas limit too low" ); // Elasticity multiplier must be greater than 0. require( _config.elasticityMultiplier > 0, "SystemConfig: elasticity multiplier cannot be 0" ); // No precision loss when computing target resource limit. require( ((_config.maxResourceLimit / _config.elasticityMultiplier) * _config.elasticityMultiplier) == _config.maxResourceLimit, "SystemConfig: precision loss with target resource limit" ); _resourceConfig = _config; } } /** * @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; } } /** * @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 ) ); } } /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ library AddressAliasHelper { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function that converts the address in the L1 that submitted a tx to /// the inbox to the msg.sender viewed in the L2 /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { unchecked { l2Address = address(uint160(l1Address) + offset); } } /// @notice Utility function that converts the msg.sender viewed in the L2 to the /// address in the L1 that submitted a tx to the inbox /// @param l2Address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { unchecked { l1Address = address(uint160(l2Address) - offset); } } } contract Tree { error MerkleTreeFull(); uint256 internal constant _TREE_DEPTH = 32; uint256 internal constant _MAX_DEPOSIT_COUNT = 2 ** _TREE_DEPTH - 1; bytes32[_TREE_DEPTH] internal _branch; uint256 public leafNodesCount; uint256[10] private _gap; function getTreeRoot() public view returns (bytes32) { bytes32 node; uint256 size = leafNodesCount; bytes32 currentZeroHashHeight = 0; for (uint256 height = 0; height < _TREE_DEPTH; height++) { if (((size >> height) & 1) == 1) node = keccak256(abi.encodePacked(_branch[height], node)); else node = keccak256(abi.encodePacked(node, currentZeroHashHeight)); currentZeroHashHeight = keccak256( abi.encodePacked(currentZeroHashHeight, currentZeroHashHeight) ); } return node; } function _appendMessageHash(bytes32 leafHash) internal { bytes32 node = leafHash; // Avoid overflowing the Merkle tree (and prevent edge case in computing `_branch`) if (leafNodesCount >= _MAX_DEPOSIT_COUNT) { revert MerkleTreeFull(); } // Add deposit data root to Merkle tree (update a single `_branch` node) uint256 size = ++leafNodesCount; for (uint256 height = 0; height < _TREE_DEPTH; height++) { if (((size >> height) & 1) == 1) { _branch[height] = node; return; } node = keccak256(abi.encodePacked(_branch[height], node)); } // As the loop should always end prematurely with the `return` statement, // this code should be unreachable. We assert `false` just to be safe. assert(false); } function verifyMerkleProof( bytes32 leafHash, bytes32[_TREE_DEPTH] memory smtProof, uint256 index, bytes32 root ) public pure returns (bool) { bytes32 node = leafHash; for (uint256 height = 0; height < _TREE_DEPTH; height++) { if (((index >> height) & 1) == 1) node = keccak256(abi.encodePacked(smtProof[height], node)); else node = keccak256(abi.encodePacked(node, smtProof[height])); } return node == root; } } contract Verify { function verifyMerkleProof( bytes32 leafHash, bytes32[32] calldata smtProof, uint256 index, bytes32 root ) public pure returns (bool) { bytes32 node = leafHash; for (uint256 height = 0; height < 32; height++) { if (((index >> height) & 1) == 1) node = keccak256(abi.encodePacked(smtProof[height], node)); else node = keccak256(abi.encodePacked(node, smtProof[height])); } return node == root; } } // 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; } /** * @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; } 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; } } // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/BitMaps.sol) /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMapsUpgradeable { struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo(BitMap storage bitmap, uint256 index, bool value) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] &= ~mask; } } contract L1MessageStorage { using BitMapsUpgradeable for BitMapsUpgradeable.BitMap; /// @notice The list of queued cross domain messages. bytes32[] public messageQueue; uint256 public pendingQueueIndex; /// @dev The bitmap for dropped messages, where `droppedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`. BitMapsUpgradeable.BitMap private droppedMessageBitmap; /// @dev The bitmap for skipped messages, where `skippedMessageBitmap[i]` keeps the bits from `[i*256, (i+1)*256)`. mapping(uint256 => uint256) private skippedMessageBitmap; /// @notice Emitted when a new L1 => L2 transaction is appended to the queue. /// @param sender The address of account who initiates the transaction. /// @param target The address of account who will receive the transaction. /// @param value The value passed with the transaction. /// @param queueIndex The index of this transaction in the queue. /// @param gasLimit Gas limit required to complete the message relay on L2. /// @param data The calldata of the transaction. event QueueTransaction( address indexed sender, address indexed target, uint256 value, uint64 queueIndex, uint256 gasLimit, bytes data ); /// @notice Emitted when some L1 => L2 transactions are included in L1. /// @param startIndex The start index of messages popped. /// @param count The number of messages popped. /// @param skippedBitmap A bitmap indicates whether a message is skipped. event DequeueTransaction( uint256 startIndex, uint256 count, uint256 skippedBitmap ); /// @notice Emitted when a message is dropped from L1. /// @param index The index of message dropped. event DropTransaction(uint256 index); constructor() {} function nextCrossDomainMessageIndex() external view returns (uint256) { return messageQueue.length; } function computeTransactionHash( address _sender, uint256 _queueIndex, uint256 _value, address _target, uint256 _gasLimit, bytes calldata _data ) public pure returns (bytes32) { // We use EIP-2718 to encode the L1 message, and the encoding of the message is // `TransactionType || TransactionPayload` // where // 1. `TransactionType` is 0x7E // 2. `TransactionPayload` is `rlp([queueIndex, gasLimit, to, value, data, sender])` // // The spec of rlp: https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/ uint256 transactionType = 0x7E; bytes32 hash; assembly { function get_uint_bytes(v) -> len { if eq(v, 0) { len := 1 leave } for { } gt(v, 0) { } { len := add(len, 1) v := shr(8, v) } } // This is used for both store uint and single byte. // Integer zero is special handled by geth to encode as `0x80` function store_uint_or_byte(_ptr, v, is_uint) -> ptr { ptr := _ptr switch lt(v, 128) case 1 { switch and(iszero(v), is_uint) case 1 { // integer 0 mstore8(ptr, 0x80) } default { // single byte in the [0x00, 0x7f] mstore8(ptr, v) } ptr := add(ptr, 1) } default { // 1-32 bytes long let len := get_uint_bytes(v) mstore8(ptr, add(len, 0x80)) ptr := add(ptr, 1) mstore(ptr, shl(mul(8, sub(32, len)), v)) ptr := add(ptr, len) } } function store_address(_ptr, v) -> ptr { ptr := _ptr // 20 bytes long mstore8(ptr, 0x94) // 0x80 + 0x14 ptr := add(ptr, 1) mstore(ptr, shl(96, v)) ptr := add(ptr, 0x14) } // 1 byte for TransactionType // 4 byte for list payload length let start_ptr := add(mload(0x40), 5) let ptr := start_ptr ptr := store_uint_or_byte(ptr, _queueIndex, 1) ptr := store_uint_or_byte(ptr, _gasLimit, 1) ptr := store_address(ptr, _target) ptr := store_uint_or_byte(ptr, _value, 1) switch eq(_data.length, 1) case 1 { // single byte ptr := store_uint_or_byte( ptr, byte(0, calldataload(_data.offset)), 0 ) } default { switch lt(_data.length, 56) case 1 { // a string is 0-55 bytes long mstore8(ptr, add(0x80, _data.length)) ptr := add(ptr, 1) calldatacopy(ptr, _data.offset, _data.length) ptr := add(ptr, _data.length) } default { // a string is more than 55 bytes long let len_bytes := get_uint_bytes(_data.length) mstore8(ptr, add(0xb7, len_bytes)) ptr := add(ptr, 1) mstore(ptr, shl(mul(8, sub(32, len_bytes)), _data.length)) ptr := add(ptr, len_bytes) calldatacopy(ptr, _data.offset, _data.length) ptr := add(ptr, _data.length) } } ptr := store_address(ptr, _sender) let payload_len := sub(ptr, start_ptr) let value let value_bytes switch lt(payload_len, 56) case 1 { // the total payload of a list is 0-55 bytes long value := add(0xc0, payload_len) value_bytes := 1 } default { // If the total payload of a list is more than 55 bytes long let len_bytes := get_uint_bytes(payload_len) value_bytes := add(len_bytes, 1) value := add(0xf7, len_bytes) value := shl(mul(len_bytes, 8), value) value := or(value, payload_len) } value := or(value, shl(mul(8, value_bytes), transactionType)) value_bytes := add(value_bytes, 1) let value_bits := mul(8, value_bytes) value := or( shl(sub(256, value_bits), value), shr(value_bits, mload(start_ptr)) ) start_ptr := sub(start_ptr, value_bytes) mstore(start_ptr, value) hash := keccak256(start_ptr, sub(ptr, start_ptr)) } return hash; } function isMessageSkipped( uint256 _queueIndex ) external view returns (bool) { if (_queueIndex >= pendingQueueIndex) return false; return _isMessageSkipped(_queueIndex); } function isMessageDropped( uint256 _queueIndex ) external view returns (bool) { // it should be a skipped message first. return _isMessageSkipped(_queueIndex) && droppedMessageBitmap.get(_queueIndex); } function _popCrossDomainMessage( uint256 _startIndex, uint256 _count, uint256 _skippedBitmap ) internal { require(_count <= 256, "pop too many messages"); require(pendingQueueIndex == _startIndex, "start index mismatch"); unchecked { // clear extra bits in `_skippedBitmap`, and if _count = 256, it's designed to overflow. uint256 mask = (1 << _count) - 1; _skippedBitmap &= mask; uint256 bucket = _startIndex >> 8; uint256 offset = _startIndex & 0xff; skippedMessageBitmap[bucket] |= _skippedBitmap << offset; if (offset + _count > 256) { skippedMessageBitmap[bucket + 1] = _skippedBitmap >> (256 - offset); } pendingQueueIndex = _startIndex + _count; } emit DequeueTransaction(_startIndex, _count, _skippedBitmap); } function _dropCrossDomainMessage(uint256 _index) internal { require(_index < pendingQueueIndex, "cannot drop pending message"); require(_isMessageSkipped(_index), "drop non-skipped message"); require(!droppedMessageBitmap.get(_index), "message already dropped"); droppedMessageBitmap.set(_index); emit DropTransaction(_index); } /// @dev Internal function to queue a L1 transaction. /// @param _sender The address of sender who will initiate this transaction in L2. /// @param _target The address of target contract to call in L2. /// @param _value The value passed /// @param _gasLimit The maximum gas should be used for this transaction in L2. /// @param _data The calldata passed to target contract. function _queueTransaction( address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes calldata _data ) internal { // compute transaction hash uint256 _queueIndex = messageQueue.length; bytes32 _hash = computeTransactionHash( _sender, _queueIndex, _value, _target, _gasLimit, _data ); messageQueue.push(_hash); // emit event emit QueueTransaction( _sender, _target, _value, uint64(_queueIndex), _gasLimit, _data ); } /// @dev Returns whether the bit at `index` is set. function _isMessageSkipped(uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return skippedMessageBitmap[bucket] & mask != 0; } } /** * @custom:proxied * @title MorphPortal * @notice The MorphPortal is a low-level contract responsible for passing messages between L1 * and L2. Messages sent directly to the MorphPortal have no form of replayability. * Users are encouraged to use the L1CrossDomainMessenger for a higher-level interface. */ contract MorphPortal is Initializable, ResourceMetering, Semver, Verify, L1MessageStorage, IL1MessageQueue { /** * @notice Represents a proven withdrawal. * * @custom:field withdrawalRoot Root of the L2 withdraw this was proven against. * @custom:field timestamp Timestamp at which the withdrawal was proven. * @custom:field index Index of the withdraw tx this was proven against. */ struct ProvenWithdrawal { bytes32 withdrawalRoot; uint256 timestamp; uint256 withdrawalIndex; } /** * @notice Version of the deposit event. */ uint256 internal constant DEPOSIT_VERSION = 0; /** * @notice The L2 gas limit set when eth is deposited using the receive() function. */ uint64 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000; /** * @notice Address of the SystemConfig contract. */ SystemConfig public immutable SYSTEM_CONFIG; /** * @notice Address that has the ability to pause and unpause withdrawals. */ address public immutable GUARDIAN; /** * @notice Address of the Rollup contract. */ Rollup public immutable ROLLUP; /** * @notice Address of the L2 account which initiated a withdrawal in this transaction. If the * of this variable is the default L2 sender address, then we are NOT inside of a call * to finalizeWithdrawalTransaction. */ address public l2Sender; /** * @notice Address of the l1CrossDomainMessenger contract. */ address public l1Messenger; /** * @notice A list of withdrawal hashes which have been successfully finalized. */ mapping(bytes32 => bool) public finalizedWithdrawals; /** * @notice A mapping of withdrawal hashes to `ProvenWithdrawal` data. */ mapping(bytes32 => ProvenWithdrawal) public provenWithdrawals; /** * @notice Determines if cross domain messaging is paused. When set to true, * withdrawals are paused. This may be removed in the future. */ bool public paused; /** * @notice Emitted when a transaction is deposited from L1 to L2. The parameters of this event * are read by the rollup node and used to derive deposit transactions on L2. * * @param from Address that triggered the deposit transaction. * @param to Address that the deposit transaction is directed to. * @param version Version of this deposit transaction event. * @param opaqueData ABI encoded deposit data to be parsed off-chain. */ event TransactionDeposited( address indexed from, address indexed to, uint256 indexed version, bytes opaqueData ); /** * @notice Emitted when a withdrawal transaction is proven. * * @param withdrawalHash Hash of the withdrawal transaction. */ event WithdrawalProven( bytes32 indexed withdrawalHash, address indexed from, address indexed to ); /** * @notice Emitted when a withdrawal transaction is finalized. * * @param withdrawalHash Hash of the withdrawal transaction. * @param success Whether the withdrawal transaction was successful. */ event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success); /** * @notice Emitted when the pause is triggered. * * @param account Address of the account triggering the pause. */ event Paused(address account); /** * @notice Emitted when the pause is lifted. * * @param account Address of the account triggering the unpause. */ event Unpaused(address account); /** * @notice Reverts when paused. */ modifier whenNotPaused() { require(paused == false, "MorphPortal: paused"); _; } /** * @notice Reverts when caller not messager contract. */ modifier onlyMessenger() { require( msg.sender == l1Messenger, "messenger contract unauthenticated" ); _; } /** * @notice Reverts when caller not rollup contract. */ modifier onlyRollup() { require( msg.sender == address(ROLLUP), "ROLLUP contract unauthenticated" ); _; } /** * todo: change version * @custom:semver 1.6.0 * * @param _guardian Address that can pause deposits and withdrawals. * @param _paused Sets the contract's pausability state. * @param _config Address of the SystemConfig contract. */ constructor( address _guardian, bool _paused, SystemConfig _config, Rollup _rollup, address _l1Messenger ) Semver(1, 6, 0) { GUARDIAN = _guardian; SYSTEM_CONFIG = _config; ROLLUP = _rollup; initialize(_paused, _l1Messenger); } /** * @notice Initializer. */ function initialize(bool _paused, address _l1Messenger) public initializer { l2Sender = Constants.DEFAULT_L2_SENDER; paused = _paused; l1Messenger = _l1Messenger; __ResourceMetering_init(); } /** * @notice Pause deposits and withdrawals. */ function pause() external { require( msg.sender == GUARDIAN, "MorphPortal: only guardian can pause" ); paused = true; emit Paused(msg.sender); } /** * @notice Unpause deposits and withdrawals. */ function unpause() external { require( msg.sender == GUARDIAN, "MorphPortal: only guardian can unpause" ); paused = false; emit Unpaused(msg.sender); } /** * @notice Computes the minimum gas limit for a deposit. The minimum gas limit * linearly increases based on the size of the calldata. This is to prevent * users from creating L2 resource usage without paying for it. This function * can be used when interacting with the portal to ensure forwards compatibility. * */ function minimumGasLimit(uint64 _byteCount) public pure returns (uint64) { return _byteCount * 16 + 21000; } /** * @notice Getter for the resource config. Used internally by the ResourceMetering * contract. The SystemConfig is the source of truth for the resource config. * * @return ResourceMetering.ResourceConfig */ function _resourceConfig() internal view override returns (ResourceMetering.ResourceConfig memory) { return SYSTEM_CONFIG.resourceConfig(); } /** * @notice Proves a withdrawal transaction. * * @param _tx Withdrawal transaction to finalize. * @param _withdrawalProof Inclusion proof of the withdrawal in L2ToL1MessagePasser contract. * @param _withdrawalRoot Inclusion root of the withdrawal in L2ToL1MessagePasser contract. */ function proveWithdrawalTransaction( Types.WithdrawalTransaction memory _tx, bytes32[32] calldata _withdrawalProof, bytes32 _withdrawalRoot ) external whenNotPaused { // Prevent users from creating a deposit transaction where this address is the message // sender on L2. Because this is checked here, we do not need to check again in // `finalizeWithdrawalTransaction`. require( _tx.target != address(this), "MorphPortal: you cannot send messages to the portal contract" ); // Load the ProvenWithdrawal into memory, using the withdrawal hash as a unique identifier. bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx); ProvenWithdrawal memory provenWithdrawal = provenWithdrawals[ withdrawalHash ]; // We generally want to prevent users from proving the same withdrawal multiple times // because each successive proof will update the timestamp. A malicious user can take // advantage of this to prevent other users from finalizing their withdrawal. However, // since withdrawals are proven before an output root is finalized, we need to allow users // to re-prove their withdrawal only in the case that the output root for their specified // output index has been updated. require( provenWithdrawal.timestamp == 0, "MorphPortal: withdrawal hash has already been proven" ); // withdrawalRoot for withdraw proof verify uint256 withdrawalBatchIndex = ROLLUP.withdrawalRoots(_withdrawalRoot); require( (withdrawalBatchIndex > 0), "MorphPortal: do not submit withdrawalRoot" ); // Verify that the hash of this withdrawal was stored in the L2toL1MessagePasser contract // on L2. If this is true, under the assumption that the Tree does not have // bugs, then we know that this withdrawal was actually triggered on L2 and can therefore // be relayed on L1. require( verifyMerkleProof( withdrawalHash, _withdrawalProof, _tx.nonce, _withdrawalRoot ), "MorphPortal: invalid withdrawal inclusion proof" ); // Designate the withdrawalHash as proven by storing the `withdrawalRoot`, `timestamp`, and // `withdrawalIndex` in the `provenWithdrawals` mapping. A `withdrawalHash` can only be // proven once unless it is submitted again with a different withdrawalRoot. provenWithdrawals[withdrawalHash] = ProvenWithdrawal({ withdrawalRoot: _withdrawalRoot, timestamp: block.timestamp, withdrawalIndex: _tx.nonce }); // Emit a `WithdrawalProven` event. emit WithdrawalProven(withdrawalHash, _tx.sender, _tx.target); } /** * @notice Finalizes a withdrawal transaction. * * @param _tx Withdrawal transaction to finalize. */ function finalizeWithdrawalTransaction( Types.WithdrawalTransaction memory _tx ) external whenNotPaused { // Make sure that the l2Sender has not yet been set. The l2Sender is set to a value other // than the default value when a withdrawal transaction is being finalized. This check is // a defacto reentrancy guard. require( l2Sender == Constants.DEFAULT_L2_SENDER, "MorphPortal: can only trigger one withdrawal per transaction" ); // Grab the proven withdrawal from the `provenWithdrawals` map. bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx); ProvenWithdrawal memory provenWithdrawal = provenWithdrawals[ withdrawalHash ]; // A withdrawal can only be finalized if it has been proven. We know that a withdrawal has // been proven at least once when its timestamp is non-zero. Unproven withdrawals will have // a timestamp of zero. require( provenWithdrawal.timestamp != 0, "MorphPortal: withdrawal has not been proven yet" ); // A proven withdrawal must wait at least the finalization period before it can be // finalized. This waiting period can elapse in parallel with the waiting period for the // output the withdrawal was proven against. In effect, this means that the minimum // withdrawal time is proposal submission time + finalization period. require( _isFinalizationPeriodElapsed(provenWithdrawal.timestamp), "MorphPortal: proven withdrawal finalization period has not elapsed" ); // withdrawalRoot for withdraw proof verify uint256 withdrawalBatchIndex = ROLLUP.withdrawalRoots( provenWithdrawal.withdrawalRoot ); require( (withdrawalBatchIndex > 0), "MorphPortal: do not submit withdrawalRoot" ); bytes32 finStateRoots = ROLLUP.finalizedStateRoots( withdrawalBatchIndex ); require(finStateRoots != bytes32(0), "batch not verified"); // Check that this withdrawal has not already been finalized, this is replay protection. require( finalizedWithdrawals[withdrawalHash] == false, "MorphPortal: withdrawal has already been finalized" ); // Mark the withdrawal as finalized so it can't be replayed. finalizedWithdrawals[withdrawalHash] = true; // Set the l2Sender so contracts know who triggered this withdrawal on L2. l2Sender = _tx.sender; // Trigger the call to the target contract. We use a custom low level method // SafeCall.callWithMinGas to ensure two key properties // 1. Target contracts cannot force this call to run out of gas by returning a very large // amount of data (and this is OK because we don't care about the returndata here). // 2. The amount of gas provided to the execution context of the target is at least the // gas limit specified by the user. If there is not enough gas in the current context // to accomplish this, `callWithMinGas` will revert. bool success = SafeCall.callWithMinGas( _tx.target, _tx.gasLimit, _tx.value, _tx.data ); // Reset the l2Sender back to the default value. l2Sender = Constants.DEFAULT_L2_SENDER; // All withdrawals are immediately finalized. Replayability can // be achieved through contracts built on top of this contract emit WithdrawalFinalized(withdrawalHash, success); // Reverting here is useful for determining the exact gas cost to successfully execute the // sub call to the target contract if the minimum gas limit specified by the user would not // be sufficient to execute the sub call. if (success == false && tx.origin == Constants.ESTIMATION_ADDRESS) { revert("MorphPortal: withdrawal failed"); } } /** * @notice Accepts deposits of ETH and data, and emits a TransactionDeposited event for use in * deriving deposit transactions. Note that if a deposit is made by a contract, its * address will be aliased when retrieved using `tx.origin` or `msg.sender`. Consider * using the CrossDomainMessenger contracts for a simpler developer experience. * * @param _to Target address on L2. * @param _value ETH value to send to the recipient. * @param _gasLimit Minimum L2 gas limit (can be greater than or equal to this value). * @param _isCreation Whether or not the transaction is a contract creation. * @param _data Data to trigger the recipient with. */ function depositTransaction( address _to, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes calldata _data ) public payable metered(_gasLimit) onlyMessenger { // Just to be safe, make sure that people specify address(0) as the target when doing // contract creations. if (_isCreation) { require( _to == address(0), "MorphPortal: must send to address(0) when creating a contract" ); } // Prevent depositing transactions that have too small of a gas limit. Users should pay // more for more resource usage. require( _gasLimit >= minimumGasLimit(uint64(_data.length)), "MorphPortal: gas limit too small" ); // Prevent the creation of deposit transactions that have too much calldata. This gives an // upper limit on the size of unsafe blocks over the p2p network. 120kb is chosen to ensure // that the transaction can fit into the p2p network policy of 128kb even though deposit // transactions are not gossipped over the p2p network. require(_data.length <= 120_000, "MorphPortal: data too large"); address from = AddressAliasHelper.applyL1ToL2Alias(msg.sender); _queueTransaction(from, _to, _value, _gasLimit, _data); // Compute the opaque data that will be emitted as part of the TransactionDeposited event. // We use opaque data so that we can update the TransactionDeposited event in the future // without breaking the current interface. bytes memory opaqueData = abi.encodePacked( msg.value, _value, _gasLimit, _isCreation, _data ); // Emit a TransactionDeposited event so that the rollup node can derive a deposit // transaction for this deposit. emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); } function popCrossDomainMessage( uint256 _startIndex, uint256 _count, uint256 _skippedBitmap ) external onlyRollup { _popCrossDomainMessage(_startIndex, _count, _skippedBitmap); } function appendEnforcedTransaction( address _sender, address _target, uint256 _value, uint256 _gasLimit, bytes calldata _data ) external onlyMessenger { require(_sender.code.length == 0, "only EOA"); _queueTransaction(_sender, _target, _value, _gasLimit, _data); } function dropCrossDomainMessage(uint256 _index) external onlyMessenger { _dropCrossDomainMessage(_index); } /** * @notice Determines whether the finalization period has elapsed w/r/t a given timestamp. * * @param _timestamp Timestamp to check. * * @return Whether or not the finalization period has elapsed. */ function _isFinalizationPeriodElapsed( uint256 _timestamp ) internal view returns (bool) { return block.timestamp > _timestamp + ROLLUP.FINALIZATION_PERIOD_SECONDS(); } // @inheritdoc IL1MessageQueue function getCrossDomainMessage( uint256 _queueIndex ) external view returns (bytes32) { return messageQueue[_queueIndex]; } }
[{"inputs":[{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"bool","name":"_paused","type":"bool"},{"internalType":"contract SystemConfig","name":"_config","type":"address"},{"internalType":"contract Rollup","name":"_rollup","type":"address"},{"internalType":"address","name":"_l1Messenger","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"skippedBitmap","type":"uint256"}],"name":"DequeueTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"DropTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"queueIndex","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"QueueTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"opaqueData","type":"bytes"}],"name":"TransactionDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"WithdrawalFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawalProven","type":"event"},{"inputs":[],"name":"GUARDIAN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLLUP","outputs":[{"internalType":"contract Rollup","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SYSTEM_CONFIG","outputs":[{"internalType":"contract SystemConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"appendEnforcedTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint256","name":"_queueIndex","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"computeTransactionHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_gasLimit","type":"uint64"},{"internalType":"bool","name":"_isCreation","type":"bool"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"depositTransaction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"dropCrossDomainMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"}],"name":"finalizeWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"finalizedWithdrawals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueIndex","type":"uint256"}],"name":"getCrossDomainMessage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"},{"internalType":"address","name":"_l1Messenger","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueIndex","type":"uint256"}],"name":"isMessageDropped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueIndex","type":"uint256"}],"name":"isMessageSkipped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1Messenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2Sender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"messageQueue","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_byteCount","type":"uint64"}],"name":"minimumGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextCrossDomainMessageIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"params","outputs":[{"internalType":"uint128","name":"prevBaseFee","type":"uint128"},{"internalType":"uint64","name":"prevBoughtGas","type":"uint64"},{"internalType":"uint64","name":"prevBlockNum","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingQueueIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startIndex","type":"uint256"},{"internalType":"uint256","name":"_count","type":"uint256"},{"internalType":"uint256","name":"_skippedBitmap","type":"uint256"}],"name":"popCrossDomainMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"},{"internalType":"bytes32[32]","name":"_withdrawalProof","type":"bytes32[32]"},{"internalType":"bytes32","name":"_withdrawalRoot","type":"bytes32"}],"name":"proveWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"provenWithdrawals","outputs":[{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"withdrawalIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"leafHash","type":"bytes32"},{"internalType":"bytes32[32]","name":"smtProof","type":"bytes32[32]"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"verifyMerkleProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101406040523480156200001257600080fd5b5060405162003e7138038062003e718339810160408190526200003591620002ae565b6001608052600660a052600060c0526001600160a01b038086166101005283811660e0528216610120526200006b848262000076565b505050505062000332565b600054610100900460ff1615808015620000975750600054600160ff909116105b80620000c75750620000b430620001e360201b62001e191760201c565b158015620000c7575060005460ff166001145b620001305760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562000154576000805461ff0019166101001790555b6036805461dead6001600160a01b031991821617909155603a805460ff1916851515179055603780549091166001600160a01b03841617905562000197620001f2565b8015620001de576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6001600160a01b03163b151590565b600054610100900460ff166200025f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162000127565b60408051606081018252633b9aca0080825260006020830152436001600160401b031691909201819052600160c01b0217600155565b6001600160a01b0381168114620002ab57600080fd5b50565b600080600080600060a08688031215620002c757600080fd5b8551620002d48162000295565b60208701519095508015158114620002eb57600080fd5b6040870151909450620002fe8162000295565b6060870151909350620003118162000295565b6080870151909250620003248162000295565b809150509295509295909350565b60805160a05160c05160e0516101005161012051613ab7620003ba6000396000818161041f01528181610989015281816111ac015281816112ce0152818161180f0152612170015260008181610336015281816107d80152610c4901526000818161064a01526128d401526000610927015260006108fe015260006108d50152613ab76000f3fe6080604052600436106101b75760003560e01c806391652461116100ec578063ae453cd51161008a578063e965084c11610064578063e965084c146105ce578063e9e05c4214610625578063f049875014610638578063fd0ad31e1461066c57600080fd5b8063ae453cd5146104ed578063bdc6f0a01461050d578063cff0ab961461052d57600080fd5b80639bf62d82116100c65780639bf62d8214610441578063a14238e71461046e578063a35d99df1461049e578063a85006ca146104d757600080fd5b806391652461146103cd57806394aeecd5146103ed5780639611c5c21461040d57600080fd5b80635c975abb116101595780637d82191a116101335780637d82191a146103585780638456cb591461037857806385ee7ba61461038d5780638c3152e9146103ad57600080fd5b80635c975abb146102b85780636140e0e6146102d2578063724c184c1461032457600080fd5b80633f4ba83a116101955780633f4ba83a1461023f57806354fd4d501461025657806355f613ce146102785780635ad9945a1461029857600080fd5b806329aa604b146101bc578063340735f7146101ef5780633e6dada11461021f575b600080fd5b3480156101c857600080fd5b506101dc6101d7366004612f73565b610681565b6040519081526020015b60405180910390f35b3480156101fb57600080fd5b5061020f61020a366004612f9e565b6106a2565b60405190151581526020016101e6565b34801561022b57600080fd5b5061020f61023a366004612f73565b610776565b34801561024b57600080fd5b506102546107c0565b005b34801561026257600080fd5b5061026b6108ce565b6040516101e6919061304b565b34801561028457600080fd5b5061025461029336600461305e565b610971565b3480156102a457600080fd5b506101dc6102b33660046130f7565b610a06565b3480156102c457600080fd5b50603a5461020f9060ff1681565b3480156102de57600080fd5b506037546102ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e6565b34801561033057600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561036457600080fd5b5061020f610373366004612f73565b610bfb565b34801561038457600080fd5b50610254610c31565b34801561039957600080fd5b506102546103a8366004613189565b610d36565b3480156103b957600080fd5b506102546103c8366004613360565b610f2c565b3480156103d957600080fd5b506102546103e8366004612f73565b611594565b3480156103f957600080fd5b50610254610408366004613395565b61162d565b34801561041957600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561044d57600080fd5b506036546102ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561047a57600080fd5b5061020f610489366004612f73565b60386020526000908152604090205460ff1681565b3480156104aa57600080fd5b506104be6104b9366004613407565b611a1c565b60405167ffffffffffffffff90911681526020016101e6565b3480156104e357600080fd5b506101dc60335481565b3480156104f957600080fd5b506101dc610508366004612f73565b611a35565b34801561051957600080fd5b50610254610528366004613422565b611a5c565b34801561053957600080fd5b50600154610595906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff92831660208501529116908201526060016101e6565b3480156105da57600080fd5b5061060a6105e9366004612f73565b60396020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016101e6565b61025461063336600461349a565b611b5c565b34801561064457600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561067857600080fd5b506032546101dc565b6032818154811061069157600080fd5b600091825260209091200154905081565b600084815b602081101561076a578085901c60011660010361070d578581602081106106d0576106d06134fb565b6020020135826040516020016106f0929190918252602082015260400190565b604051602081830303815290604052805190602001209150610758565b81868260208110610720576107206134fb565b602002013560405160200161073f929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b8061076281613559565b9150506106a7565b50909114949350505050565b600881901c600090815260356020526040812054600160ff84161b16151580156107ba5750600882901c600090815260346020526040902054600160ff84161b1615155b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108705760405162461bcd60e51b815260206004820152602660248201527f4d6f727068506f7274616c3a206f6e6c7920677561726469616e2063616e207560448201527f6e7061757365000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606108f97f0000000000000000000000000000000000000000000000000000000000000000611e35565b6109227f0000000000000000000000000000000000000000000000000000000000000000611e35565b61094b7f0000000000000000000000000000000000000000000000000000000000000000611e35565b60405160200161095d93929190613591565b604051602081830303815290604052905090565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146109f65760405162461bcd60e51b815260206004820152601f60248201527f524f4c4c555020636f6e747261637420756e61757468656e74696361746564006044820152606401610867565b610a01838383611ef3565b505050565b6000607e81610ab2565b600081610a1f57506001919050565b5b8115610a355760089190911c90600101610a20565b919050565b806080831060018114610a7257610a5084610a10565b60808101835360018301925084816020036008021b8352808301925050610a93565b8484151660018114610a8657848353610a8b565b608083535b506001820191505b509392505050565b806094815360609290921b60018301525060150190565b60056040510180610ac560018c83610a3a565b9050610ad360018983610a3a565b9050610adf8982610a9b565b9050610aed60018b83610a3a565b90506001861460018114610b55576038871060018114610b3a57610b1088610a10565b8060b701845360018401935088816020036008021b84528084019350508789843791870191610b4f565b87608001835360018301925087898437918701915b50610b68565b610b656000893560001a84610a3a565b91505b50610b738c82610a9b565b90508181036000806038831060018114610ba757610b9084610a10565b60f78101600882021b851793506001019150610bb2565b8360c0019250600191505b5086816008021b821791506001810190508060080292508451831c8284610100031b17915080850394505080845250508181038220925050508092505050979650505050505050565b60006033548210610c0e57506000919050565b600882901c600090815260356020526040902054600160ff84161b1615156107ba565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cdb5760405162461bcd60e51b8152602060048201526024808201527f4d6f727068506f7274616c3a206f6e6c7920677561726469616e2063616e207060448201527f61757365000000000000000000000000000000000000000000000000000000006064820152608401610867565b603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016108c4565b600054610100900460ff1615808015610d565750600054600160ff909116105b80610d705750303b158015610d70575060005460ff166001145b610de25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610867565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610e4057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6036805461dead7fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515151790556037805490911673ffffffffffffffffffffffffffffffffffffffff8416179055610ec4612056565b8015610a0157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a1505050565b603a5460ff1615610f7f5760405162461bcd60e51b815260206004820152601360248201527f4d6f727068506f7274616c3a20706175736564000000000000000000000000006044820152606401610867565b60365473ffffffffffffffffffffffffffffffffffffffff1661dead1461100e5760405162461bcd60e51b815260206004820152603c60248201527f4d6f727068506f7274616c3a2063616e206f6e6c792074726967676572206f6e60448201527f65207769746864726177616c20706572207472616e73616374696f6e000000006064820152608401610867565b60006110198261211f565b600081815260396020908152604080832081516060810183528154815260018201549381018490526002909101549181019190915292935090036110c55760405162461bcd60e51b815260206004820152602f60248201527f4d6f727068506f7274616c3a207769746864726177616c20686173206e6f742060448201527f6265656e2070726f76656e2079657400000000000000000000000000000000006064820152608401610867565b6110d2816020015161216c565b61116a5760405162461bcd60e51b815260206004820152604260248201527f4d6f727068506f7274616c3a2070726f76656e207769746864726177616c206660448201527f696e616c697a6174696f6e20706572696f6420686173206e6f7420656c61707360648201527f6564000000000000000000000000000000000000000000000000000000000000608482015260a401610867565b80516040517f04d7721500000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916304d77215916111e39160040190815260200190565b602060405180830381865afa158015611200573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112249190613607565b90506000811161129c5760405162461bcd60e51b815260206004820152602960248201527f4d6f727068506f7274616c3a20646f206e6f74207375626d697420776974686460448201527f726177616c526f6f7400000000000000000000000000000000000000000000006064820152608401610867565b6040517f2571098d000000000000000000000000000000000000000000000000000000008152600481018290526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632571098d90602401602060405180830381865afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190613607565b90508061139d5760405162461bcd60e51b815260206004820152601260248201527f6261746368206e6f7420766572696669656400000000000000000000000000006044820152606401610867565b60008481526038602052604090205460ff16156114225760405162461bcd60e51b815260206004820152603260248201527f4d6f727068506f7274616c3a207769746864726177616c2068617320616c726560448201527f616479206265656e2066696e616c697a656400000000000000000000000000006064820152608401610867565b600084815260386020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908701516036805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558601516080870151606088015160a08901516114c49392919061220f565b603680547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915085907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b9061152990841515815260200190565b60405180910390a28015801561153f5750326001145b1561158c5760405162461bcd60e51b815260206004820152601e60248201527f4d6f727068506f7274616c3a207769746864726177616c206661696c656400006044820152606401610867565b505050505050565b60375473ffffffffffffffffffffffffffffffffffffffff1633146116215760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b61162a8161226d565b50565b603a5460ff16156116805760405162461bcd60e51b815260206004820152601360248201527f4d6f727068506f7274616c3a20706175736564000000000000000000000000006044820152606401610867565b3073ffffffffffffffffffffffffffffffffffffffff16836040015173ffffffffffffffffffffffffffffffffffffffff16036117255760405162461bcd60e51b815260206004820152603c60248201527f4d6f727068506f7274616c3a20796f752063616e6e6f742073656e64206d657360448201527f736167657320746f2074686520706f7274616c20636f6e7472616374000000006064820152608401610867565b60006117308461211f565b60008181526039602090815260409182902082516060810184528154815260018201549281018390526002909101549281019290925291925090156117dd5760405162461bcd60e51b815260206004820152603460248201527f4d6f727068506f7274616c3a207769746864726177616c20686173682068617360448201527f20616c7265616479206265656e2070726f76656e0000000000000000000000006064820152608401610867565b6040517f04d77215000000000000000000000000000000000000000000000000000000008152600481018490526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906304d7721590602401602060405180830381865afa15801561186b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188f9190613607565b9050600081116119075760405162461bcd60e51b815260206004820152602960248201527f4d6f727068506f7274616c3a20646f206e6f74207375626d697420776974686460448201527f726177616c526f6f7400000000000000000000000000000000000000000000006064820152608401610867565b61191783868860000151876106a2565b6119895760405162461bcd60e51b815260206004820152602f60248201527f4d6f727068506f7274616c3a20696e76616c6964207769746864726177616c2060448201527f696e636c7573696f6e2070726f6f6600000000000000000000000000000000006064820152608401610867565b6040805160608101825285815242602080830191825289518385019081526000888152603983528581209451855592516001850155516002909301929092558883015191890151925173ffffffffffffffffffffffffffffffffffffffff928316939092169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f6291a4505050505050565b6000611a29826010613620565b6107ba90615208613650565b600060328281548110611a4a57611a4a6134fb565b90600052602060002001549050919050565b60375473ffffffffffffffffffffffffffffffffffffffff163314611ae95760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b73ffffffffffffffffffffffffffffffffffffffff86163b15611b4e5760405162461bcd60e51b815260206004820152600860248201527f6f6e6c7920454f410000000000000000000000000000000000000000000000006044820152606401610867565b61158c8686868686866123e4565b8360005a60375490915073ffffffffffffffffffffffffffffffffffffffff163314611bf05760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b8415611c805773ffffffffffffffffffffffffffffffffffffffff881615611c805760405162461bcd60e51b815260206004820152603d60248201527f4d6f727068506f7274616c3a206d7573742073656e6420746f2061646472657360448201527f73283029207768656e206372656174696e67206120636f6e74726163740000006064820152608401610867565b611c8983611a1c565b67ffffffffffffffff168667ffffffffffffffff161015611cec5760405162461bcd60e51b815260206004820181905260248201527f4d6f727068506f7274616c3a20676173206c696d697420746f6f20736d616c6c6044820152606401610867565b6201d4c0831115611d3f5760405162461bcd60e51b815260206004820152601b60248201527f4d6f727068506f7274616c3a206461746120746f6f206c6172676500000000006044820152606401610867565b3373111100000000000000000000000000000000111101611d6e818a8a67ffffffffffffffff8b1689896123e4565b6000348989898989604051602001611d8b96959493929190613678565b604051602081830303815290604052905060008a73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c3284604051611dfb919061304b565b60405180910390a45050611e0f8282612497565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60606000611e42836127a0565b600101905060008167ffffffffffffffff811115611e6257611e626131bc565b6040519080825280601f01601f191660200182016040528015611e8c576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084611e9657509392505050565b610100821115611f455760405162461bcd60e51b815260206004820152601560248201527f706f7020746f6f206d616e79206d6573736167657300000000000000000000006044820152606401610867565b8260335414611f965760405162461bcd60e51b815260206004820152601460248201527f737461727420696e646578206d69736d617463680000000000000000000000006044820152606401610867565b600883901c600081815260356020526040902080546001851b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0193841660ff871681811b90921790925590929190610100818601111561200f5760018201600090815260356020526040902061010082900385901c90555b50505081830160335560408051848152602081018490529081018290527fc77f792f838ae38399ac31acc3348389aeb110ce7bedf3cfdbdd5e667926797090606001610f1f565b600054610100900460ff166120d35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610867565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b80516020808301516040808501516060860151608087015160a0880151935160009761214f979096959101613700565b604051602081830303815290604052805190602001209050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fd9190613607565b6122079083613757565b421192915050565b600080600061221f866000612882565b905080612255576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080855160208701888b5af1979650505050505050565b60335481106122be5760405162461bcd60e51b815260206004820152601b60248201527f63616e6e6f742064726f702070656e64696e67206d65737361676500000000006044820152606401610867565b600881901c600090815260356020526040902054600160ff83161b166123265760405162461bcd60e51b815260206004820152601860248201527f64726f70206e6f6e2d736b6970706564206d65737361676500000000000000006044820152606401610867565b600881901c600090815260346020526040902054600160ff83161b161561238f5760405162461bcd60e51b815260206004820152601760248201527f6d65737361676520616c72656164792064726f707065640000000000000000006044820152606401610867565b600881901c60009081526034602052604090208054600160ff84161b1790556040518181527f43a375005206d20a83abc71722cba68c24434a8dc1f583775be7c3fde0396cbf9060200160405180910390a150565b60325460006123f88883888a898989610a06565b603280546001810182556000919091527f11df491316f14931039edfd4f8964c9a443b862f02d4c7611d18c2bc4e6ff6970181905560405190915073ffffffffffffffffffffffffffffffffffffffff80891691908a16907f69cfcb8e6d4192b8aba9902243912587f37e550d75c1fa801491fce26717f37e90612485908a9087908b908b908b9061376a565b60405180910390a35050505050505050565b6001546000906124cd907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16436137d6565b905060006124d96128a0565b90506000816020015160ff16826000015163ffffffff166124fa91906137e9565b9050821561263157600154600090612531908390700100000000000000000000000000000000900467ffffffffffffffff16613851565b90506000836040015160ff16836125489190613871565b6001546125689084906fffffffffffffffffffffffffffffffff16613871565b61257291906137e9565b6001549091506000906125c39061259c9084906fffffffffffffffffffffffffffffffff1661392d565b866060015163ffffffff168760a001516fffffffffffffffffffffffffffffffff16612966565b905060018611156125f2576125ef61259c82876040015160ff1660018a6125ea91906137d6565b612983565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b60018054869190601090612664908490700100000000000000000000000000000000900467ffffffffffffffff16613650565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550816000015163ffffffff16600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff16131561272d5760405162461bcd60e51b815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610867565b600154600090612759906fffffffffffffffffffffffffffffffff1667ffffffffffffffff8816613955565b9050600061276b48633b9aca006129d8565b6127759083613992565b905060005a61278490886137d6565b905080821115611e0f57611e0f61279b82846137d6565b6129f0565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106127e9577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612815576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061283357662386f26fc10000830492506010015b6305f5e100831061284b576305f5e100830492506008015b612710831061285f57612710830492506004015b60648310612871576064830492506002015b600a83106107ba5760010192915050565b600080603f83619c4001026040850201603f5a021015949350505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cc731b026040518163ffffffff1660e01b815260040160c060405180830381865afa15801561293d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296191906139cb565b905090565b600061297b6129758585612a19565b83612a28565b949350505050565b6000670de0b6b3a76400006129c461299b85836137e9565b6129ad90670de0b6b3a7640000613851565b6129bf85670de0b6b3a7640000613871565b612a37565b6129ce9086613871565b61297b91906137e9565b60008183116129e757816129e9565b825b9392505050565b6000805a90505b825a612a0390836137d6565b1015610a0157612a1282613559565b91506129f7565b60008183136129e757816129e9565b60008183126129e757816129e9565b60006129e9670de0b6b3a764000083612a4f86612a68565b612a599190613871565b612a6391906137e9565b612c92565b6000808213612ab95760405162461bcd60e51b815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610867565b60006060612ac684612eb7565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c18213612cc357506000919050565b680755bf798b4a1bf1e58212612d1b5760405162461bcd60e51b815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610867565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6000808211612f085760405162461bcd60e51b815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610867565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b600060208284031215612f8557600080fd5b5035919050565b8061040081018310156107ba57600080fd5b6000806000806104608587031215612fb557600080fd5b84359350612fc68660208701612f8c565b939693955050505061042082013591610440013590565b60005b83811015612ff8578181015183820152602001612fe0565b50506000910152565b60008151808452613019816020860160208601612fdd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006129e96020830184613001565b60008060006060848603121561307357600080fd5b505081359360208301359350604090920135919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a3557600080fd5b60008083601f8401126130c057600080fd5b50813567ffffffffffffffff8111156130d857600080fd5b6020830191508360208285010111156130f057600080fd5b9250929050565b600080600080600080600060c0888a03121561311257600080fd5b61311b8861308a565b965060208801359550604088013594506131376060890161308a565b93506080880135925060a088013567ffffffffffffffff81111561315a57600080fd5b6131668a828b016130ae565b989b979a50959850939692959293505050565b80358015158114610a3557600080fd5b6000806040838503121561319c57600080fd5b6131a583613179565b91506131b36020840161308a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561320e5761320e6131bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561325b5761325b6131bc565b604052919050565b600060c0828403121561327557600080fd5b61327d6131eb565b905081358152602061329081840161308a565b818301526132a06040840161308a565b6040830152606083013560608301526080830135608083015260a083013567ffffffffffffffff808211156132d457600080fd5b818501915085601f8301126132e857600080fd5b8135818111156132fa576132fa6131bc565b61332a847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613214565b9150808252868482850101111561334057600080fd5b80848401858401376000848284010152508060a085015250505092915050565b60006020828403121561337257600080fd5b813567ffffffffffffffff81111561338957600080fd5b61297b84828501613263565b600080600061044084860312156133ab57600080fd5b833567ffffffffffffffff8111156133c257600080fd5b6133ce86828701613263565b9350506133de8560208601612f8c565b915061042084013590509250925092565b803567ffffffffffffffff81168114610a3557600080fd5b60006020828403121561341957600080fd5b6129e9826133ef565b60008060008060008060a0878903121561343b57600080fd5b6134448761308a565b95506134526020880161308a565b94506040870135935060608701359250608087013567ffffffffffffffff81111561347c57600080fd5b61348889828a016130ae565b979a9699509497509295939492505050565b60008060008060008060a087890312156134b357600080fd5b6134bc8761308a565b9550602087013594506134d1604088016133ef565b93506134df60608801613179565b9250608087013567ffffffffffffffff81111561347c57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361358a5761358a61352a565b5060010190565b600084516135a3818460208901612fdd565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516135df816001850160208a01612fdd565b600192019182015283516135fa816002840160208801612fdd565b0160020195945050505050565b60006020828403121561361957600080fd5b5051919050565b600067ffffffffffffffff808316818516818304811182151516156136475761364761352a565b02949350505050565b67ffffffffffffffff8181168382160190808211156136715761367161352a565b5092915050565b8681528560208201527fffffffffffffffff0000000000000000000000000000000000000000000000008560c01b16604082015283151560f81b6048820152818360498301376000910160490190815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261374b60c0830184613001565b98975050505050505050565b808201808211156107ba576107ba61352a565b85815267ffffffffffffffff8516602082015283604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101949350505050565b818103818111156107ba576107ba61352a565b6000826137f8576137f86136d1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561384c5761384c61352a565b500590565b81810360008312801583831316838312821617156136715761367161352a565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156138b2576138b261352a565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156138ed576138ed61352a565b600087129250878205871284841616156139095761390961352a565b8785058712818416161561391f5761391f61352a565b505050929093029392505050565b808201828112600083128015821682158216171561394d5761394d61352a565b505092915050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561398d5761398d61352a565b500290565b6000826139a1576139a16136d1565b500490565b805163ffffffff81168114610a3557600080fd5b805160ff81168114610a3557600080fd5b600060c082840312156139dd57600080fd5b60405160c0810181811067ffffffffffffffff82111715613a0057613a006131bc565b604052613a0c836139a6565b8152613a1a602084016139ba565b6020820152613a2b604084016139ba565b6040820152613a3c606084016139a6565b6060820152613a4d608084016139a6565b608082015260a08301516fffffffffffffffffffffffffffffffff81168114613a7557600080fd5b60a0820152939250505056fea2646970667358221220783ce1cf18c9f745c75d43dcdec745f05370389e8e6190af40a072a1cddacf5c64736f6c6343000810003300000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e57000000000000000000000000000000000000000000000000000000000000000010000000000000000000000002cebeb054efbbbe86f0c9f6414d0044d42609ff60000000000000000000000009672010622c9511127b56028465afd1d8ecabc65000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
Deployed Bytecode
0x6080604052600436106101b75760003560e01c806391652461116100ec578063ae453cd51161008a578063e965084c11610064578063e965084c146105ce578063e9e05c4214610625578063f049875014610638578063fd0ad31e1461066c57600080fd5b8063ae453cd5146104ed578063bdc6f0a01461050d578063cff0ab961461052d57600080fd5b80639bf62d82116100c65780639bf62d8214610441578063a14238e71461046e578063a35d99df1461049e578063a85006ca146104d757600080fd5b806391652461146103cd57806394aeecd5146103ed5780639611c5c21461040d57600080fd5b80635c975abb116101595780637d82191a116101335780637d82191a146103585780638456cb591461037857806385ee7ba61461038d5780638c3152e9146103ad57600080fd5b80635c975abb146102b85780636140e0e6146102d2578063724c184c1461032457600080fd5b80633f4ba83a116101955780633f4ba83a1461023f57806354fd4d501461025657806355f613ce146102785780635ad9945a1461029857600080fd5b806329aa604b146101bc578063340735f7146101ef5780633e6dada11461021f575b600080fd5b3480156101c857600080fd5b506101dc6101d7366004612f73565b610681565b6040519081526020015b60405180910390f35b3480156101fb57600080fd5b5061020f61020a366004612f9e565b6106a2565b60405190151581526020016101e6565b34801561022b57600080fd5b5061020f61023a366004612f73565b610776565b34801561024b57600080fd5b506102546107c0565b005b34801561026257600080fd5b5061026b6108ce565b6040516101e6919061304b565b34801561028457600080fd5b5061025461029336600461305e565b610971565b3480156102a457600080fd5b506101dc6102b33660046130f7565b610a06565b3480156102c457600080fd5b50603a5461020f9060ff1681565b3480156102de57600080fd5b506037546102ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e6565b34801561033057600080fd5b506102ff7f00000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e57081565b34801561036457600080fd5b5061020f610373366004612f73565b610bfb565b34801561038457600080fd5b50610254610c31565b34801561039957600080fd5b506102546103a8366004613189565b610d36565b3480156103b957600080fd5b506102546103c8366004613360565b610f2c565b3480156103d957600080fd5b506102546103e8366004612f73565b611594565b3480156103f957600080fd5b50610254610408366004613395565b61162d565b34801561041957600080fd5b506102ff7f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6581565b34801561044d57600080fd5b506036546102ff9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561047a57600080fd5b5061020f610489366004612f73565b60386020526000908152604090205460ff1681565b3480156104aa57600080fd5b506104be6104b9366004613407565b611a1c565b60405167ffffffffffffffff90911681526020016101e6565b3480156104e357600080fd5b506101dc60335481565b3480156104f957600080fd5b506101dc610508366004612f73565b611a35565b34801561051957600080fd5b50610254610528366004613422565b611a5c565b34801561053957600080fd5b50600154610595906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff92831660208501529116908201526060016101e6565b3480156105da57600080fd5b5061060a6105e9366004612f73565b60396020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016101e6565b61025461063336600461349a565b611b5c565b34801561064457600080fd5b506102ff7f0000000000000000000000002cebeb054efbbbe86f0c9f6414d0044d42609ff681565b34801561067857600080fd5b506032546101dc565b6032818154811061069157600080fd5b600091825260209091200154905081565b600084815b602081101561076a578085901c60011660010361070d578581602081106106d0576106d06134fb565b6020020135826040516020016106f0929190918252602082015260400190565b604051602081830303815290604052805190602001209150610758565b81868260208110610720576107206134fb565b602002013560405160200161073f929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b8061076281613559565b9150506106a7565b50909114949350505050565b600881901c600090815260356020526040812054600160ff84161b16151580156107ba5750600882901c600090815260346020526040902054600160ff84161b1615155b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e57016146108705760405162461bcd60e51b815260206004820152602660248201527f4d6f727068506f7274616c3a206f6e6c7920677561726469616e2063616e207560448201527f6e7061757365000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606108f97f0000000000000000000000000000000000000000000000000000000000000001611e35565b6109227f0000000000000000000000000000000000000000000000000000000000000006611e35565b61094b7f0000000000000000000000000000000000000000000000000000000000000000611e35565b60405160200161095d93929190613591565b604051602081830303815290604052905090565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6516146109f65760405162461bcd60e51b815260206004820152601f60248201527f524f4c4c555020636f6e747261637420756e61757468656e74696361746564006044820152606401610867565b610a01838383611ef3565b505050565b6000607e81610ab2565b600081610a1f57506001919050565b5b8115610a355760089190911c90600101610a20565b919050565b806080831060018114610a7257610a5084610a10565b60808101835360018301925084816020036008021b8352808301925050610a93565b8484151660018114610a8657848353610a8b565b608083535b506001820191505b509392505050565b806094815360609290921b60018301525060150190565b60056040510180610ac560018c83610a3a565b9050610ad360018983610a3a565b9050610adf8982610a9b565b9050610aed60018b83610a3a565b90506001861460018114610b55576038871060018114610b3a57610b1088610a10565b8060b701845360018401935088816020036008021b84528084019350508789843791870191610b4f565b87608001835360018301925087898437918701915b50610b68565b610b656000893560001a84610a3a565b91505b50610b738c82610a9b565b90508181036000806038831060018114610ba757610b9084610a10565b60f78101600882021b851793506001019150610bb2565b8360c0019250600191505b5086816008021b821791506001810190508060080292508451831c8284610100031b17915080850394505080845250508181038220925050508092505050979650505050505050565b60006033548210610c0e57506000919050565b600882901c600090815260356020526040902054600160ff84161b1615156107ba565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e5701614610cdb5760405162461bcd60e51b8152602060048201526024808201527f4d6f727068506f7274616c3a206f6e6c7920677561726469616e2063616e207060448201527f61757365000000000000000000000000000000000000000000000000000000006064820152608401610867565b603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016108c4565b600054610100900460ff1615808015610d565750600054600160ff909116105b80610d705750303b158015610d70575060005460ff166001145b610de25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610867565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610e4057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6036805461dead7fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155603a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515151790556037805490911673ffffffffffffffffffffffffffffffffffffffff8416179055610ec4612056565b8015610a0157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a1505050565b603a5460ff1615610f7f5760405162461bcd60e51b815260206004820152601360248201527f4d6f727068506f7274616c3a20706175736564000000000000000000000000006044820152606401610867565b60365473ffffffffffffffffffffffffffffffffffffffff1661dead1461100e5760405162461bcd60e51b815260206004820152603c60248201527f4d6f727068506f7274616c3a2063616e206f6e6c792074726967676572206f6e60448201527f65207769746864726177616c20706572207472616e73616374696f6e000000006064820152608401610867565b60006110198261211f565b600081815260396020908152604080832081516060810183528154815260018201549381018490526002909101549181019190915292935090036110c55760405162461bcd60e51b815260206004820152602f60248201527f4d6f727068506f7274616c3a207769746864726177616c20686173206e6f742060448201527f6265656e2070726f76656e2079657400000000000000000000000000000000006064820152608401610867565b6110d2816020015161216c565b61116a5760405162461bcd60e51b815260206004820152604260248201527f4d6f727068506f7274616c3a2070726f76656e207769746864726177616c206660448201527f696e616c697a6174696f6e20706572696f6420686173206e6f7420656c61707360648201527f6564000000000000000000000000000000000000000000000000000000000000608482015260a401610867565b80516040517f04d7721500000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6516916304d77215916111e39160040190815260200190565b602060405180830381865afa158015611200573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112249190613607565b90506000811161129c5760405162461bcd60e51b815260206004820152602960248201527f4d6f727068506f7274616c3a20646f206e6f74207375626d697420776974686460448201527f726177616c526f6f7400000000000000000000000000000000000000000000006064820152608401610867565b6040517f2571098d000000000000000000000000000000000000000000000000000000008152600481018290526000907f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6573ffffffffffffffffffffffffffffffffffffffff1690632571098d90602401602060405180830381865afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190613607565b90508061139d5760405162461bcd60e51b815260206004820152601260248201527f6261746368206e6f7420766572696669656400000000000000000000000000006044820152606401610867565b60008481526038602052604090205460ff16156114225760405162461bcd60e51b815260206004820152603260248201527f4d6f727068506f7274616c3a207769746864726177616c2068617320616c726560448201527f616479206265656e2066696e616c697a656400000000000000000000000000006064820152608401610867565b600084815260386020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908701516036805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558601516080870151606088015160a08901516114c49392919061220f565b603680547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915085907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b9061152990841515815260200190565b60405180910390a28015801561153f5750326001145b1561158c5760405162461bcd60e51b815260206004820152601e60248201527f4d6f727068506f7274616c3a207769746864726177616c206661696c656400006044820152606401610867565b505050505050565b60375473ffffffffffffffffffffffffffffffffffffffff1633146116215760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b61162a8161226d565b50565b603a5460ff16156116805760405162461bcd60e51b815260206004820152601360248201527f4d6f727068506f7274616c3a20706175736564000000000000000000000000006044820152606401610867565b3073ffffffffffffffffffffffffffffffffffffffff16836040015173ffffffffffffffffffffffffffffffffffffffff16036117255760405162461bcd60e51b815260206004820152603c60248201527f4d6f727068506f7274616c3a20796f752063616e6e6f742073656e64206d657360448201527f736167657320746f2074686520706f7274616c20636f6e7472616374000000006064820152608401610867565b60006117308461211f565b60008181526039602090815260409182902082516060810184528154815260018201549281018390526002909101549281019290925291925090156117dd5760405162461bcd60e51b815260206004820152603460248201527f4d6f727068506f7274616c3a207769746864726177616c20686173682068617360448201527f20616c7265616479206265656e2070726f76656e0000000000000000000000006064820152608401610867565b6040517f04d77215000000000000000000000000000000000000000000000000000000008152600481018490526000907f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6573ffffffffffffffffffffffffffffffffffffffff16906304d7721590602401602060405180830381865afa15801561186b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188f9190613607565b9050600081116119075760405162461bcd60e51b815260206004820152602960248201527f4d6f727068506f7274616c3a20646f206e6f74207375626d697420776974686460448201527f726177616c526f6f7400000000000000000000000000000000000000000000006064820152608401610867565b61191783868860000151876106a2565b6119895760405162461bcd60e51b815260206004820152602f60248201527f4d6f727068506f7274616c3a20696e76616c6964207769746864726177616c2060448201527f696e636c7573696f6e2070726f6f6600000000000000000000000000000000006064820152608401610867565b6040805160608101825285815242602080830191825289518385019081526000888152603983528581209451855592516001850155516002909301929092558883015191890151925173ffffffffffffffffffffffffffffffffffffffff928316939092169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f6291a4505050505050565b6000611a29826010613620565b6107ba90615208613650565b600060328281548110611a4a57611a4a6134fb565b90600052602060002001549050919050565b60375473ffffffffffffffffffffffffffffffffffffffff163314611ae95760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b73ffffffffffffffffffffffffffffffffffffffff86163b15611b4e5760405162461bcd60e51b815260206004820152600860248201527f6f6e6c7920454f410000000000000000000000000000000000000000000000006044820152606401610867565b61158c8686868686866123e4565b8360005a60375490915073ffffffffffffffffffffffffffffffffffffffff163314611bf05760405162461bcd60e51b815260206004820152602260248201527f6d657373656e67657220636f6e747261637420756e61757468656e746963617460448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610867565b8415611c805773ffffffffffffffffffffffffffffffffffffffff881615611c805760405162461bcd60e51b815260206004820152603d60248201527f4d6f727068506f7274616c3a206d7573742073656e6420746f2061646472657360448201527f73283029207768656e206372656174696e67206120636f6e74726163740000006064820152608401610867565b611c8983611a1c565b67ffffffffffffffff168667ffffffffffffffff161015611cec5760405162461bcd60e51b815260206004820181905260248201527f4d6f727068506f7274616c3a20676173206c696d697420746f6f20736d616c6c6044820152606401610867565b6201d4c0831115611d3f5760405162461bcd60e51b815260206004820152601b60248201527f4d6f727068506f7274616c3a206461746120746f6f206c6172676500000000006044820152606401610867565b3373111100000000000000000000000000000000111101611d6e818a8a67ffffffffffffffff8b1689896123e4565b6000348989898989604051602001611d8b96959493929190613678565b604051602081830303815290604052905060008a73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c3284604051611dfb919061304b565b60405180910390a45050611e0f8282612497565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60606000611e42836127a0565b600101905060008167ffffffffffffffff811115611e6257611e626131bc565b6040519080825280601f01601f191660200182016040528015611e8c576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084611e9657509392505050565b610100821115611f455760405162461bcd60e51b815260206004820152601560248201527f706f7020746f6f206d616e79206d6573736167657300000000000000000000006044820152606401610867565b8260335414611f965760405162461bcd60e51b815260206004820152601460248201527f737461727420696e646578206d69736d617463680000000000000000000000006044820152606401610867565b600883901c600081815260356020526040902080546001851b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0193841660ff871681811b90921790925590929190610100818601111561200f5760018201600090815260356020526040902061010082900385901c90555b50505081830160335560408051848152602081018490529081018290527fc77f792f838ae38399ac31acc3348389aeb110ce7bedf3cfdbdd5e667926797090606001610f1f565b600054610100900460ff166120d35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610867565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b80516020808301516040808501516060860151608087015160a0880151935160009761214f979096959101613700565b604051602081830303815290604052805190602001209050919050565b60007f0000000000000000000000009672010622c9511127b56028465afd1d8ecabc6573ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fd9190613607565b6122079083613757565b421192915050565b600080600061221f866000612882565b905080612255576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080855160208701888b5af1979650505050505050565b60335481106122be5760405162461bcd60e51b815260206004820152601b60248201527f63616e6e6f742064726f702070656e64696e67206d65737361676500000000006044820152606401610867565b600881901c600090815260356020526040902054600160ff83161b166123265760405162461bcd60e51b815260206004820152601860248201527f64726f70206e6f6e2d736b6970706564206d65737361676500000000000000006044820152606401610867565b600881901c600090815260346020526040902054600160ff83161b161561238f5760405162461bcd60e51b815260206004820152601760248201527f6d65737361676520616c72656164792064726f707065640000000000000000006044820152606401610867565b600881901c60009081526034602052604090208054600160ff84161b1790556040518181527f43a375005206d20a83abc71722cba68c24434a8dc1f583775be7c3fde0396cbf9060200160405180910390a150565b60325460006123f88883888a898989610a06565b603280546001810182556000919091527f11df491316f14931039edfd4f8964c9a443b862f02d4c7611d18c2bc4e6ff6970181905560405190915073ffffffffffffffffffffffffffffffffffffffff80891691908a16907f69cfcb8e6d4192b8aba9902243912587f37e550d75c1fa801491fce26717f37e90612485908a9087908b908b908b9061376a565b60405180910390a35050505050505050565b6001546000906124cd907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16436137d6565b905060006124d96128a0565b90506000816020015160ff16826000015163ffffffff166124fa91906137e9565b9050821561263157600154600090612531908390700100000000000000000000000000000000900467ffffffffffffffff16613851565b90506000836040015160ff16836125489190613871565b6001546125689084906fffffffffffffffffffffffffffffffff16613871565b61257291906137e9565b6001549091506000906125c39061259c9084906fffffffffffffffffffffffffffffffff1661392d565b866060015163ffffffff168760a001516fffffffffffffffffffffffffffffffff16612966565b905060018611156125f2576125ef61259c82876040015160ff1660018a6125ea91906137d6565b612983565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b60018054869190601090612664908490700100000000000000000000000000000000900467ffffffffffffffff16613650565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550816000015163ffffffff16600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff16131561272d5760405162461bcd60e51b815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610867565b600154600090612759906fffffffffffffffffffffffffffffffff1667ffffffffffffffff8816613955565b9050600061276b48633b9aca006129d8565b6127759083613992565b905060005a61278490886137d6565b905080821115611e0f57611e0f61279b82846137d6565b6129f0565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106127e9577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612815576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061283357662386f26fc10000830492506010015b6305f5e100831061284b576305f5e100830492506008015b612710831061285f57612710830492506004015b60648310612871576064830492506002015b600a83106107ba5760010192915050565b600080603f83619c4001026040850201603f5a021015949350505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091527f0000000000000000000000002cebeb054efbbbe86f0c9f6414d0044d42609ff673ffffffffffffffffffffffffffffffffffffffff1663cc731b026040518163ffffffff1660e01b815260040160c060405180830381865afa15801561293d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296191906139cb565b905090565b600061297b6129758585612a19565b83612a28565b949350505050565b6000670de0b6b3a76400006129c461299b85836137e9565b6129ad90670de0b6b3a7640000613851565b6129bf85670de0b6b3a7640000613871565b612a37565b6129ce9086613871565b61297b91906137e9565b60008183116129e757816129e9565b825b9392505050565b6000805a90505b825a612a0390836137d6565b1015610a0157612a1282613559565b91506129f7565b60008183136129e757816129e9565b60008183126129e757816129e9565b60006129e9670de0b6b3a764000083612a4f86612a68565b612a599190613871565b612a6391906137e9565b612c92565b6000808213612ab95760405162461bcd60e51b815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610867565b60006060612ac684612eb7565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c18213612cc357506000919050565b680755bf798b4a1bf1e58212612d1b5760405162461bcd60e51b815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610867565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6000808211612f085760405162461bcd60e51b815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610867565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b600060208284031215612f8557600080fd5b5035919050565b8061040081018310156107ba57600080fd5b6000806000806104608587031215612fb557600080fd5b84359350612fc68660208701612f8c565b939693955050505061042082013591610440013590565b60005b83811015612ff8578181015183820152602001612fe0565b50506000910152565b60008151808452613019816020860160208601612fdd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006129e96020830184613001565b60008060006060848603121561307357600080fd5b505081359360208301359350604090920135919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a3557600080fd5b60008083601f8401126130c057600080fd5b50813567ffffffffffffffff8111156130d857600080fd5b6020830191508360208285010111156130f057600080fd5b9250929050565b600080600080600080600060c0888a03121561311257600080fd5b61311b8861308a565b965060208801359550604088013594506131376060890161308a565b93506080880135925060a088013567ffffffffffffffff81111561315a57600080fd5b6131668a828b016130ae565b989b979a50959850939692959293505050565b80358015158114610a3557600080fd5b6000806040838503121561319c57600080fd5b6131a583613179565b91506131b36020840161308a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561320e5761320e6131bc565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561325b5761325b6131bc565b604052919050565b600060c0828403121561327557600080fd5b61327d6131eb565b905081358152602061329081840161308a565b818301526132a06040840161308a565b6040830152606083013560608301526080830135608083015260a083013567ffffffffffffffff808211156132d457600080fd5b818501915085601f8301126132e857600080fd5b8135818111156132fa576132fa6131bc565b61332a847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613214565b9150808252868482850101111561334057600080fd5b80848401858401376000848284010152508060a085015250505092915050565b60006020828403121561337257600080fd5b813567ffffffffffffffff81111561338957600080fd5b61297b84828501613263565b600080600061044084860312156133ab57600080fd5b833567ffffffffffffffff8111156133c257600080fd5b6133ce86828701613263565b9350506133de8560208601612f8c565b915061042084013590509250925092565b803567ffffffffffffffff81168114610a3557600080fd5b60006020828403121561341957600080fd5b6129e9826133ef565b60008060008060008060a0878903121561343b57600080fd5b6134448761308a565b95506134526020880161308a565b94506040870135935060608701359250608087013567ffffffffffffffff81111561347c57600080fd5b61348889828a016130ae565b979a9699509497509295939492505050565b60008060008060008060a087890312156134b357600080fd5b6134bc8761308a565b9550602087013594506134d1604088016133ef565b93506134df60608801613179565b9250608087013567ffffffffffffffff81111561347c57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361358a5761358a61352a565b5060010190565b600084516135a3818460208901612fdd565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516135df816001850160208a01612fdd565b600192019182015283516135fa816002840160208801612fdd565b0160020195945050505050565b60006020828403121561361957600080fd5b5051919050565b600067ffffffffffffffff808316818516818304811182151516156136475761364761352a565b02949350505050565b67ffffffffffffffff8181168382160190808211156136715761367161352a565b5092915050565b8681528560208201527fffffffffffffffff0000000000000000000000000000000000000000000000008560c01b16604082015283151560f81b6048820152818360498301376000910160490190815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261374b60c0830184613001565b98975050505050505050565b808201808211156107ba576107ba61352a565b85815267ffffffffffffffff8516602082015283604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101949350505050565b818103818111156107ba576107ba61352a565b6000826137f8576137f86136d1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561384c5761384c61352a565b500590565b81810360008312801583831316838312821617156136715761367161352a565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156138b2576138b261352a565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156138ed576138ed61352a565b600087129250878205871284841616156139095761390961352a565b8785058712818416161561391f5761391f61352a565b505050929093029392505050565b808201828112600083128015821682158216171561394d5761394d61352a565b505092915050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561398d5761398d61352a565b500290565b6000826139a1576139a16136d1565b500490565b805163ffffffff81168114610a3557600080fd5b805160ff81168114610a3557600080fd5b600060c082840312156139dd57600080fd5b60405160c0810181811067ffffffffffffffff82111715613a0057613a006131bc565b604052613a0c836139a6565b8152613a1a602084016139ba565b6020820152613a2b604084016139ba565b6040820152613a3c606084016139a6565b6060820152613a4d608084016139a6565b608082015260a08301516fffffffffffffffffffffffffffffffff81168114613a7557600080fd5b60a0820152939250505056fea2646970667358221220783ce1cf18c9f745c75d43dcdec745f05370389e8e6190af40a072a1cddacf5c64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e57000000000000000000000000000000000000000000000000000000000000000010000000000000000000000002cebeb054efbbbe86f0c9f6414d0044d42609ff60000000000000000000000009672010622c9511127b56028465afd1d8ecabc65000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
-----Decoded View---------------
Arg [0] : _guardian (address): 0x77778E169A7A162aA0D926B0C1a1C0541Ed9E570
Arg [1] : _paused (bool): True
Arg [2] : _config (address): 0x2cEbEb054efbbbE86F0C9f6414D0044D42609Ff6
Arg [3] : _rollup (address): 0x9672010622C9511127b56028465AFD1D8eCABC65
Arg [4] : _l1Messenger (address): 0xFE26613A717A793560dF394928bcC22Ed0D8542e
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000077778e169a7a162aa0d926b0c1a1c0541ed9e570
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 0000000000000000000000002cebeb054efbbbe86f0c9f6414d0044d42609ff6
Arg [3] : 0000000000000000000000009672010622c9511127b56028465afd1d8ecabc65
Arg [4] : 000000000000000000000000fe26613a717a793560df394928bcc22ed0d8542e
Deployed Bytecode Sourcemap
249097:18869:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;238306:29;;;;;;;;;;-1:-1:-1;238306:29:0;;;;;:::i;:::-;;:::i;:::-;;;345:25:1;;;333:2;318:18;238306:29:0;;;;;;;;133403:523;;;;;;;;;;-1:-1:-1;133403:523:0;;;;;:::i;:::-;;:::i;:::-;;;1163:14:1;;1156:22;1138:41;;1126:2;1111:18;133403:523:0;998:187:1;245688:265:0;;;;;;;;;;-1:-1:-1;245688:265:0;;;;;:::i;:::-;;:::i;254940:218::-;;;;;;;;;;;;;:::i;:::-;;55178:383;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;266609:224::-;;;;;;;;;;-1:-1:-1;266609:224:0;;;;;:::i;:::-;;:::i;240168:5293::-;;;;;;;;;;-1:-1:-1;240168:5293:0;;;;;:::i;:::-;;:::i;251285:18::-;;;;;;;;;;-1:-1:-1;251285:18:0;;;;;;;;250749:26;;;;;;;;;;-1:-1:-1;250749:26:0;;;;;;;;;;;3824:42:1;3812:55;;;3794:74;;3782:2;3767:18;250749:26:0;3648:226:1;250221:33:0;;;;;;;;;;;;;;;245469:211;;;;;;;;;;-1:-1:-1;245469:211:0;;;;;:::i;:::-;;:::i;254653:::-;;;;;;;;;;;;;:::i;254347:232::-;;;;;;;;;;-1:-1:-1;254347:232:0;;;;;:::i;:::-;;:::i;259611:4166::-;;;;;;;;;;-1:-1:-1;259611:4166:0;;;;;:::i;:::-;;:::i;267186:121::-;;;;;;;;;;-1:-1:-1;267186:121:0;;;;;:::i;:::-;;:::i;256478:2992::-;;;;;;;;;;-1:-1:-1;256478:2992:0;;;;;:::i;:::-;;:::i;250329:30::-;;;;;;;;;;;;;;;250635:23;;;;;;;;;;-1:-1:-1;250635:23:0;;;;;;;;250886:52;;;;;;;;;;-1:-1:-1;250886:52:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;255551:122;;;;;;;;;;-1:-1:-1;255551:122:0;;;;;:::i;:::-;;:::i;:::-;;;8214:18:1;8202:31;;;8184:50;;8172:2;8157:18;255551:122:0;8040:200:1;238344:32:0;;;;;;;;;;;;;;;;267812:151;;;;;;;;;;-1:-1:-1;267812:151:0;;;;;:::i;:::-;;:::i;266841:337::-;;;;;;;;;;-1:-1:-1;266841:337:0;;;;;:::i;:::-;;:::i;76770:28::-;;;;;;;;;;-1:-1:-1;76770:28:0;;;;;;;;;;;;;;;;;;;;;;;;;9355:34:1;9343:47;;;9325:66;;9410:18;9464:15;;;9459:2;9444:18;;9437:43;9516:15;;9496:18;;;9489:43;9313:2;9298:18;76770:28:0;9127:411:1;251040:61:0;;;;;;;;;;-1:-1:-1;251040:61:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9745:25:1;;;9801:2;9786:18;;9779:34;;;;9829:18;;;9822:34;9733:2;9718:18;251040:61:0;9543:319:1;264551:2050:0;;;;;;:::i;:::-;;:::i;250072:43::-;;;;;;;;;;;;;;;240044:116;;;;;;;;;;-1:-1:-1;240133:12:0;:19;240044:116;;238306:29;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;238306:29:0;:::o;133403:523::-;133572:4;133604:8;133572:4;133625:262;133659:2;133650:6;:11;133625:262;;;133703:6;133694:5;:15;;133713:1;133693:21;133719:1;133692:28;133688:187;;133773:8;133782:6;133773:16;;;;;;;:::i;:::-;;;;;133791:4;133756:40;;;;;;;;11163:19:1;;;11207:2;11198:12;;11191:28;11244:2;11235:12;;11006:247;133756:40:0;;;;;;;;;;;;;133746:51;;;;;;133739:58;;133688:187;;;133851:4;133857:8;133866:6;133857:16;;;;;;;:::i;:::-;;;;;133834:40;;;;;;;;11163:19:1;;;11207:2;11198:12;;11191:28;11244:2;11235:12;;11006:247;133834:40:0;;;;;;;;;;;;;133824:51;;;;;;133817:58;;133688:187;133663:8;;;;:::i;:::-;;;;133625:262;;;-1:-1:-1;133906:12:0;;;;133403:523;-1:-1:-1;;;;133403:523:0:o;245688:265::-;248639:1;248630:10;;;245774:4;248703:28;;;:20;:28;;;;;;248666:1;248680:4;248672:12;;248666:19;248703:35;:40;;245861:84;;;;-1:-1:-1;237239:1:0;237230:10;;;237196:4;237303:20;;;245908;237303;;;;;;237266:1;237280:4;237272:12;;237266:19;237303:27;:32;;245908:37;245841:104;245688:265;-1:-1:-1;;245688:265:0:o;254940:218::-;255001:10;:22;255015:8;255001:22;;254979:110;;;;-1:-1:-1;;;254979:110:0;;11849:2:1;254979:110:0;;;11831:21:1;11888:2;11868:18;;;11861:30;11927:34;11907:18;;;11900:62;11998:8;11978:18;;;11971:36;12024:19;;254979:110:0;;;;;;;;;255100:6;:14;;;;;;255130:20;;255139:10;3794:74:1;;255130:20:0;;3782:2:1;3767:18;255130:20:0;;;;;;;;254940:218::o;55178:383::-;55218:13;55328:31;55345:13;55328:16;:31::i;:::-;55408;55425:13;55408:16;:31::i;:::-;55488;55505:13;55488:16;:31::i;:::-;55289:249;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;55244:309;;55178:383;:::o;266609:224::-;253523:10;:29;253545:6;253523:29;;253501:110;;;;-1:-1:-1;;;253501:110:0;;13260:2:1;253501:110:0;;;13242:21:1;13299:2;13279:18;;;13272:30;13338:33;13318:18;;;13311:61;13389:18;;253501:110:0;13058:355:1;253501:110:0;266766:59:::1;266789:11;266802:6;266810:14;266766:22;:59::i;:::-;266609:224:::0;;;:::o;240168:5293::-;240394:7;240856:4;240394:7;240918:330;;;240948:3;240977:1;240971:89;;-1:-1:-1;241013:1:0;;240918:330;-1:-1:-1;240918:330:0:o;240971:89::-;241078:155;241105:8;;241078:155;;241209:1;241205:9;;;;;241176:1;241167:11;241078:155;;;240918:330;;;:::o;241406:891::-;241485:4;241520:3;241514:10;;241547:1;241542:409;;;;242051:17;242066:1;242051:17;:::i;:::-;242112:4;242107:3;242103:14;242098:3;242090:28;242156:1;242151:3;242147:11;242140:18;;242218:1;242211:3;242207:2;242203:12;242200:1;242196:20;242192:28;242187:3;242180:41;242259:3;242254;242250:13;242243:20;;;241507:775;;241542:409;241594:7;241590:1;241583:9;241579:23;241629:1;241624:113;;;;241867:1;241862:3;241854:15;241572:320;;241624:113;241709:4;241704:3;241696:18;241572:320;;241930:1;241925:3;241921:11;241914:18;;241507:775;;241406:891;;;;;:::o;242313:285::-;242378:4;242447;242378;242434:18;242537:2;242533:10;;;;242501:1;242492:11;;242521:23;-1:-1:-1;242569:14:0;;;242313:285::o;:::-;242738:1;242731:4;242725:11;242721:19;242765:9;242795:39;242832:1;242819:11;242814:3;242795:39;:::i;:::-;242788:46;;242855:37;242890:1;242879:9;242874:3;242855:37;:::i;:::-;242848:44;;242913:27;242932:7;242927:3;242913:27;:::i;:::-;242906:34;;242961;242993:1;242985:6;242980:3;242961:34;:::i;:::-;242954:41;;243035:1;243021:12;243018:19;243056:1;243051:225;;;;243341:2;243327:12;243324:20;243367:1;243362:296;;;;243784:28;243799:12;243784:28;:::i;:::-;243857:9;243851:4;243847:20;243842:3;243834:34;243906:1;243901:3;243897:11;243890:18;;243974:12;243961:9;243957:2;243953:18;243950:1;243946:26;243942:45;243937:3;243930:58;244026:9;244021:3;244017:19;244010:26;;;244090:12;244076;244071:3;244058:45;244132:22;;;;243317:856;;243362:296;243467:12;243461:4;243457:23;243452:3;243444:37;243519:1;243514:3;243510:11;243503:18;;243575:12;243561;243556:3;243543:45;243617:22;;;;243317:856;;243011:1177;;243051:225;243116:145;243241:1;243204:12;243191:26;243188:1;243183:35;243157:3;243116:145;:::i;:::-;243109:152;;243011:1177;;244209:27;244228:7;244223:3;244209:27;:::i;:::-;244202:34;;244280:9;244275:3;244271:19;244304:9;244327:15;244379:2;244366:11;244363:19;244401:1;244396:173;;;;244705:27;244720:11;244705:27;:::i;:::-;244813:4;244809:20;;244875:1;244860:17;;244856:29;244912:22;;;-1:-1:-1;244780:1:0;244765:17;;-1:-1:-1;244356:593:0;;244396:173;244508:11;244502:4;244498:22;244489:31;;244553:1;244538:16;;244356:593;;245007:15;244993:11;244990:1;244986:19;244982:41;244975:5;244972:52;244963:61;;245070:1;245057:11;245053:19;245038:34;;245111:11;245108:1;245104:19;245086:37;;245240:9;245234:16;245222:10;245218:33;245193:5;245180:10;245175:3;245171:20;245167:32;245146:120;245137:129;;245308:11;245297:9;245293:27;245280:40;;;245352:5;245341:9;245334:24;;;245410:9;245405:3;245401:19;245390:9;245380:41;245372:49;;;;245449:4;245442:11;;;;240168:5293;;;;;;;;;:::o;245469:211::-;245555:4;245591:17;;245576:11;:32;245572:50;;-1:-1:-1;245617:5:0;;245469:211;-1:-1:-1;245469:211:0:o;245572:50::-;248639:1;248630:10;;;248596:4;248703:28;;;:20;:28;;;;;;248666:1;248680:4;248672:12;;248666:19;248703:35;:40;;245642:30;248531:220;254653:211;254712:10;:22;254726:8;254712:22;;254690:108;;;;-1:-1:-1;;;254690:108:0;;13620:2:1;254690:108:0;;;13602:21:1;13659:2;13639:18;;;13632:30;13698:34;13678:18;;;13671:62;13769:6;13749:18;;;13742:34;13793:19;;254690:108:0;13418:400:1;254690:108:0;254809:6;:13;;;;254818:4;254809:13;;;254838:18;;254845:10;3794:74:1;;254838:18:0;;3782:2:1;3767:18;254838::0;3648:226:1;254347:232:0;12866:19;12889:13;;;;;;12888:14;;12936:34;;;;-1:-1:-1;12954:12:0;;12969:1;12954:12;;;;:16;12936:34;12935:97;;;-1:-1:-1;13004:4:0;1830:19;:23;;;12976:55;;-1:-1:-1;13014:12:0;;;;;:17;12976:55;12913:193;;;;-1:-1:-1;;;12913:193:0;;14025:2:1;12913:193:0;;;14007:21:1;14064:2;14044:18;;;14037:30;14103:34;14083:18;;;14076:62;14174:16;14154:18;;;14147:44;14208:19;;12913:193:0;13823:410:1;12913:193:0;13117:12;:16;;;;13132:1;13117:16;;;13144:67;;;;13179:13;:20;;;;;;;;13144:67;254433:8:::1;:38:::0;;94840:42:::1;254433:38:::0;;;::::1;;::::0;;;254482:6:::1;:16:::0;;;::::1;::::0;::::1;;;::::0;;254509:11:::1;:26:::0;;;;::::1;254433:38;254509:26:::0;::::1;;::::0;;254546:25:::1;:23;:25::i;:::-;13237:14:::0;13233:102;;;13284:5;13268:21;;;;;;13309:14;;-1:-1:-1;14390:36:1;;13309:14:0;;14378:2:1;14363:18;13309:14:0;;;;;;;;12855:487;254347:232;;:::o;259611:4166::-;253076:6;;;;:15;253068:47;;;;-1:-1:-1;;;253068:47:0;;14639:2:1;253068:47:0;;;14621:21:1;14678:2;14658:18;;;14651:30;14717:21;14697:18;;;14690:49;14756:18;;253068:47:0;14437:343:1;253068:47:0;260000:8:::1;::::0;:39:::1;:8;94840:42;260000:39;259978:149;;;::::0;-1:-1:-1;;;259978:149:0;;14987:2:1;259978:149:0::1;::::0;::::1;14969:21:1::0;15026:2;15006:18;;;14999:30;15065:34;15045:18;;;15038:62;15136:30;15116:18;;;15109:58;15184:19;;259978:149:0::1;14785:424:1::0;259978:149:0::1;260213:22;260238:27;260261:3;260238:22;:27::i;:::-;260276:40;260319:57:::0;;;:17:::1;:57;::::0;;;;;;;260276:100;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;;;;;;260213:52;;-1:-1:-1;260645:31:0;;260623:128:::1;;;::::0;-1:-1:-1;;;260623:128:0;;15416:2:1;260623:128:0::1;::::0;::::1;15398:21:1::0;15455:2;15435:18;;;15428:30;15494:34;15474:18;;;15467:62;15565:17;15545:18;;;15538:45;15600:19;;260623:128:0::1;15214:411:1::0;260623:128:0::1;261148:56;261177:16;:26;;;261148:28;:56::i;:::-;261126:172;;;::::0;-1:-1:-1;;;261126:172:0;;15832:2:1;261126:172:0::1;::::0;::::1;15814:21:1::0;15871:2;15851:18;;;15844:30;15910:34;15890:18;;;15883:62;15981:34;15961:18;;;15954:62;16053:4;16032:19;;;16025:33;16075:19;;261126:172:0::1;15630:470:1::0;261126:172:0::1;261432:31:::0;;261395:79:::1;::::0;;;;261364:28:::1;::::0;261395:22:::1;:6;:22;::::0;::::1;::::0;:79:::1;::::0;::::1;;345:25:1::0;;;333:2;318:18;;199:177;261395:79:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;261364:110;;261531:1;261508:20;:24;261485:117;;;::::0;-1:-1:-1;;;261485:117:0;;16496:2:1;261485:117:0::1;::::0;::::1;16478:21:1::0;16535:2;16515:18;;;16508:30;16574:34;16554:18;;;16547:62;16645:11;16625:18;;;16618:39;16674:19;;261485:117:0::1;16294:405:1::0;261485:117:0::1;261637:72;::::0;;;;::::1;::::0;::::1;345:25:1::0;;;261613:21:0::1;::::0;261637:6:::1;:26;;::::0;::::1;::::0;318:18:1;;261637:72:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;261613:96:::0;-1:-1:-1;261613:96:0;261720:58:::1;;;::::0;-1:-1:-1;;;261720:58:0;;17095:2:1;261720:58:0::1;::::0;::::1;17077:21:1::0;17134:2;17114:18;;;17107:30;17173:20;17153:18;;;17146:48;17211:18;;261720:58:0::1;16893:342:1::0;261720:58:0::1;261911:36;::::0;;;:20:::1;:36;::::0;;;;;::::1;;:45;261889:145;;;::::0;-1:-1:-1;;;261889:145:0;;17442:2:1;261889:145:0::1;::::0;::::1;17424:21:1::0;17481:2;17461:18;;;17454:30;17520:34;17500:18;;;17493:62;17591:20;17571:18;;;17564:48;17629:19;;261889:145:0::1;17240:414:1::0;261889:145:0::1;262117:36;::::0;;;:20:::1;:36;::::0;;;;;;;:43;;;::::1;262156:4;262117:43;::::0;;262268:10;;::::1;::::0;262257:8:::1;:21:::0;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;262960:10;::::1;::::0;262985:12:::1;::::0;::::1;::::0;263012:9:::1;::::0;::::1;::::0;263036:8:::1;::::0;::::1;::::0;262922:133:::1;::::0;262960:10;262985:12;263012:9;262922:23:::1;:133::i;:::-;263126:8;:38:::0;;;::::1;94840:42;263126:38;::::0;;263327:44:::1;::::0;262907:148;;-1:-1:-1;263347:14:0;;263327:44:::1;::::0;::::1;::::0;262907:148;1163:14:1;1156:22;1138:41;;1126:2;1111:18;;998:187;263327:44:0::1;;;;;;;;263640:16:::0;::::1;::::0;::::1;:61;;-1:-1:-1::0;263660:9:0::1;94501:1;263660:41;263640:61;263636:134;;;263718:40;::::0;-1:-1:-1;;;263718:40:0;;17861:2:1;263718:40:0::1;::::0;::::1;17843:21:1::0;17900:2;17880:18;;;17873:30;17939:32;17919:18;;;17912:60;17989:18;;263718:40:0::1;17659:354:1::0;263636:134:0::1;259729:4048;;;;;259611:4166:::0;:::o;267186:121::-;253292:11;;;;253278:10;:25;253256:109;;;;-1:-1:-1;;;253256:109:0;;18220:2:1;253256:109:0;;;18202:21:1;18259:2;18239:18;;;18232:30;18298:34;18278:18;;;18271:62;18369:4;18349:18;;;18342:32;18391:19;;253256:109:0;18018:398:1;253256:109:0;267268:31:::1;267292:6;267268:23;:31::i;:::-;267186:121:::0;:::o;256478:2992::-;253076:6;;;;:15;253068:47;;;;-1:-1:-1;;;253068:47:0;;14639:2:1;253068:47:0;;;14621:21:1;14678:2;14658:18;;;14651:30;14717:21;14697:18;;;14690:49;14756:18;;253068:47:0;14437:343:1;253068:47:0;256960:4:::1;256938:27;;:3;:10;;;:27;;::::0;256916:137:::1;;;::::0;-1:-1:-1;;;256916:137:0;;18623:2:1;256916:137:0::1;::::0;::::1;18605:21:1::0;18662:2;18642:18;;;18635:30;18701:34;18681:18;;;18674:62;18772:30;18752:18;;;18745:58;18820:19;;256916:137:0::1;18421:424:1::0;256916:137:0::1;257167:22;257192:27;257215:3;257192:22;:27::i;:::-;257230:40;257273:57:::0;;;:17:::1;:57;::::0;;;;;;;;257230:100;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;;;;;;257167:52;;-1:-1:-1;257230:100:0;257893:31;257871:133:::1;;;::::0;-1:-1:-1;;;257871:133:0;;19052:2:1;257871:133:0::1;::::0;::::1;19034:21:1::0;19091:2;19071:18;;;19064:30;19130:34;19110:18;;;19103:62;19201:22;19181:18;;;19174:50;19241:19;;257871:133:0::1;18850:416:1::0;257871:133:0::1;258101:39;::::0;;;;::::1;::::0;::::1;345:25:1::0;;;258070:28:0::1;::::0;258101:6:::1;:22;;::::0;::::1;::::0;318:18:1;;258101:39:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;258070:70;;258197:1;258174:20;:24;258151:117;;;::::0;-1:-1:-1;;;258151:117:0;;16496:2:1;258151:117:0::1;::::0;::::1;16478:21:1::0;16535:2;16515:18;;;16508:30;16574:34;16554:18;;;16547:62;16645:11;16625:18;;;16618:39;16674:19;;258151:117:0::1;16294:405:1::0;258151:117:0::1;258616:162;258652:14;258685:16;258720:3;:9;;;258748:15;258616:17;:162::i;:::-;258594:259;;;::::0;-1:-1:-1;;;258594:259:0;;19473:2:1;258594:259:0::1;::::0;::::1;19455:21:1::0;19512:2;19492:18;;;19485:30;19551:34;19531:18;;;19524:62;19622:17;19602:18;;;19595:45;19657:19;;258594:259:0::1;19271:411:1::0;258594:259:0::1;259186:157;::::0;;::::1;::::0;::::1;::::0;;;;;259275:15:::1;259186:157;::::0;;::::1;::::0;;;259322:9;;259186:157;;;;;;-1:-1:-1;259150:33:0;;;:17:::1;:33:::0;;;;;:193;;;;;;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;259451:10;;::::1;::::0;259439;;::::1;::::0;259406:56;;::::1;::::0;;::::1;::::0;;;::::1;::::0;259168:14;;259406:56:::1;::::0;::::1;256675:2795;;;256478:2992:::0;;;:::o;255551:122::-;255616:6;255642:15;:10;255655:2;255642:15;:::i;:::-;:23;;255660:5;255642:23;:::i;267812:151::-;267903:7;267930:12;267943:11;267930:25;;;;;;;;:::i;:::-;;;;;;;;;267923:32;;267812:151;;;:::o;266841:337::-;253292:11;;;;253278:10;:25;253256:109;;;;-1:-1:-1;;;253256:109:0;;18220:2:1;253256:109:0;;;18202:21:1;18259:2;18239:18;;;18232:30;18298:34;18278:18;;;18271:62;18369:4;18349:18;;;18342:32;18391:19;;253256:109:0;18018:398:1;253256:109:0;267061:19:::1;::::0;::::1;;:24:::0;267053:45:::1;;;::::0;-1:-1:-1;;;267053:45:0;;20349:2:1;267053:45:0::1;::::0;::::1;20331:21:1::0;20388:1;20368:18;;;20361:29;20426:10;20406:18;;;20399:38;20454:18;;267053:45:0::1;20147:331:1::0;267053:45:0::1;267109:61;267127:7;267136;267145:6;267153:9;267164:5;;267109:17;:61::i;264551:2050::-:0;264741:9;77238:18;77259:9;253292:11:::1;::::0;77238:30;;-1:-1:-1;253292:11:0::1;;253278:10;:25;253256:109;;;::::0;-1:-1:-1;;;253256:109:0;;18220:2:1;253256:109:0::1;::::0;::::1;18202:21:1::0;18259:2;18239:18;;;18232:30;18298:34;18278:18;;;18271:62;18369:4;18349:18;;;18342:32;18391:19;;253256:109:0::1;18018:398:1::0;253256:109:0::1;264908:11:::2;264904:184;;;264962:17;::::0;::::2;::::0;264936:140:::2;;;::::0;-1:-1:-1;;;264936:140:0;;20685:2:1;264936:140:0::2;::::0;::::2;20667:21:1::0;20724:2;20704:18;;;20697:30;20763:34;20743:18;;;20736:62;20834:31;20814:18;;;20807:59;20883:19;;264936:140:0::2;20483:425:1::0;264936:140:0::2;265274:37;265297:5:::0;265274:15:::2;:37::i;:::-;265261:50;;:9;:50;;;;265239:132;;;::::0;-1:-1:-1;;;265239:132:0;;21115:2:1;265239:132:0::2;::::0;::::2;21097:21:1::0;;;21134:18;;;21127:30;21193:34;21173:18;;;21166:62;21245:18;;265239:132:0::2;20913:356:1::0;265239:132:0::2;265772:7;265756:23:::0;::::2;;265748:63;;;::::0;-1:-1:-1;;;265748:63:0;;21476:2:1;265748:63:0::2;::::0;::::2;21458:21:1::0;21515:2;21495:18;;;21488:30;21554:29;21534:18;;;21527:57;21601:18;;265748:63:0::2;21274:351:1::0;265748:63:0::2;265875:10;129980:42:::0;130460:27;265897:54:::2;130460:27:::0;265921:3;265926:6;265897:54:::2;::::0;::::2;265945:5:::0;;265897:17:::2;:54::i;:::-;266214:23;266271:9;266295:6;266316:9;266340:11;266366:5;;266240:142;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;266214:168;;249814:1;266560:3;266533:60;;266554:4;266533:60;;;266582:10;266533:60;;;;;;:::i;:::-;;;;;;;;264766:1835;;77375:29:::0;77384:7;77393:10;77375:8;:29::i;:::-;77158:254;264551:2050;;;;;;;:::o;1535:326::-;1830:19;;;:23;;;1535:326::o;51806:716::-;51862:13;51913:14;51930:17;51941:5;51930:10;:17::i;:::-;51950:1;51930:21;51913:38;;51966:20;52000:6;51989:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51989:18:0;-1:-1:-1;51966:41:0;-1:-1:-1;52131:28:0;;;52147:2;52131:28;52188:288;52220:5;;52362:8;52357:2;52346:14;;52341:30;52220:5;52328:44;52418:2;52409:11;;;-1:-1:-1;52439:21:0;52188:288;52439:21;-1:-1:-1;52497:6:0;51806:716;-1:-1:-1;;;51806:716:0:o;245961:986::-;246126:3;246116:6;:13;;246108:47;;;;-1:-1:-1;;;246108:47:0;;22890:2:1;246108:47:0;;;22872:21:1;22929:2;22909:18;;;22902:30;22968:23;22948:18;;;22941:51;23009:18;;246108:47:0;22688:345:1;246108:47:0;246195:11;246174:17;;:32;246166:65;;;;-1:-1:-1;;;246166:65:0;;23240:2:1;246166:65:0;;;23222:21:1;23279:2;23259:18;;;23252:30;23318:22;23298:18;;;23291:50;23358:18;;246166:65:0;23038:344:1;246166:65:0;246489:1;246474:16;;;246371:12;246557:28;;;:20;:28;;;;;:56;;246402:1;246387:11;;246386:17;;246418:22;;;246536:4;246522:18;;246589:24;;;246557:56;;;;;;246418:22;;246386:17;246474:16;246650:3;246632:15;;;:21;246628:171;;;246704:1;246695:10;;246674:32;;;;:20;:32;;;;;246770:3;:12;;;246730:53;;;246674:109;;246628:171;-1:-1:-1;;;246835:20:0;;;246815:17;:40;246884:55;;;9745:25:1;;;9801:2;9786:18;;9779:34;;;9829:18;;;9822:34;;;246884:55:0;;9733:2:1;9718:18;246884:55:0;9543:319:1;82451:230:0;14998:13;;;;;;;14990:69;;;;-1:-1:-1;;;14990:69:0;;23913:2:1;14990:69:0;;;23895:21:1;23952:2;23932:18;;;23925:30;23991:34;23971:18;;;23964:62;24062:13;24042:18;;;24035:41;24093:19;;14990:69:0;23711:407:1;14990:69:0;82532:141:::1;::::0;;::::1;::::0;::::1;::::0;;82575:6:::1;82532:141:::0;;;-1:-1:-1;82532:141:0::1;::::0;::::1;::::0;82648:12:::1;82532:141;;::::0;;;;;;;82523:150;::::1;;:6;:150:::0;82451:230::o;128861:419::-;129065:9;;129097:10;;;;;129130;;;;;129163:9;;;;129195:12;;;;129230:8;;;;129032:225;;128964:7;;129032:225;;129065:9;;129097:10;129230:8;129032:225;;:::i;:::-;;;;;;;;;;;;;129004:268;;;;;;128984:288;;128861:419;;;:::o;267559:209::-;267656:4;267724:6;:34;;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;267711:49;;:10;:49;:::i;:::-;267693:15;:67;;267559:209;-1:-1:-1;;267559:209:0:o;20824:2299::-;20983:4;21000:13;21024:15;21042:21;21052:7;21061:1;21042:9;:21::i;:::-;21024:39;;21177:10;21167:1165;;21291:10;21288:1;21281:21;21408:2;21404;21397:14;22157:56;22153:2;22146:68;22313:3;22309:2;22302:15;21167:1165;23050:4;23017;22979:9;22973:16;22942:2;22931:9;22927:18;22887:6;22848:7;22817:5;22794:285;22782:297;20824:2299;-1:-1:-1;;;;;;;20824:2299:0:o;246955:382::-;247041:17;;247032:6;:26;247024:66;;;;-1:-1:-1;;;247024:66:0;;25116:2:1;247024:66:0;;;25098:21:1;25155:2;25135:18;;;25128:30;25194:29;25174:18;;;25167:57;25241:18;;247024:66:0;24914:351:1;247024:66:0;248639:1;248630:10;;;248596:4;248703:28;;;:20;:28;;;;;;248666:1;248680:4;248672:12;;248666:19;248703:35;247103:62;;;;-1:-1:-1;;;247103:62:0;;25472:2:1;247103:62:0;;;25454:21:1;25511:2;25491:18;;;25484:30;25550:26;25530:18;;;25523:54;25594:18;;247103:62:0;25270:348:1;247103:62:0;237239:1;237230:10;;;237196:4;237303:20;;;247185;237303;;;;;;237266:1;237280:4;237272:12;;237266:19;237303:27;:32;247176:69;;;;-1:-1:-1;;;247176:69:0;;25825:2:1;247176:69:0;;;25807:21:1;25864:2;25844:18;;;25837:30;25903:25;25883:18;;;25876:53;25946:18;;247176:69:0;25623:347:1;247176:69:0;237792:1;237783:10;;;237766:14;237849:20;;;247256;237849;;;;;:28;;237819:1;237833:4;237825:12;;237819:19;237849:28;;;247306:23;;345:25:1;;;247306:23:0;;333:2:1;318:18;247306:23:0;;;;;;;246955:382;:::o;247749:717::-;247998:12;:19;247976;248044:168;248081:7;247998:19;248129:6;248150:7;248172:9;248196:5;;248044:22;:168::i;:::-;248223:12;:24;;;;;;;-1:-1:-1;248223:24:0;;;;;;;;;248288:170;;248028:184;;-1:-1:-1;248288:170:0;;;;;;;;;;;;;248363:6;;248391:11;;248418:9;;248442:5;;;;248288:170;:::i;:::-;;;;;;;;247928:538;;247749:717;;;;;;:::o;77673:4237::-;77842:6;:19;77807:17;;77827:34;;77842:19;;;;;77827:12;:34;:::i;:::-;77807:54;;77874:28;77905:17;:15;:17::i;:::-;77874:48;;77933:26;78033:6;:27;;;78025:36;;77977:6;:23;;;77969:32;;77962:100;;;;:::i;:::-;77933:129;-1:-1:-1;78079:13:0;;78075:2378;;78440:6;:20;78403:19;;78425:76;;78482:19;;78440:20;;;;;78425:76;:::i;:::-;78403:98;;78516:19;78686:6;:34;;;78678:43;;78628:19;:94;;;;:::i;:::-;78554:6;:18;78539:67;;78594:12;;78554:18;;78539:67;:::i;:::-;78538:185;;;;:::i;:::-;78947:6;:18;78516:207;;-1:-1:-1;78868:17:0;;78888:236;;78932:50;;78516:207;;78947:18;;78932:50;:::i;:::-;79022:6;:21;;;79014:30;;79085:6;:21;;;79077:30;;78888:16;:236::i;:::-;78868:256;;79406:1;79394:9;:13;79390:810;;;79683:501;79731:299;79789:10;79885:6;:34;;;79877:43;;80004:1;79992:9;:13;;;;:::i;:::-;79731:16;:299::i;79683:501::-;79670:514;;79390:810;80296:49;;80399:42;80360:24;80428:12;80399:42;;;80296:6;80399:42;-1:-1:-1;;78075:2378:0;80550:6;:31;;80574:7;;80550:6;:20;;:31;;80574:7;;80550:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;80687:6;:23;;;80679:32;;80629:6;:20;;;;;;;;;;;;80621:29;;80614:98;;80592:210;;;;-1:-1:-1;;;80592:210:0;;28402:2:1;80592:210:0;;;28384:21:1;28441:2;28421:18;;;28414:30;28480:34;28460:18;;;28453:62;28551:32;28531:18;;;28524:60;28601:19;;80592:210:0;28200:426:1;80592:210:0;80917:6;:18;80867:20;;80890:46;;80917:18;;80890:16;;;:46;:::i;:::-;80867:69;;81425:15;81458:31;81467:13;81482:6;81458:8;:31::i;:::-;81443:46;;:12;:46;:::i;:::-;81425:64;;81774:15;81806:9;81792:23;;:11;:23;:::i;:::-;81774:41;;81840:7;81830;:17;81826:77;;;81864:27;81873:17;81883:7;81873;:17;:::i;:::-;81864:8;:27::i;47550:948::-;47603:7;;47690:8;47681:17;;47677:106;;47728:8;47719:17;;;-1:-1:-1;47765:2:0;47755:12;47677:106;47810:8;47801:5;:17;47797:106;;47848:8;47839:17;;;-1:-1:-1;47885:2:0;47875:12;47797:106;47930:8;47921:5;:17;47917:106;;47968:8;47959:17;;;-1:-1:-1;48005:2:0;47995:12;47917:106;48050:7;48041:5;:16;48037:103;;48087:7;48078:16;;;-1:-1:-1;48123:1:0;48113:11;48037:103;48167:7;48158:5;:16;48154:103;;48204:7;48195:16;;;-1:-1:-1;48240:1:0;48230:11;48154:103;48284:7;48275:5;:16;48271:103;;48321:7;48312:16;;;-1:-1:-1;48357:1:0;48347:11;48271:103;48401:7;48392:5;:16;48388:68;;48439:1;48429:11;48484:6;47550:948;-1:-1:-1;;47550:948:0:o;19953:404::-;20034:4;20051:15;20291:2;20276:12;20269:5;20265:24;20261:33;20256:2;20247:7;20243:16;20239:56;20234:2;20227:5;20223:14;20220:76;20195:116;;19953:404;-1:-1:-1;;;;19953:404:0:o;255934:196::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;256092:13:0;:28;;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;256085:37;;255934:196;:::o;73118:197::-;73231:6;73257:50;73272:28;73287:6;73295:4;73272:14;:28::i;:::-;73302:4;73257:14;:50::i;:::-;73250:57;73118:197;-1:-1:-1;;;;73118:197:0:o;73693:294::-;73825:6;73975:4;73898:72;73931:19;73938:12;73975:4;73931:19;:::i;:::-;73923:28;;:4;:28;:::i;:::-;73953:16;:9;73965:4;73953:16;:::i;:::-;73898:24;:72::i;:::-;73865:106;;:12;:106;:::i;:::-;73864:115;;;;:::i;37591:106::-;37649:7;37680:1;37676;:5;:13;;37688:1;37676:13;;;37684:1;37676:13;37669:20;37591:106;-1:-1:-1;;;37591:106:0:o;55969:198::-;56024:9;56048:18;56069:9;56048:30;;56089:71;56121:7;56109:9;56096:22;;:10;:22;:::i;:::-;:32;56089:71;;;56145:3;;;:::i;:::-;;;56089:71;;50549:103;50605:6;50635:1;50631;:5;:13;;50643:1;50631:13;;50735:103;50791:6;50821:1;50817;:5;:13;;50829:1;50817:13;;57727:276;57786:6;57912:36;56992:4;57931:1;57920:8;57926:1;57920:5;:8::i;:::-;:12;;;;:::i;:::-;57919:28;;;;:::i;:::-;57912:6;:36::i;61178:3005::-;61226:8;61284:1;61280;:5;61272:27;;;;-1:-1:-1;;;61272:27:0;;30517:2:1;61272:27:0;;;30499:21:1;30556:1;30536:18;;;30529:29;30594:11;30574:18;;;30567:39;30623:18;;61272:27:0;30315:332:1;61272:27:0;61700:8;61738:2;61718:16;61731:1;61718:4;:16::i;:::-;61711:29;61769:3;:7;;;61755:22;;;;61803:17;;;62610:31;62606:35;;62662:5;;62059:2;62661:13;;;62678:32;62660:50;62731:5;;62730:13;;62747:33;62729:51;62801:5;;62800:13;;62817:33;62799:51;62871:5;;62870:13;;62887:33;62869:51;62941:5;;62940:13;;62957:32;62939:50;63010:5;;63009:13;;63026:30;63008:48;61997:31;61993:35;;62049:5;;62048:13;;62065:32;62047:50;62118:5;;62117:13;;62134:32;62116:50;62187:5;;62186:13;;62185:50;;62256:5;;62255:13;;62254:50;;62325:5;;62324:13;;;62323:50;;62392:5;;;:46;;63355:10;63757:43;63752:48;63866:71;:75;;;;63861:80;;;;64016:72;64011:77;64161:3;64155:9;;;-1:-1:-1;;61178:3005:0:o;58011:3159::-;58060:8;58246:21;58241:1;:26;58237:40;;-1:-1:-1;58276:1:0;;58011:3159;-1:-1:-1;58011:3159:0:o;58237:40::-;58480:21;58475:1;:26;58471:54;;58503:22;;-1:-1:-1;;;58503:22:0;;30854:2:1;58503:22:0;;;30836:21:1;30893:2;30873:18;;;30866:30;30932:14;30912:18;;;30905:42;30964:18;;58503:22:0;30652:336:1;58471:54:0;58803:5;58797:2;58792:7;;;58791:17;;-1:-1:-1;59077:8:0;59143:2;59101:29;59090:7;;;59089:41;59133:5;59089:49;59088:57;;59172:29;59168:33;;59164:37;;;59856:35;;;59912:5;;59485:2;59911:13;;;59928:32;59910:50;59981:5;;59980:13;;59979:51;;60051:5;;60050:13;;60067:34;60049:52;60122:5;;60121:13;;60120:53;;60194:5;;60193:13;;60210:35;60192:53;59491:32;59423:31;59419:35;;59475:5;;59474:13;;59473:50;;;59549:5;;;:40;;59610:5;59609:13;;;59626:35;59608:53;59680:5;;;59689:40;59680:50;60569:10;61080:49;61067:62;61142:3;:7;;;;61066:84;;;;;;-1:-1:-1;;58011:3159:0:o;72170:588::-;72218:9;72252:1;72248;:5;72240:27;;;;-1:-1:-1;;;72240:27:0;;30517:2:1;72240:27:0;;;30499:21:1;30556:1;30536:18;;;30529:29;30594:11;30574:18;;;30567:39;30623:18;;72240:27:0;30315:332:1;72240:27:0;-1:-1:-1;72673:1:0;72319:34;-1:-1:-1;;72313:1:0;72309:49;72413:9;;;72393:18;72390:33;72387:1;72383:41;72377:48;72472:9;;;72460:10;72457:25;72454:1;72450:33;72444:40;72527:9;;;72519:6;72516:21;72513:1;72509:29;72503:36;72580:9;;;72574:4;72571:19;72568:1;72564:27;;;72558:34;;;72632:9;;;72627:3;72624:18;72621:1;72617:26;72611:33;72684:9;;;72676:18;;;72669:26;;72663:33;72729:9;;;-1:-1:-1;72715:25:0;;72170:588::o;14:180:1:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;-1:-1:-1;165:23:1;;14:180;-1:-1:-1;14:180:1:o;381:161::-;475:6;508:4;496:17;;493:26;-1:-1:-1;490:46:1;;;532:1;529;522:12;547:446;659:6;667;675;683;736:4;724:9;715:7;711:23;707:34;704:54;;;754:1;751;744:12;704:54;790:9;777:23;767:33;;819:62;873:7;868:2;857:9;853:18;819:62;:::i;:::-;547:446;;809:72;;-1:-1:-1;;;;928:4:1;913:20;;900:34;;981:4;966:20;953:34;;547:446::o;1190:250::-;1275:1;1285:113;1299:6;1296:1;1293:13;1285:113;;;1375:11;;;1369:18;1356:11;;;1349:39;1321:2;1314:10;1285:113;;;-1:-1:-1;;1432:1:1;1414:16;;1407:27;1190:250::o;1445:330::-;1487:3;1525:5;1519:12;1552:6;1547:3;1540:19;1568:76;1637:6;1630:4;1625:3;1621:14;1614:4;1607:5;1603:16;1568:76;:::i;:::-;1689:2;1677:15;1694:66;1673:88;1664:98;;;;1764:4;1660:109;;1445:330;-1:-1:-1;;1445:330:1:o;1780:220::-;1929:2;1918:9;1911:21;1892:4;1949:45;1990:2;1979:9;1975:18;1967:6;1949:45;:::i;2005:316::-;2082:6;2090;2098;2151:2;2139:9;2130:7;2126:23;2122:32;2119:52;;;2167:1;2164;2157:12;2119:52;-1:-1:-1;;2190:23:1;;;2260:2;2245:18;;2232:32;;-1:-1:-1;2311:2:1;2296:18;;;2283:32;;2005:316;-1:-1:-1;2005:316:1:o;2326:196::-;2394:20;;2454:42;2443:54;;2433:65;;2423:93;;2512:1;2509;2502:12;2527:347;2578:8;2588:6;2642:3;2635:4;2627:6;2623:17;2619:27;2609:55;;2660:1;2657;2650:12;2609:55;-1:-1:-1;2683:20:1;;2726:18;2715:30;;2712:50;;;2758:1;2755;2748:12;2712:50;2795:4;2787:6;2783:17;2771:29;;2847:3;2840:4;2831:6;2823;2819:19;2815:30;2812:39;2809:59;;;2864:1;2861;2854:12;2809:59;2527:347;;;;;:::o;2879:764::-;2994:6;3002;3010;3018;3026;3034;3042;3095:3;3083:9;3074:7;3070:23;3066:33;3063:53;;;3112:1;3109;3102:12;3063:53;3135:29;3154:9;3135:29;:::i;:::-;3125:39;;3211:2;3200:9;3196:18;3183:32;3173:42;;3262:2;3251:9;3247:18;3234:32;3224:42;;3285:38;3319:2;3308:9;3304:18;3285:38;:::i;:::-;3275:48;;3370:3;3359:9;3355:19;3342:33;3332:43;;3426:3;3415:9;3411:19;3398:33;3454:18;3446:6;3443:30;3440:50;;;3486:1;3483;3476:12;3440:50;3525:58;3575:7;3566:6;3555:9;3551:22;3525:58;:::i;:::-;2879:764;;;;-1:-1:-1;2879:764:1;;-1:-1:-1;2879:764:1;;;;3499:84;;-1:-1:-1;;;2879:764:1:o;3879:160::-;3944:20;;4000:13;;3993:21;3983:32;;3973:60;;4029:1;4026;4019:12;4044:254;4109:6;4117;4170:2;4158:9;4149:7;4145:23;4141:32;4138:52;;;4186:1;4183;4176:12;4138:52;4209:26;4225:9;4209:26;:::i;:::-;4199:36;;4254:38;4288:2;4277:9;4273:18;4254:38;:::i;:::-;4244:48;;4044:254;;;;;:::o;4303:184::-;4355:77;4352:1;4345:88;4452:4;4449:1;4442:15;4476:4;4473:1;4466:15;4492:253;4564:2;4558:9;4606:4;4594:17;;4641:18;4626:34;;4662:22;;;4623:62;4620:88;;;4688:18;;:::i;:::-;4724:2;4717:22;4492:253;:::o;4750:334::-;4821:2;4815:9;4877:2;4867:13;;4882:66;4863:86;4851:99;;4980:18;4965:34;;5001:22;;;4962:62;4959:88;;;5027:18;;:::i;:::-;5063:2;5056:22;4750:334;;-1:-1:-1;4750:334:1:o;5089:1197::-;5157:5;5205:4;5193:9;5188:3;5184:19;5180:30;5177:50;;;5223:1;5220;5213:12;5177:50;5245:22;;:::i;:::-;5236:31;;5303:9;5290:23;5283:5;5276:38;5333:2;5367:38;5401:2;5390:9;5386:18;5367:38;:::i;:::-;5362:2;5355:5;5351:14;5344:62;5438:38;5472:2;5461:9;5457:18;5438:38;:::i;:::-;5433:2;5426:5;5422:14;5415:62;5537:2;5526:9;5522:18;5509:32;5504:2;5497:5;5493:14;5486:56;5603:3;5592:9;5588:19;5575:33;5569:3;5562:5;5558:15;5551:58;5660:3;5649:9;5645:19;5632:33;5684:18;5725:2;5717:6;5714:14;5711:34;;;5741:1;5738;5731:12;5711:34;5779:6;5768:9;5764:22;5754:32;;5824:3;5817:4;5813:2;5809:13;5805:23;5795:51;;5842:1;5839;5832:12;5795:51;5878:2;5865:16;5900:2;5896;5893:10;5890:36;;;5906:18;;:::i;:::-;5948:112;6056:2;5987:66;5980:4;5976:2;5972:13;5968:86;5964:95;5948:112;:::i;:::-;5935:125;;6083:2;6076:5;6069:17;6123:3;6118:2;6113;6109;6105:11;6101:20;6098:29;6095:49;;;6140:1;6137;6130:12;6095:49;6195:2;6190;6186;6182:11;6177:2;6170:5;6166:14;6153:45;6239:1;6234:2;6229;6222:5;6218:14;6214:23;6207:34;;6274:5;6268:3;6261:5;6257:15;6250:30;;;;5089:1197;;;;:::o;6291:373::-;6389:6;6442:2;6430:9;6421:7;6417:23;6413:32;6410:52;;;6458:1;6455;6448:12;6410:52;6498:9;6485:23;6531:18;6523:6;6520:30;6517:50;;;6563:1;6560;6553:12;6517:50;6586:72;6650:7;6641:6;6630:9;6626:22;6586:72;:::i;6669:569::-;6811:6;6819;6827;6880:4;6868:9;6859:7;6855:23;6851:34;6848:54;;;6898:1;6895;6888:12;6848:54;6938:9;6925:23;6971:18;6963:6;6960:30;6957:50;;;7003:1;7000;6993:12;6957:50;7026:72;7090:7;7081:6;7070:9;7066:22;7026:72;:::i;:::-;7016:82;;;7117:62;7171:7;7166:2;7155:9;7151:18;7117:62;:::i;:::-;7107:72;;7226:4;7215:9;7211:20;7198:34;7188:44;;6669:569;;;;;:::o;7675:171::-;7742:20;;7802:18;7791:30;;7781:41;;7771:69;;7836:1;7833;7826:12;7851:184;7909:6;7962:2;7950:9;7941:7;7937:23;7933:32;7930:52;;;7978:1;7975;7968:12;7930:52;8001:28;8019:9;8001:28;:::i;8427:695::-;8533:6;8541;8549;8557;8565;8573;8626:3;8614:9;8605:7;8601:23;8597:33;8594:53;;;8643:1;8640;8633:12;8594:53;8666:29;8685:9;8666:29;:::i;:::-;8656:39;;8714:38;8748:2;8737:9;8733:18;8714:38;:::i;:::-;8704:48;;8799:2;8788:9;8784:18;8771:32;8761:42;;8850:2;8839:9;8835:18;8822:32;8812:42;;8905:3;8894:9;8890:19;8877:33;8933:18;8925:6;8922:30;8919:50;;;8965:1;8962;8955:12;8919:50;9004:58;9054:7;9045:6;9034:9;9030:22;9004:58;:::i;:::-;8427:695;;;;-1:-1:-1;8427:695:1;;-1:-1:-1;8427:695:1;;9081:8;;8427:695;-1:-1:-1;;;8427:695:1:o;9867:693::-;9969:6;9977;9985;9993;10001;10009;10062:3;10050:9;10041:7;10037:23;10033:33;10030:53;;;10079:1;10076;10069:12;10030:53;10102:29;10121:9;10102:29;:::i;:::-;10092:39;;10178:2;10167:9;10163:18;10150:32;10140:42;;10201:37;10234:2;10223:9;10219:18;10201:37;:::i;:::-;10191:47;;10257:35;10288:2;10277:9;10273:18;10257:35;:::i;:::-;10247:45;;10343:3;10332:9;10328:19;10315:33;10371:18;10363:6;10360:30;10357:50;;;10403:1;10400;10393:12;10817:184;10869:77;10866:1;10859:88;10966:4;10963:1;10956:15;10990:4;10987:1;10980:15;11258:184;11310:77;11307:1;11300:88;11407:4;11404:1;11397:15;11431:4;11428:1;11421:15;11447:195;11486:3;11517:66;11510:5;11507:77;11504:103;;11587:18;;:::i;:::-;-1:-1:-1;11634:1:1;11623:13;;11447:195::o;12054:999::-;12483:3;12521:6;12515:13;12537:66;12596:6;12591:3;12584:4;12576:6;12572:17;12537:66;:::i;:::-;12634:6;12629:3;12625:16;12612:29;;12660:3;12686:2;12679:5;12672:17;12720:6;12714:13;12736:78;12805:8;12801:1;12794:5;12790:13;12783:4;12775:6;12771:17;12736:78;:::i;:::-;12877:1;12833:20;;12869:10;;;12862:22;12909:13;;12931:75;12909:13;12993:1;12985:10;;12978:4;12966:17;;12931:75;:::i;:::-;13026:17;13045:1;13022:25;;12054:999;-1:-1:-1;;;;;12054:999:1:o;16105:184::-;16175:6;16228:2;16216:9;16207:7;16203:23;16199:32;16196:52;;;16244:1;16241;16234:12;16196:52;-1:-1:-1;16267:16:1;;16105:184;-1:-1:-1;16105:184:1:o;19687:270::-;19726:7;19758:18;19803:2;19800:1;19796:10;19833:2;19830:1;19826:10;19889:3;19885:2;19881:12;19876:3;19873:21;19866:3;19859:11;19852:19;19848:47;19845:73;;;19898:18;;:::i;:::-;19938:13;;19687:270;-1:-1:-1;;;;19687:270:1:o;19962:180::-;20029:18;20067:10;;;20079;;;20063:27;;20102:11;;;20099:37;;;20116:18;;:::i;:::-;20099:37;19962:180;;;;:::o;21630:641::-;21903:6;21898:3;21891:19;21940:6;21935:2;21930:3;21926:12;21919:28;21999:66;21990:6;21985:3;21981:16;21977:89;21972:2;21967:3;21963:12;21956:111;22120:6;22113:14;22106:22;22101:3;22097:32;22092:2;22087:3;22083:12;22076:54;22174:6;22166;22161:2;22156:3;22152:12;22139:42;21873:3;22204:16;;22222:2;22200:25;22234:13;;;22200:25;21630:641;-1:-1:-1;;;;;21630:641:1:o;22499:184::-;22551:77;22548:1;22541:88;22648:4;22645:1;22638:15;22672:4;22669:1;22662:15;24123:656;24410:6;24399:9;24392:25;24373:4;24436:42;24526:2;24518:6;24514:15;24509:2;24498:9;24494:18;24487:43;24578:2;24570:6;24566:15;24561:2;24550:9;24546:18;24539:43;;24618:6;24613:2;24602:9;24598:18;24591:34;24662:6;24656:3;24645:9;24641:19;24634:35;24706:3;24700;24689:9;24685:19;24678:32;24727:46;24768:3;24757:9;24753:19;24745:6;24727:46;:::i;:::-;24719:54;24123:656;-1:-1:-1;;;;;;;;24123:656:1:o;24784:125::-;24849:9;;;24870:10;;;24867:36;;;24883:18;;:::i;25975:688::-;26214:6;26203:9;26196:25;26269:18;26261:6;26257:31;26252:2;26241:9;26237:18;26230:59;26325:6;26320:2;26309:9;26305:18;26298:34;26368:3;26363:2;26352:9;26348:18;26341:31;26409:6;26403:3;26392:9;26388:19;26381:35;26467:6;26459;26453:3;26442:9;26438:19;26425:49;26524:1;26494:22;;;26518:3;26490:32;;;26483:43;;;;26578:2;26566:15;;;26583:66;26562:88;26547:104;26543:114;;25975:688;-1:-1:-1;;;;25975:688:1:o;26668:128::-;26735:9;;;26756:11;;;26753:37;;;26770:18;;:::i;26801:308::-;26840:1;26866;26856:35;;26871:18;;:::i;:::-;26988:66;26985:1;26982:73;26913:66;26910:1;26907:73;26903:153;26900:179;;;27059:18;;:::i;:::-;-1:-1:-1;27093:10:1;;26801:308::o;27114:200::-;27180:9;;;27153:4;27208:9;;27236:10;;27248:12;;;27232:29;27271:12;;;27263:21;;27229:56;27226:82;;;27288:18;;:::i;27319:655::-;27358:7;27390:66;27482:1;27479;27475:9;27510:1;27507;27503:9;27555:1;27551:2;27547:10;27544:1;27541:17;27536:2;27532;27528:11;27524:35;27521:61;;;27562:18;;:::i;:::-;27601:66;27693:1;27690;27686:9;27740:1;27736:2;27731:11;27728:1;27724:19;27719:2;27715;27711:11;27707:37;27704:63;;;27747:18;;:::i;:::-;27793:1;27790;27786:9;27776:19;;27840:1;27836:2;27831:11;27828:1;27824:19;27819:2;27815;27811:11;27807:37;27804:63;;;27847:18;;:::i;:::-;27912:1;27908:2;27903:11;27900:1;27896:19;27891:2;27887;27883:11;27879:37;27876:63;;;27919:18;;:::i;:::-;-1:-1:-1;;;27959:9:1;;;;;27319:655;-1:-1:-1;;;27319:655:1:o;27979:216::-;28043:9;;;28071:11;;;28018:3;28101:9;;28129:10;;28125:19;;28154:10;;28146:19;;28122:44;28119:70;;;28169:18;;:::i;:::-;28119:70;;27979:216;;;;:::o;28631:228::-;28671:7;28797:1;28729:66;28725:74;28722:1;28719:81;28714:1;28707:9;28700:17;28696:105;28693:131;;;28804:18;;:::i;:::-;-1:-1:-1;28844:9:1;;28631:228::o;28864:120::-;28904:1;28930;28920:35;;28935:18;;:::i;:::-;-1:-1:-1;28969:9:1;;28864:120::o;28989:167::-;29067:13;;29120:10;29109:22;;29099:33;;29089:61;;29146:1;29143;29136:12;29161:160;29238:13;;29291:4;29280:16;;29270:27;;29260:55;;29311:1;29308;29301:12;29326:984;29428:6;29481:3;29469:9;29460:7;29456:23;29452:33;29449:53;;;29498:1;29495;29488:12;29449:53;29531:2;29525:9;29573:3;29565:6;29561:16;29643:6;29631:10;29628:22;29607:18;29595:10;29592:34;29589:62;29586:88;;;29654:18;;:::i;:::-;29690:2;29683:22;29729:39;29758:9;29729:39;:::i;:::-;29721:6;29714:55;29802:47;29845:2;29834:9;29830:18;29802:47;:::i;:::-;29797:2;29789:6;29785:15;29778:72;29883:47;29926:2;29915:9;29911:18;29883:47;:::i;:::-;29878:2;29870:6;29866:15;29859:72;29964:48;30008:2;29997:9;29993:18;29964:48;:::i;:::-;29959:2;29951:6;29947:15;29940:73;30047:49;30091:3;30080:9;30076:19;30047:49;:::i;:::-;30041:3;30033:6;30029:16;30022:75;30140:3;30129:9;30125:19;30119:26;30185:34;30178:5;30174:46;30167:5;30164:57;30154:85;;30235:1;30232;30225:12;30154:85;30267:3;30255:16;;30248:31;30259:6;29326:984;-1:-1:-1;;;29326:984:1:o
Swarm Source
ipfs://783ce1cf18c9f745c75d43dcdec745f05370389e8e6190af40a072a1cddacf5c
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.