Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Challenge
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ChallengeHeader.sol";
import "./ChallengeDataAvailability.sol";
import "./ChallengeL2Header.sol";
/// @custom:proxied
/// @title Challenge
/// @author LightLink Hummingbird
/// @custom:version v1.1.0-beta
/// @notice Challenge is the entry point for all validity challenges.
/// Challenge mechanisms allow for the verification of rollup
/// validity, with invalid blocks causing a rollback.
/// Challenges require a fee, incentivizing valid challenges
/// and discouraging frivolous ones, while compensating
/// defenders for their costs.
///
/// Challenges must be made within a specified time window
/// post-block publication, with late challenges being
/// rejected. The rules for fees and timing are outlined in
/// ChallengeBase.sol.
contract Challenge is
ChallengeHeader,
ChallengeDataAvailability,
ChallengeL2Header
{
/// @notice Initializes the Challenge contract.
/// @param _chain - The address of the chain contract.
/// @param _daOracle - The address of the data availability oracle.
/// @param _chainOracle - The address of the chain oracle contract.
function initialize(
address _chain,
address _daOracle,
address _chainOracle
) public initializer {
__ChallengeBase_init(_chain, _daOracle, _chainOracle);
__ChallengeHeader_init();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. 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 {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @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 Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._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 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._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() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @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 {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
/// @dev bytes32 encoding of the string "checkpoint"
bytes32 constant VALIDATOR_SET_HASH_DOMAIN_SEPARATOR =
0x636865636b706f696e7400000000000000000000000000000000000000000000;
/// @dev bytes32 encoding of the string "transactionBatch"
bytes32 constant DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR =
0x7472616e73616374696f6e426174636800000000000000000000000000000000;// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
/// @notice A tuple of data root with metadata. Each data root is associated
/// with a Celestia block height.
/// @dev `availableDataRoot` in
/// https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#header
struct DataRootTuple {
// Celestia block height the data root was included in.
// Genesis block is height = 0.
// First queryable block is height = 1.
uint256 height;
// Data root.
bytes32 dataRoot;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;
import "./DataRootTuple.sol";
import "./lib/tree/binary/BinaryMerkleProof.sol";
/// @notice Data Availability Oracle interface.
interface IDAOracle {
/// @notice Verify a Data Availability attestation.
/// @param _tupleRootNonce Nonce of the tuple root to prove against.
/// @param _tuple Data root tuple to prove inclusion of.
/// @param _proof Binary Merkle tree proof that `tuple` is in the root at `_tupleRootNonce`.
/// @return `true` is proof is valid, `false` otherwise.
function verifyAttestation(uint256 _tupleRootNonce, DataRootTuple memory _tuple, BinaryMerkleProof memory _proof)
external
view
returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
/// @notice Merkle Tree Proof structure.
struct BinaryMerkleProof {
// List of side nodes to verify and calculate tree.
bytes32[] sideNodes;
// The key of the leaf to verify.
uint256 key;
// The number of leaves in the tree
uint256 numLeaves;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "../Constants.sol";
import "../Utils.sol";
import "./TreeHasher.sol";
import "./BinaryMerkleProof.sol";
/// @title Binary Merkle Tree.
library BinaryMerkleTree {
/// @notice Verify if element exists in Merkle tree, given data, proof, and root.
/// @param root The root of the tree in which verify the given leaf.
/// @param proof Binary Merkle proof for the leaf.
/// @param data The data of the leaf to verify.
/// @return `true` is proof is valid, `false` otherwise.
/// @dev proof.numLeaves is necessary to determine height of subtree containing the data to prove.
function verify(bytes32 root, BinaryMerkleProof memory proof, bytes memory data) internal pure returns (bool) {
// Check proof is correct length for the key it is proving
if (proof.numLeaves <= 1) {
if (proof.sideNodes.length != 0) {
return false;
}
} else if (proof.sideNodes.length != pathLengthFromKey(proof.key, proof.numLeaves)) {
return false;
}
// Check key is in tree
if (proof.key >= proof.numLeaves) {
return false;
}
// A sibling at height 1 is created by getting the hash of the data to prove.
bytes32 digest = leafDigest(data);
// Null proof is only valid if numLeaves = 1
// If so, just verify hash(data) is root
if (proof.sideNodes.length == 0) {
if (proof.numLeaves == 1) {
return (root == digest);
} else {
return false;
}
}
bytes32 computedHash = computeRootHash(proof.key, proof.numLeaves, digest, proof.sideNodes);
return (computedHash == root);
}
/// @notice Use the leafHash and innerHashes to get the root merkle hash.
/// If the length of the innerHashes slice isn't exactly correct, the result is nil.
/// Recursive impl.
function computeRootHash(uint256 key, uint256 numLeaves, bytes32 leafHash, bytes32[] memory sideNodes)
private
pure
returns (bytes32)
{
if (numLeaves == 0) {
revert("cannot call computeRootHash with 0 number of leaves");
}
if (numLeaves == 1) {
if (sideNodes.length != 0) {
revert("unexpected inner hashes");
}
return leafHash;
}
if (sideNodes.length == 0) {
revert("expected at least one inner hash");
}
uint256 numLeft = _getSplitPoint(numLeaves);
bytes32[] memory sideNodesLeft = slice(sideNodes, 0, sideNodes.length - 1);
if (key < numLeft) {
bytes32 leftHash = computeRootHash(key, numLeft, leafHash, sideNodesLeft);
return nodeDigest(leftHash, sideNodes[sideNodes.length - 1]);
}
bytes32 rightHash = computeRootHash(key - numLeft, numLeaves - numLeft, leafHash, sideNodesLeft);
return nodeDigest(sideNodes[sideNodes.length - 1], rightHash);
}
/// @notice creates a slice of bytes32 from the data slice of bytes32 containing the elements
/// that correspond to the provided range.
/// It selects a half-open range which includes the begin element, but excludes the end one.
/// @param _data The slice that we want to select data from.
/// @param _begin The beginning of the range (inclusive).
/// @param _end The ending of the range (exclusive).
/// @return _ the sliced data.
function slice(bytes32[] memory _data, uint256 _begin, uint256 _end) internal pure returns (bytes32[] memory) {
if (_begin > _end) {
revert("Invalid range: _begin is greater than _end");
}
if (_begin > _data.length || _end > _data.length) {
revert("Invalid range: _begin or _end are out of bounds");
}
bytes32[] memory out = new bytes32[](_end - _begin);
for (uint256 i = _begin; i < _end; i++) {
out[i - _begin] = _data[i];
}
return out;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "../Constants.sol";
/// @notice Calculate the digest of a node.
/// @param left The left child.
/// @param right The right child.
/// @return digest The node digest.
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#binary-merkle-tree
// solhint-disable-next-line func-visibility
function nodeDigest(bytes32 left, bytes32 right) pure returns (bytes32 digest) {
digest = sha256(abi.encodePacked(Constants.NODE_PREFIX, left, right));
}
/// @notice Calculate the digest of a leaf.
/// @param data The data of the leaf.
/// @return digest The leaf digest.
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#binary-merkle-tree
// solhint-disable-next-line func-visibility
function leafDigest(bytes memory data) pure returns (bytes32 digest) {
digest = sha256(abi.encodePacked(Constants.LEAF_PREFIX, data));
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "./Types.sol";
library Constants {
///////////////
// Constants //
///////////////
/// @dev Maximum tree height
uint256 internal constant MAX_HEIGHT = 256;
/// @dev The prefixes of leaves and nodes
bytes1 internal constant LEAF_PREFIX = 0x00;
bytes1 internal constant NODE_PREFIX = 0x01;
}
/// @dev Parity share namespace.
/// utility function to provide the parity share namespace as a Namespace struct.
function PARITY_SHARE_NAMESPACE() pure returns (Namespace memory) {
return Namespace(0xFF, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "./NamespaceNode.sol";
/// @notice Namespace Merkle Tree Multiproof structure. Proves multiple leaves.
struct NamespaceMerkleMultiproof {
// The beginning key of the leaves to verify.
uint256 beginKey;
// The ending key of the leaves to verify.
uint256 endKey;
// List of side nodes to verify and calculate tree.
NamespaceNode[] sideNodes;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "./NamespaceNode.sol";
/// @notice Namespace Merkle Tree Proof structure.
struct NamespaceMerkleProof {
// List of side nodes to verify and calculate tree.
NamespaceNode[] sideNodes;
// The key of the leaf to verify.
uint256 key;
// The number of leaves in the tree
uint256 numLeaves;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "../Constants.sol";
import "../Types.sol";
import "../Utils.sol";
import "./NamespaceMerkleProof.sol";
import "./NamespaceMerkleMultiproof.sol";
import "./NamespaceNode.sol";
import "./TreeHasher.sol";
/// @title Namespace Merkle Tree.
library NamespaceMerkleTree {
/// @notice Verify if element exists in Merkle tree, given data, proof, and root.
/// @param root The root of the tree in which the given leaf is verified.
/// @param proof Namespace Merkle proof for the leaf.
/// @param namespace Namespace of the leaf.
/// @param data The data of the leaf to verify.
/// @return `true` if the proof is valid, `false` otherwise.
/// @dev proof.numLeaves is necessary to determine height of subtree containing the data to prove.
function verify(
NamespaceNode memory root,
NamespaceMerkleProof memory proof,
Namespace memory namespace,
bytes memory data
) internal pure returns (bool) {
// A sibling at height 1 is created by getting the leafDigest of the original data.
NamespaceNode memory node = leafDigest(namespace, data);
// Since we're verifying a leaf, height parameter is 1.
return verifyInner(root, proof, node, 1);
}
/// @notice Verify if inner node exists in Merkle tree, given node, proof, and root.
/// @param root The root of the tree in which the given leaf is verified.
/// @param proof Namespace Merkle proof for the leaf.
/// proof.key is any key in the subtree rooted at the inner node.
/// @param node The inner node to verify.
/// @param startingHeight Starting height of the proof.
/// @return `true` if the proof is valid, `false` otherwise.
/// @dev proof.numLeaves is necessary to determine height of subtree containing the data to prove.
function verifyInner(
NamespaceNode memory root,
NamespaceMerkleProof memory proof,
NamespaceNode memory node,
uint256 startingHeight
) internal pure returns (bool) {
// Check starting height is at least 1
if (startingHeight < 1) {
return false;
}
uint256 heightOffset = startingHeight - 1;
// Check proof is correct length for the key it is proving
if (proof.numLeaves <= 1) {
if (proof.sideNodes.length != 0) {
return false;
}
} else if (proof.sideNodes.length + heightOffset != pathLengthFromKey(proof.key, proof.numLeaves)) {
return false;
}
// Check key is in tree
if (proof.key >= proof.numLeaves) {
return false;
}
// Handle case where proof is empty: i.e, only one leaf exists, so verify hash(data) is root
// TODO handle case where inner node is actually the root of a tree with more than one node
if (proof.sideNodes.length == 0) {
if (proof.numLeaves == 1) {
return namespaceNodeEquals(root, node);
} else {
return false;
}
}
uint256 height = startingHeight;
uint256 stableEnd = proof.key;
// While the current subtree (of height 'height') is complete, determine
// the position of the next sibling using the complete subtree algorithm.
// 'stableEnd' tells us the ending index of the last full subtree. It gets
// initialized to 'key' because the first full subtree was the
// subtree of height 1, created above (and had an ending index of
// 'key').
while (true) {
// Determine if the subtree is complete. This is accomplished by
// rounding down the key to the nearest 1 << 'height', adding 1
// << 'height', and comparing the result to the number of leaves in the
// Merkle tree.
uint256 subTreeStartIndex = (proof.key / (1 << height)) * (1 << height);
uint256 subTreeEndIndex = subTreeStartIndex + (1 << height) - 1;
// If the Merkle tree does not have a leaf at index
// 'subTreeEndIndex', then the subtree of the current height is not
// a complete subtree.
if (subTreeEndIndex >= proof.numLeaves) {
break;
}
stableEnd = subTreeEndIndex;
// Determine if the key is in the first or the second half of
// the subtree.
if (proof.sideNodes.length + heightOffset <= height - 1) {
return false;
}
if (proof.key - subTreeStartIndex < (1 << (height - heightOffset - 1))) {
node = nodeDigest(node, proof.sideNodes[height - heightOffset - 1]);
} else {
node = nodeDigest(proof.sideNodes[height - heightOffset - 1], node);
}
height += 1;
}
// Determine if the next hash belongs to an orphan that was elevated. This
// is the case IFF 'stableEnd' (the last index of the largest full subtree)
// is equal to the number of leaves in the Merkle tree.
if (stableEnd != proof.numLeaves - 1) {
if (proof.sideNodes.length <= height - 1) {
return false;
}
node = nodeDigest(node, proof.sideNodes[height - heightOffset - 1]);
height += 1;
}
// All remaining elements in the proof set will belong to a left sibling.
while (height - heightOffset - 1 < proof.sideNodes.length) {
node = nodeDigest(proof.sideNodes[height - heightOffset - 1], node);
height += 1;
}
return namespaceNodeEquals(root, node);
}
/// @notice Verify if contiguous elements exists in Merkle tree, given leaves, mutliproof, and root.
/// @param root The root of the tree in which the given leaves are verified.
/// @param proof Namespace Merkle multiproof for the leaves.
/// @param namespace Namespace of the leaves. All leaves must have the same namespace.
/// @param data The leaves to verify. Note: leaf data must be the _entire_ share (including namespace prefixing).
/// @return `true` if the proof is valid, `false` otherwise.
function verifyMulti(
NamespaceNode memory root,
NamespaceMerkleMultiproof memory proof,
Namespace memory namespace,
bytes[] memory data
) internal pure returns (bool) {
// Hash all the leaves to get leaf nodes.
NamespaceNode[] memory nodes = new NamespaceNode[](data.length);
for (uint256 i = 0; i < data.length; ++i) {
nodes[i] = leafDigest(namespace, data[i]);
}
// Verify inclusion of leaf nodes.
return verifyMultiHashes(root, proof, nodes);
}
/// @notice Verify if contiguous leaf hashes exists in Merkle tree, given leaf nodes, multiproof, and root.
/// @param root The root of the tree in which the given leaf nodes are verified.
/// @param proof Namespace Merkle multiproof for the leaves.
/// @param leafNodes The leaf nodes to verify.
/// @return `true` if the proof is valid, `false` otherwise.
function verifyMultiHashes(
NamespaceNode memory root,
NamespaceMerkleMultiproof memory proof,
NamespaceNode[] memory leafNodes
) internal pure returns (bool) {
uint256 leafIndex = 0;
NamespaceNode[] memory leftSubtrees = new NamespaceNode[](proof.sideNodes.length);
for (uint256 i = 0; leafIndex != proof.beginKey && i < proof.sideNodes.length; ++i) {
uint256 subtreeSize = _nextSubtreeSize(leafIndex, proof.beginKey);
leftSubtrees[i] = proof.sideNodes[i];
leafIndex += subtreeSize;
}
// estimate the leaf size of the subtree containing the proof range
uint256 proofRangeSubtreeEstimate = _getSplitPoint(proof.endKey) * 2;
if (proofRangeSubtreeEstimate < 1) {
proofRangeSubtreeEstimate = 1;
}
(NamespaceNode memory rootHash, uint256 proofHead,,) =
_computeRoot(proof, leafNodes, 0, proofRangeSubtreeEstimate, 0, 0);
for (uint256 i = proofHead; i < proof.sideNodes.length; ++i) {
rootHash = nodeDigest(rootHash, proof.sideNodes[i]);
}
return namespaceNodeEquals(rootHash, root);
}
/// @notice Returns the size of the subtree adjacent to `begin` that does
/// not overlap `end`.
/// @param begin Begin index, inclusive.
/// @param end End index, exclusive.
function _nextSubtreeSize(uint256 begin, uint256 end) private pure returns (uint256) {
uint256 ideal = _bitsTrailingZeroes(begin);
uint256 max = _bitsLen(end - begin) - 1;
if (ideal > max) {
return 1 << max;
}
return 1 << ideal;
}
/// @notice Returns the number of trailing zero bits in `x`; the result is
/// 256 for `x` == 0.
/// @param x Number.
function _bitsTrailingZeroes(uint256 x) private pure returns (uint256) {
uint256 mask = 1;
uint256 count = 0;
while (x != 0 && mask & x == 0) {
count++;
x >>= 1;
}
return count;
}
/// @notice Computes the NMT root recursively.
/// @param proof Namespace Merkle multiproof for the leaves.
/// @param leafNodes Leaf nodes for which inclusion is proven.
/// @param begin Begin index, inclusive.
/// @param end End index, exclusive.
/// @param headProof Internal detail: head of proof sidenodes array. Used for recursion. Set to `0` on first call.
/// @param headLeaves Internal detail: head of leaves array. Used for recursion. Set to `0` on first call.
/// @return _ Subtree root.
/// @return _ New proof sidenodes array head. Used for recursion.
/// @return _ New leaves array head. Used for recursion.
/// @return _ If the subtree root is "nil."
function _computeRoot(
NamespaceMerkleMultiproof memory proof,
NamespaceNode[] memory leafNodes,
uint256 begin,
uint256 end,
uint256 headProof,
uint256 headLeaves
) private pure returns (NamespaceNode memory, uint256, uint256, bool) {
// reached a leaf
if (end - begin == 1) {
// if current range overlaps with proof range, pop and return a leaf
if (proof.beginKey <= begin && begin < proof.endKey) {
// Note: second return value is guaranteed to be `false` by
// construction.
return _popLeavesIfNonEmpty(leafNodes, headLeaves, leafNodes.length, headProof);
}
// if current range does not overlap with proof range,
// pop and return a proof node (leaf) if present,
// else return nil because leaf doesn't exist
return _popProofIfNonEmpty(proof.sideNodes, headProof, end, headLeaves);
}
// if current range does not overlap with proof range,
// pop and return a proof node if present,
// else return nil because subtree doesn't exist
if (end <= proof.beginKey || begin >= proof.endKey) {
return _popProofIfNonEmpty(proof.sideNodes, headProof, end, headLeaves);
}
// Recursively get left and right subtree
uint256 k = _getSplitPoint(end - begin);
(NamespaceNode memory left, uint256 newHeadProofLeft, uint256 newHeadLeavesLeft,) =
_computeRoot(proof, leafNodes, begin, begin + k, headProof, headLeaves);
(NamespaceNode memory right, uint256 newHeadProof, uint256 newHeadLeaves, bool rightIsNil) =
_computeRoot(proof, leafNodes, begin + k, end, newHeadProofLeft, newHeadLeavesLeft);
// only right leaf/subtree can be non-existent
if (rightIsNil == true) {
return (left, newHeadProof, newHeadLeaves, false);
}
NamespaceNode memory hash = nodeDigest(left, right);
return (hash, newHeadProof, newHeadLeaves, false);
}
/// @notice Pop from the leaf nodes array slice if it's not empty.
/// @param nodes Entire leaf nodes array.
/// @param headLeaves Head of leaf nodes array slice.
/// @param end End of leaf nodes array slice.
/// @param headProof Used only to return for recursion.
/// @return _ Popped node.
/// @return _ Head of proof sidenodes array slice (unchanged).
/// @return _ New head of leaf nodes array slice.
/// @return _ If the popped node is "nil."
function _popLeavesIfNonEmpty(NamespaceNode[] memory nodes, uint256 headLeaves, uint256 end, uint256 headProof)
private
pure
returns (NamespaceNode memory, uint256, uint256, bool)
{
(NamespaceNode memory node, uint256 newHead, bool isNil) = _popIfNonEmpty(nodes, headLeaves, end);
return (node, headProof, newHead, isNil);
}
/// @notice Pop from the proof sidenodes array slice if it's not empty.
/// @param nodes Entire proof sidenodes array.
/// @param headLeaves Head of proof sidenodes array slice.
/// @param end End of proof sidenodes array slice.
/// @param headProof Used only to return for recursion.
/// @return _ Popped node.
/// @return _ New head of proof sidenodes array slice.
/// @return _ Head of proof sidenodes array slice (unchanged).
/// @return _ If the popped node is "nil."
function _popProofIfNonEmpty(NamespaceNode[] memory nodes, uint256 headProof, uint256 end, uint256 headLeaves)
private
pure
returns (NamespaceNode memory, uint256, uint256, bool)
{
(NamespaceNode memory node, uint256 newHead, bool isNil) = _popIfNonEmpty(nodes, headProof, end);
return (node, newHead, headLeaves, isNil);
}
/// @notice Pop from an array slice if it's not empty.
/// @param nodes Entire array.
/// @param head Head of array slice.
/// @param end End of array slice.
/// @return _ Popped node.
/// @return _ New head of array slice.
/// @return _ If the popped node is "nil."
function _popIfNonEmpty(NamespaceNode[] memory nodes, uint256 head, uint256 end)
private
pure
returns (NamespaceNode memory, uint256, bool)
{
if (nodes.length == 0 || head >= nodes.length || head >= end) {
NamespaceNode memory node;
return (node, head, true);
}
return (nodes[head], head + 1, false);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "../Types.sol";
/// @notice Namespace Merkle Tree node.
struct NamespaceNode {
// Minimum namespace.
Namespace min;
// Maximum namespace.
Namespace max;
// Node value.
bytes32 digest;
}
/// @notice Compares two `NamespaceNode`s.
/// @param first First node.
/// @param second Second node.
/// @return `true` is equal, `false otherwise.
// solhint-disable-next-line func-visibility
function namespaceNodeEquals(NamespaceNode memory first, NamespaceNode memory second) pure returns (bool) {
return first.min.equalTo(second.min) && first.max.equalTo(second.max) && (first.digest == second.digest);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "../Constants.sol";
import "../Types.sol";
import "./NamespaceNode.sol";
/// @notice Get the minimum namespace.
// solhint-disable-next-line func-visibility
function namespaceMin(Namespace memory l, Namespace memory r) pure returns (Namespace memory) {
if (l.lessThan(r)) {
return l;
} else {
return r;
}
}
/// @notice Get the maximum namespace.
// solhint-disable-next-line func-visibility
function namespaceMax(Namespace memory l, Namespace memory r) pure returns (Namespace memory) {
if (l.greaterThan(r)) {
return l;
} else {
return r;
}
}
/// @notice Hash a leaf node.
/// @param namespace Namespace of the leaf.
/// @param data Raw data of the leaf.
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#namespace-merkle-tree
// solhint-disable-next-line func-visibility
function leafDigest(Namespace memory namespace, bytes memory data) pure returns (NamespaceNode memory) {
bytes32 digest = sha256(abi.encodePacked(Constants.LEAF_PREFIX, namespace.toBytes(), data));
NamespaceNode memory node = NamespaceNode(namespace, namespace, digest);
return node;
}
/// @notice Hash an internal node.
/// @param l Left child.
/// @param r Right child.
/// @dev More details in https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#namespace-merkle-tree
// solhint-disable-next-line func-visibility
function nodeDigest(NamespaceNode memory l, NamespaceNode memory r) pure returns (NamespaceNode memory) {
Namespace memory min = namespaceMin(l.min, r.min);
Namespace memory max;
if (l.min.equalTo(PARITY_SHARE_NAMESPACE())) {
max = PARITY_SHARE_NAMESPACE();
} else if (r.min.equalTo(PARITY_SHARE_NAMESPACE())) {
max = l.max;
} else {
max = namespaceMax(l.max, r.max);
}
bytes32 digest = sha256(
abi.encodePacked(
Constants.NODE_PREFIX,
l.min.toBytes(),
l.max.toBytes(),
l.digest,
r.min.toBytes(),
r.max.toBytes(),
r.digest
)
);
NamespaceNode memory node = NamespaceNode(min, max, digest);
return node;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
/// @notice A representation of the Celestia-app namespace ID and its version.
/// See: https://celestiaorg.github.io/celestia-app/specs/namespace.html
struct Namespace {
// The namespace version.
bytes1 version;
// The namespace ID.
bytes28 id;
}
using {equalTo, lessThan, greaterThan, toBytes} for Namespace global;
function equalTo(Namespace memory l, Namespace memory r) pure returns (bool) {
return l.toBytes() == r.toBytes();
}
function lessThan(Namespace memory l, Namespace memory r) pure returns (bool) {
return l.toBytes() < r.toBytes();
}
function greaterThan(Namespace memory l, Namespace memory r) pure returns (bool) {
return l.toBytes() > r.toBytes();
}
function toBytes(Namespace memory n) pure returns (bytes29) {
return bytes29(abi.encodePacked(n.version, n.id));
}
function toNamespace(bytes29 n) pure returns (Namespace memory) {
bytes memory id = new bytes(28);
for (uint256 i = 1; i < 29; i++) {
id[i - 1] = n[i];
}
return Namespace(n[0], bytes28(id));
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "./Constants.sol";
/// @notice Calculate the starting bit of the path to a leaf
/// @param numLeaves : The total number of leaves in the tree
/// @return startingBit : The starting bit of the path
// solhint-disable-next-line func-visibility
function getStartingBit(uint256 numLeaves) pure returns (uint256 startingBit) {
// Determine height of the left subtree. This is the maximum path length, so all paths start at this offset from the right-most bit
startingBit = 0;
while ((1 << startingBit) < numLeaves) {
startingBit += 1;
}
return Constants.MAX_HEIGHT - startingBit;
}
/// @notice Calculate the length of the path to a leaf
/// @param key: The key of the leaf
/// @param numLeaves: The total number of leaves in the tree
/// @return pathLength : The length of the path to the leaf
/// @dev A precondition to this function is that `numLeaves > 1`, so that `(pathLength - 1)` does not cause an underflow when pathLength = 0.
// solhint-disable-next-line func-visibility
function pathLengthFromKey(uint256 key, uint256 numLeaves) pure returns (uint256 pathLength) {
// Get the height of the left subtree. This is equal to the offset of the starting bit of the path
pathLength = Constants.MAX_HEIGHT - getStartingBit(numLeaves);
// Determine the number of leaves in the left subtree
uint256 numLeavesLeftSubTree = (1 << (pathLength - 1));
// If leaf is in left subtree, path length is full height of left subtree
if (key <= numLeavesLeftSubTree - 1) {
return pathLength;
}
// If left sub tree has only one leaf but key is not there, path has one additional step
else if (numLeavesLeftSubTree == 1) {
return 1;
}
// Otherwise, add 1 to height and recurse into right subtree
else {
return 1 + pathLengthFromKey(key - numLeavesLeftSubTree, numLeaves - numLeavesLeftSubTree);
}
}
/// @notice Returns the minimum number of bits required to represent `x`; the
/// result is 0 for `x` == 0.
/// @param x Number.
function _bitsLen(uint256 x) pure returns (uint256) {
uint256 count = 0;
while (x != 0) {
count++;
x >>= 1;
}
return count;
}
/// @notice Returns the largest power of 2 less than `x`.
/// @param x Number.
function _getSplitPoint(uint256 x) pure returns (uint256) {
// Note: since `x` is always an unsigned int * 2, the only way for this
// to be violated is if the input == 0. Since the input is the end
// index exclusive, an input of 0 is guaranteed to be invalid (it would
// be a proof of inclusion of nothing, which is vacuous).
require(x >= 1);
uint256 bitLen = _bitsLen(x);
uint256 k = 1 << (bitLen - 1);
if (k == x) {
k >>= 1;
}
return k;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;
import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
import "../../Constants.sol";
import "../../DataRootTuple.sol";
import "../../IDAOracle.sol";
import "../tree/binary/BinaryMerkleProof.sol";
import "../tree/binary/BinaryMerkleTree.sol";
import "../tree/namespace/NamespaceMerkleTree.sol";
import "../tree/Types.sol";
/// @notice Contains the necessary parameters to prove that some shares, which were posted to
/// the Celestia network, were committed to by the Blobstream smart contract.
struct SharesProof {
// The shares that were committed to.
bytes[] data;
// The shares proof to the row roots. If the shares span multiple rows, we will have multiple nmt proofs.
NamespaceMerkleMultiproof[] shareProofs;
// The namespace of the shares.
Namespace namespace;
// The rows where the shares belong. If the shares span multiple rows, we will have multiple rows.
NamespaceNode[] rowRoots;
// The proofs of the rowRoots to the data root.
BinaryMerkleProof[] rowProofs;
// The proof of the data root tuple to the data root tuple root that was posted to the Blobstream contract.
AttestationProof attestationProof;
}
/// @notice Contains the necessary parameters needed to verify that a data root tuple
/// was committed to, by the Blobstream smart contract, at some specif nonce.
struct AttestationProof {
// the attestation nonce that commits to the data root tuple.
uint256 tupleRootNonce;
// the data root tuple that was committed to.
DataRootTuple tuple;
// the binary merkle proof of the tuple to the commitment.
BinaryMerkleProof proof;
}
/// @title DAVerifier: Celestia -> EVM, Data Availability verifier.
/// @dev The DAVerifier verifies that some shares, which were posted on Celestia, were committed to
/// by the Blobstream smart contract.
library DAVerifier {
/////////////////
// Error codes //
/////////////////
enum ErrorCodes {
NoError,
/// @notice The shares to the rows proof is invalid.
InvalidSharesToRowsProof,
/// @notice The rows to the data root proof is invalid.
InvalidRowsToDataRootProof,
/// @notice The row to the data root proof is invalid.
InvalidRowToDataRootProof,
/// @notice The data root tuple to the data root tuple roof proof is invalid.
InvalidDataRootTupleToDataRootTupleRootProof,
/// @notice The number of share proofs isn't equal to the number of rows roots.
UnequalShareProofsAndRowRootsNumber,
/// @notice The number of rows proofs isn't equal to the number of rows roots.
UnequalRowProofsAndRowRootsNumber,
/// @notice The verifier data length isn't equal to the number of shares in the shares proofs.
UnequalDataLengthAndNumberOfSharesProofs,
/// @notice The number of leaves in the binary merkle proof is not divisible by 4.
InvalidNumberOfLeavesInProof,
/// @notice The provided range is invalid.
InvalidRange,
/// @notice The provided range is out of bounds.
OutOfBoundsRange
}
///////////////
// Functions //
///////////////
/// @notice Verifies that the shares, which were posted to Celestia, were committed to by the Blobstream smart contract.
/// @param _bridge The Blobstream smart contract instance.
/// @param _sharesProof The proof of the shares to the data root tuple root.
/// @param _root The data root of the block that contains the shares.
/// @return `true` if the proof is valid, `false` otherwise.
/// @return an error code if the proof is invalid, ErrorCodes.NoError otherwise.
function verifySharesToDataRootTupleRoot(IDAOracle _bridge, SharesProof memory _sharesProof, bytes32 _root)
internal
view
returns (bool, ErrorCodes)
{
// checking that the data root was committed to by the Blobstream smart contract.
(bool success, ErrorCodes errorCode) = verifyMultiRowRootsToDataRootTupleRoot(
_bridge, _sharesProof.rowRoots, _sharesProof.rowProofs, _sharesProof.attestationProof, _root
);
if (!success) {
return (false, errorCode);
}
// checking that the shares were committed to by the rows roots.
if (_sharesProof.shareProofs.length != _sharesProof.rowRoots.length) {
return (false, ErrorCodes.UnequalShareProofsAndRowRootsNumber);
}
uint256 numberOfSharesInProofs = 0;
for (uint256 i = 0; i < _sharesProof.shareProofs.length; i++) {
numberOfSharesInProofs += _sharesProof.shareProofs[i].endKey - _sharesProof.shareProofs[i].beginKey;
}
if (_sharesProof.data.length != numberOfSharesInProofs) {
return (false, ErrorCodes.UnequalDataLengthAndNumberOfSharesProofs);
}
uint256 cursor = 0;
for (uint256 i = 0; i < _sharesProof.shareProofs.length; i++) {
uint256 sharesUsed = _sharesProof.shareProofs[i].endKey - _sharesProof.shareProofs[i].beginKey;
(bytes[] memory s, ErrorCodes err) = slice(_sharesProof.data, cursor, cursor + sharesUsed);
if (err != ErrorCodes.NoError) {
return (false, err);
}
if (
!NamespaceMerkleTree.verifyMulti(
_sharesProof.rowRoots[i], _sharesProof.shareProofs[i], _sharesProof.namespace, s
)
) {
return (false, ErrorCodes.InvalidSharesToRowsProof);
}
cursor += sharesUsed;
}
return (true, ErrorCodes.NoError);
}
/// @notice Verifies that a row/column root, from a Celestia block, was committed to by the Blobstream smart contract.
/// @param _bridge The Blobstream smart contract instance.
/// @param _rowRoot The row/column root to be proven.
/// @param _rowProof The proof of the row/column root to the data root.
/// @param _root The data root of the block that contains the row.
/// @return `true` if the proof is valid, `false` otherwise.
/// @return an error code if the proof is invalid, ErrorCodes.NoError otherwise.
function verifyRowRootToDataRootTupleRoot(
IDAOracle _bridge,
NamespaceNode memory _rowRoot,
BinaryMerkleProof memory _rowProof,
AttestationProof memory _attestationProof,
bytes32 _root
) internal view returns (bool, ErrorCodes) {
// checking that the data root was committed to by the Blobstream smart contract
if (
!_bridge.verifyAttestation(
_attestationProof.tupleRootNonce, _attestationProof.tuple, _attestationProof.proof
)
) {
return (false, ErrorCodes.InvalidDataRootTupleToDataRootTupleRootProof);
}
bytes memory rowRoot = abi.encodePacked(_rowRoot.min.toBytes(), _rowRoot.max.toBytes(), _rowRoot.digest);
if (!BinaryMerkleTree.verify(_root, _rowProof, rowRoot)) {
return (false, ErrorCodes.InvalidRowToDataRootProof);
}
return (true, ErrorCodes.NoError);
}
/// @notice Verifies that a set of rows/columns, from a Celestia block, were committed to by the Blobstream smart contract.
/// @param _bridge The Blobstream smart contract instance.
/// @param _rowRoots The set of row/column roots to be proved.
/// @param _rowProofs The set of proofs of the _rowRoots in the same order.
/// @param _root The data root of the block that contains the rows.
/// @return `true` if the proof is valid, `false` otherwise.
/// @return an error code if the proof is invalid, ErrorCodes.NoError otherwise.
function verifyMultiRowRootsToDataRootTupleRoot(
IDAOracle _bridge,
NamespaceNode[] memory _rowRoots,
BinaryMerkleProof[] memory _rowProofs,
AttestationProof memory _attestationProof,
bytes32 _root
) internal view returns (bool, ErrorCodes) {
// checking that the data root was committed to by the Blobstream smart contract
if (
!_bridge.verifyAttestation(
_attestationProof.tupleRootNonce, _attestationProof.tuple, _attestationProof.proof
)
) {
return (false, ErrorCodes.InvalidDataRootTupleToDataRootTupleRootProof);
}
// checking that the rows roots commit to the data root.
if (_rowProofs.length != _rowRoots.length) {
return (false, ErrorCodes.UnequalRowProofsAndRowRootsNumber);
}
for (uint256 i = 0; i < _rowProofs.length; i++) {
bytes memory rowRoot =
abi.encodePacked(_rowRoots[i].min.toBytes(), _rowRoots[i].max.toBytes(), _rowRoots[i].digest);
if (!BinaryMerkleTree.verify(_root, _rowProofs[i], rowRoot)) {
return (false, ErrorCodes.InvalidRowsToDataRootProof);
}
}
return (true, ErrorCodes.NoError);
}
/// @notice computes the Celestia block square size from a row/column root to data root binary merkle proof.
/// Note: the provided proof is not authenticated to the Blobstream smart contract. It is the user's responsibility
/// to verify that the proof is valid and was successfully committed to using
// the `DAVerifier.verifyRowRootToDataRootTupleRoot()` method
/// Note: the minimum square size is 1. Thus, we don't expect the proof to have number of leaves equal to 0.
/// @param _proof The proof of the row/column root to the data root.
/// @return The square size of the corresponding block.
/// @return an error code if the _proof is invalid, Errors.NoError otherwise.
function computeSquareSizeFromRowProof(BinaryMerkleProof memory _proof)
internal
pure
returns (uint256, ErrorCodes)
{
if (_proof.numLeaves % 4 != 0) {
return (0, ErrorCodes.InvalidNumberOfLeavesInProof);
}
// we divide the number of leaves of the proof by 4 because the rows/columns tree is constructed
// from the extended block row roots and column roots.
return (_proof.numLeaves / 4, ErrorCodes.NoError);
}
/// @notice computes the Celestia block square size from a shares to row/column root proof.
/// Note: the provided proof is not authenticated to the Blobstream smart contract. It is the user's responsibility
/// to verify that the proof is valid and that the shares were successfully committed to using
/// the `DAVerifier.verifySharesToDataRootTupleRoot()` method.
/// Note: the minimum square size is 1. Thus, we don't expect the proof not to contain any side node.
/// @param _proof The proof of the shares to the row/column root.
/// @return The square size of the corresponding block.
function computeSquareSizeFromShareProof(NamespaceMerkleMultiproof memory _proof) internal pure returns (uint256) {
uint256 extendedSquareRowSize = 2 ** _proof.sideNodes.length;
// we divide the extended square row size by 2 because the square size is the
// the size of the row of the original square size.
return extendedSquareRowSize / 2;
}
/// @notice creates a slice of bytes from the data slice of bytes containing the elements
/// that correspond to the provided range.
/// It selects a half-open range which includes the begin element, but excludes the end one.
/// @param _data The slice that we want to select data from.
/// @param _begin The beginning of the range (inclusive).
/// @param _end The ending of the range (exclusive).
/// @return _ the sliced data.
function slice(bytes[] memory _data, uint256 _begin, uint256 _end)
internal
pure
returns (bytes[] memory, ErrorCodes)
{
if (_begin > _end) {
return (_data, ErrorCodes.InvalidRange);
}
if (_begin > _data.length || _end > _data.length) {
return (_data, ErrorCodes.OutOfBoundsRange);
}
bytes[] memory out = new bytes[](_end - _begin);
for (uint256 i = _begin; i < _end; i++) {
out[i - _begin] = _data[i];
}
return (out, ErrorCodes.NoError);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "../interfaces/IChainOracle.sol";
import "../interfaces/ICanonicalStateChain.sol";
import "blobstream-contracts/src/IDAOracle.sol";
/// @title ChallengeBase
/// @author LightLink Hummingbird
/// @custom:version v1.1.0-beta
/// @notice ChallengeBase is the base contract for all challenges. It contains
/// the global variables for challenge period, fee, and reward. The
/// owner can set the challenge period, fee, and reward. Thus is
/// expected to be the DAO Governance contract.
contract ChallengeBase is
UUPSUpgradeable,
OwnableUpgradeable,
ReentrancyGuardUpgradeable
{
/// @notice Maximum age of a block that can be challenged.
uint256 public challengeWindow;
/// @notice The period of time that a challenge is open for.
uint256 public challengePeriod;
/// @notice The fee required to make a challenge.
uint256 public challengeFee;
/// @notice The reward for successfully challenging a block.
uint256 public challengeReward;
/// @notice The address of the defender.
address public defender;
/// @notice The address of the chain oracle.
IChainOracle public chainOracle;
/// @notice The address of the canonical state chain.
ICanonicalStateChain public chain;
/// @notice The namespace used for data availability.
Namespace public daNamespace;
/// @notice The address of the data availability oracle.
IDAOracle public daOracle;
/// @notice This function is a special internal function that's part of
/// the UUPS upgradeable contract's lifecycle. When you want to
/// upgrade the contract to a new version, _authorizeUpgrade is
/// called to check whether the upgrade is authorized, thus
/// preventing anyone from just upgrading the contract.
/// @dev Only the owner can call this function.
function _authorizeUpgrade(address) internal override onlyOwner {}
/// @notice Initializes the contract with the chain, daOracle,
/// and chainOracle addresses.
/// @param _chain The address of the canonical state chain.
/// @param _daOracle The address of the data availability oracle.
/// @param _chainOracle The address of the chain oracle.
function __ChallengeBase_init(
address _chain,
address _daOracle,
address _chainOracle
) internal {
__UUPSUpgradeable_init();
__Ownable_init(msg.sender);
__ReentrancyGuard_init();
challengeWindow = 3 days;
challengePeriod = 2 days;
challengeFee = 1.5 ether;
challengeReward = 0.2 ether; // unused.
chain = ICanonicalStateChain(_chain);
daOracle = IDAOracle(_daOracle);
chainOracle = IChainOracle(_chainOracle);
}
/// @notice Ensures that the block is within the challenge window. It
/// is used to prevent challenges on blocks that are too old.
/// @param index The index of the block to check.
modifier mustBeWithinChallengeWindow(uint256 index) {
require(index != 0, "cannot challenge genesis block");
require(
block.timestamp <=
chain.headerMetadata(chain.chain(index)).timestamp +
challengeWindow,
"block is too old to challenge"
);
_;
}
/// @notice Ensures that the block is within the chain.
/// @param index The index of the block to check.
modifier mustBeCanonical(uint256 index) {
require(index <= chain.chainHead(), "block not in the chain yet");
_;
}
/// @notice Ensures the challenger has paid the challenge fee.
modifier requireChallengeFee() {
require(msg.value == challengeFee, "challenge fee not paid");
_;
}
/// @return The total time in seconds for a block to be finalized.
function finalizationSeconds() external view returns (uint256) {
return challengePeriod + challengeWindow;
}
/// @notice Sets the challenge window time in seconds.
/// @param _challengeWindow The new challenge window time.
/// @dev Only the owner can call this function.
function setChallengeWindow(uint256 _challengeWindow) external onlyOwner {
require(
_challengeWindow >= 12 hours && _challengeWindow <= 3 weeks,
"challenge window must be between 12 hours and 3 weeks"
);
challengeWindow = _challengeWindow;
}
/// @notice Sets the challenge period time in seconds.
/// @param _challengePeriod The new challenge period time.
/// @dev Only the owner can call this function.
function setChallengePeriod(uint256 _challengePeriod) external onlyOwner {
require(
_challengePeriod >= 12 hours && _challengePeriod <= 3 weeks,
"challenge period must be between 12 hours and 3 weeks"
);
challengePeriod = _challengePeriod;
}
/// @notice Sets the challenge fee in wei.
/// @param _challengeFee The new challenge fee.
/// @dev Only the owner can call this function.
function setChallengeFee(uint256 _challengeFee) external onlyOwner {
require(
_challengeFee >= 0.01 ether && _challengeFee <= 10 ether,
"challenge fee must be between 0.01 ether and 10 ether"
);
challengeFee = _challengeFee;
}
/// @notice Sets the challenge reward in wei.
/// @param _challengeReward The new challenge reward.
/// @dev Only the owner can call this function.
function setChallengeReward(uint256 _challengeReward) external onlyOwner {
require(
_challengeReward >= 0.01 ether && _challengeReward <= 10 ether,
"challenge reward must be between 0.01 ether and 10 ether"
);
challengeReward = _challengeReward;
}
/// @notice Sets the defender address.
/// @param _defender The new defender address.
/// @dev Only the owner can call this function.
function setDefender(address _defender) external onlyOwner {
require(_defender != address(0), "defender cannot be the zero address");
defender = _defender;
}
/// @notice Sets the namespace.
/// @param _namespace The new namespace.
/// @dev Only the owner can call this function.
function setDANamespace(Namespace memory _namespace) external onlyOwner {
daNamespace = _namespace;
}
/// @notice Sets the data availability oracle address.
/// @param _daOracle The new data availability oracle address.
/// @dev Only the owner can call this function.
function setDAOracle(address _daOracle) external onlyOwner {
require(_daOracle != address(0), "daOracle cannot be the zero address");
daOracle = IDAOracle(_daOracle);
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ChallengeBase.sol";
import "blobstream-contracts/src/lib/verifier/DAVerifier.sol";
import "hardhat/console.sol";
/// @title ChallengeDataAvailability
/// @author LightLink Hummingbird
/// @custom:version v1.1.0-beta
/// @notice ChallengeDataAvailability is a challenge for verifying a rollup blocks
/// data root has been included. (via Celestia Blobstream).
///
/// This is a challenge game between two parties: the challenger and the defender.
/// There can only be one challenge per rblock hash.
///
/// The Challenge goes through the following steps:
/// 1. A challenger initiates a challenge by calling challengeDataRootInclusion.
/// 2. The defending block publisher must provide a proof of inclusion for the
/// data root. If the proof is valid, the defender wins the challenge and
/// receives the challenge fee.
/// 3. Otherwise the challenge expires and the challenger wins the challenge and
/// the block is rolled back.
///
/// You can trigger a challenge easily via the hummingbird client:
/// `hb challenge-da <block-index>`.
abstract contract ChallengeDataAvailability is ChallengeBase {
/// @notice The different states a DA challenge can be in.
/// @param None - The DA challenge has not been initiated.
/// @param ChallengerInitiated - The DA challenge has been initiated by the challenger.
/// @param ChallengerWon - The DA challenge has been won by the challenger.
/// @param DefenderWon - The DA challenge has been won by the defender.
enum ChallengeDAStatus {
None,
ChallengerInitiated,
ChallengerWon,
DefenderWon
}
/// @notice The data structure for a DA challenge.
/// @param blockHash - The block hash of the block being challenged.
/// @param blockIndex - The index of the block being challenged.
/// @param pointerIndex - The index of the celestia pointer being challenged.
/// @param shareIndex - The index of the share being challenged.
/// @param challenger - The address of the challenger.
/// @param expiry - The expiry time of the challenge.
/// @param status - The status of the challenge.
/// @param claimed - Whether the challenge has been claimed.
struct ChallengeDA {
bytes32 blockHash;
uint256 blockIndex;
uint8 pointerIndex;
uint32 shareIndex;
address challenger;
uint256 expiry;
ChallengeDAStatus status;
bool claimed;
}
/// @notice The data structure for a DA challenge proof.
/// @param rootNonce - The nonce of the data root.
/// @param dataRootTuple - The data root tuple.
/// @param proof - The binary merkle proof.
struct ChallengeDAProof {
uint256 rootNonce;
DataRootTuple dataRootTuple;
BinaryMerkleProof proof;
}
/// @notice Emitted when a DA challenge is updated.
/// @param _blockHash - The block hash of the block being challenged.
/// @param _pointerIndex - The index of the celestia pointer being challenged.
/// @param _shareIndex - The index of the share being challenged.
/// @param _blockIndex - The index of the block being challenged.
/// @param _expiry - The expiry time of the challenge.
/// @param _status - The status of the challenge.
event ChallengeDAUpdate(
bytes32 indexed _blockHash,
uint256 indexed _pointerIndex,
uint32 _shareIndex,
uint256 _blockIndex,
uint256 _expiry,
ChallengeDAStatus indexed _status
);
/// @notice The mapping of challengeKey to challenges.
/// @dev There should only be one challenge per blockhash-celestiapointer pair.
mapping(bytes32 => ChallengeDA) public daChallenges;
/// @notice The fee required to make a challenge.
/// @dev Is disabled by default.
bool public isDAChallengeEnabled;
/// @notice Returns the reference key for a DA challenge.
/// @param _blockHash - The block hash of the block being challenged.
/// @param _pointerIndex - The index of the celestia pointer being challenged.
/// @param _shareIndex - The index of the share being challenged.
/// @return The reference key for the DA challenge.
function dataRootInclusionChallengeKey(
bytes32 _blockHash,
uint8 _pointerIndex,
uint32 _shareIndex
) public pure returns (bytes32) {
return
keccak256(abi.encodePacked(_blockHash, _pointerIndex, _shareIndex));
}
/// @notice Challenges the data root inclusion of a block.
/// @param _blockIndex - The index of the block to challenge.
/// @param _pointerIndex - The index of the celestia pointer to challenge.
/// @param _shareIndex - The index of the share to challenge.
/// @return The index of the block being challenged.
function challengeDataRootInclusion(
uint256 _blockIndex,
uint8 _pointerIndex,
uint32 _shareIndex
)
external
payable
mustBeCanonical(_blockIndex)
mustBeWithinChallengeWindow(_blockIndex) // TODO: use custom challenge period.
requireChallengeFee
returns (uint256)
{
require(isDAChallengeEnabled, "DA challenges are disabled");
bytes32 challengeBlockHash = chain.chain(_blockIndex);
bytes32 challengeKey = dataRootInclusionChallengeKey(
challengeBlockHash,
_pointerIndex,
_shareIndex
);
// check if there is already a challenge for this block.
ChallengeDA storage challenge = daChallenges[challengeKey];
require(
challenge.status == ChallengeDAStatus.None,
"challenge already exists"
);
ICanonicalStateChain.Header memory header = chain.getHeaderByNum(
_blockIndex
);
require(
_pointerIndex < header.celestiaPointers.length,
"invalid pointer index"
);
require(
_shareIndex >= header.celestiaPointers[_pointerIndex].shareStart &&
_shareIndex <
header.celestiaPointers[_pointerIndex].shareStart +
header.celestiaPointers[_pointerIndex].shareLen,
"invalid share index: not in pointers range"
);
// create a new challenge.
daChallenges[challengeKey] = ChallengeDA(
challengeBlockHash,
_blockIndex,
_pointerIndex,
_shareIndex,
msg.sender,
block.timestamp + challengePeriod,
ChallengeDAStatus.ChallengerInitiated,
false
);
emit ChallengeDAUpdate(
challengeBlockHash,
_pointerIndex,
_shareIndex,
_blockIndex,
block.timestamp + challengePeriod,
ChallengeDAStatus.ChallengerInitiated
);
return _blockIndex;
}
/// @notice Defends the data root inclusion of a block.
/// @param _challengeKey - The reference key of the challenge.
/// @param _proof - The proof of inclusion.
function defendDataRootInclusion(
bytes32 _challengeKey,
SharesProof memory _proof
) public nonReentrant {
ChallengeDA storage challenge = daChallenges[_challengeKey];
ICanonicalStateChain.Header memory header = chain.getHeaderByNum(
challenge.blockIndex
);
require(
challenge.status == ChallengeDAStatus.ChallengerInitiated,
"challenge is not in the correct state"
);
require(
header.celestiaPointers[challenge.pointerIndex].height ==
_proof.attestationProof.tuple.height,
"invalid celestia height"
);
// check the namespace
require(_proof.namespace.equalTo(daNamespace), "invalid namespace");
// verify the provided proof is valid – this also calls verifyAttestations.
(bool success, ) = DAVerifier.verifySharesToDataRootTupleRoot(
daOracle,
_proof,
_proof.attestationProof.tuple.dataRoot
);
require(success, "failed to verify shares to data root tuple root");
// calculate squaresize
(uint256 squaresize, ) = DAVerifier.computeSquareSizeFromRowProof(
_proof.rowProofs[0]
);
// check that the share index is within the celestia pointer range.
uint256 shareIndexInRow = _proof.shareProofs[0].beginKey;
uint256 shareIndexInRowMajorOrder = shareIndexInRow +
squaresize *
_proof.rowProofs[0].key;
require(
shareIndexInRowMajorOrder == challenge.shareIndex,
"proof must be provided for the challenged share index"
);
// update the challenge.
challenge.status = ChallengeDAStatus.DefenderWon;
emit ChallengeDAUpdate(
challenge.blockHash,
challenge.pointerIndex,
challenge.shareIndex,
challenge.blockIndex,
challenge.expiry,
ChallengeDAStatus.DefenderWon
);
// The defender can now call claimDAChallengeReward to claim the reward.
}
/// @notice Settles the data root inclusion challenge in favor of the challenger
/// if the defender does not respond within the challenge period.
/// @param _challengeKey - The reference key of the challenge.
function settleDataRootInclusion(
bytes32 _challengeKey
) public nonReentrant {
ChallengeDA storage challenge = daChallenges[_challengeKey];
require(
challenge.status == ChallengeDAStatus.ChallengerInitiated,
"challenge is not in the correct state"
);
require(
block.timestamp > challenge.expiry,
"challenge has not expired"
);
// update the challenge.
challenge.status = ChallengeDAStatus.ChallengerWon;
// rollback the chain.
chain.rollback(challenge.blockIndex - 1, challenge.blockHash);
emit ChallengeDAUpdate(
challenge.blockHash,
challenge.pointerIndex,
challenge.shareIndex,
challenge.blockIndex,
challenge.expiry,
ChallengeDAStatus.ChallengerWon
);
// The challenger can now call claimDAChallengeReward to claim the reward.
}
/// @notice Toggles the data availability challenges on or off.
/// @param _status - The status of the data availability challenges.
/// @dev Only the owner can call this function.
function toggleDAChallenge(bool _status) external onlyOwner {
isDAChallengeEnabled = _status;
}
/// @notice Claims the reward for a data root inclusion challenge.
/// @param _challengeKey - The reference key of the challenge.
function claimDAChallengeReward(
bytes32 _challengeKey
) external nonReentrant {
ChallengeDA storage challenge = daChallenges[_challengeKey];
require(
challenge.claimed == false,
"challenge has already been claimed"
);
require(
challenge.status == ChallengeDAStatus.ChallengerWon ||
challenge.status == ChallengeDAStatus.DefenderWon,
"challenge is not in the correct state"
);
challenge.claimed = true;
if (challenge.status == ChallengeDAStatus.ChallengerWon) {
(bool success, ) = challenge.challenger.call{value: challengeFee}(
""
);
require(success, "failed to pay challenger");
} else {
(bool success, ) = defender.call{value: challengeFee}("");
require(success, "failed to pay defender");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ChallengeBase.sol";
/// @title ChallengeHeader
/// @author LightLink Hummingbird
/// @custom:version v1.1.0-beta
/// @notice ChallengeHeader lets anyone challenge a block header against some basic validity checks.
/// If the header is invalid, the chain is rolled back to the previous block.
/// Note: This challenge is free and has no payout.
///
/// The challenge is made in a single step by calling invalidateHeader. This function directly checks
/// the validity of the header without requiring the defender to respond.
///
/// The following checks are made:
/// 1. The epoch is greater than the previous epoch.
/// 2. The l2Height is greater than the previous l2Height.
/// 3. The prevHash is the previous block hash.
/// 4. The bundle size is less than the max bundle size.
///
/// If any of these checks fail, the chain is rolled back to the previous block.
/// Just like with all challenges, the challenge window must be open.
abstract contract ChallengeHeader is ChallengeBase {
/// @notice The reasons a header can be invalid.
/// @param InvalidEpoch - The epoch is less than or equal to the previous epoch.
/// @param InvalidL2Height - The l2Height is less than or equal to the previous l2Height.
/// @param InvalidPrevHash - The prevHash is not the previous block hash.
/// @param InvalidBundleSize - The bundle size is greater than the max bundle size.
enum InvalidHeaderReason {
InvalidEpoch,
InvalidL2Height,
InvalidPrevHash,
InvalidBundleSize
}
/// @notice Emitted when a header is invalid.
/// @param _blockIndex - The block index of the invalid header.
/// @param _hash - The hash of the invalid header.
/// @param _reason - The reason the header is invalid.
event InvalidHeader(
uint256 indexed _blockIndex,
bytes32 indexed _hash,
InvalidHeaderReason indexed _reason
);
/// @notice Whether the header challenge is enabled.
/// @dev Is disabled by default.
bool public isHeaderChallengeEnabled;
/// @notice The maximum bundle size.
uint256 public maxBundleSize;
/// @notice Initializes the contract.
function __ChallengeHeader_init() internal {
maxBundleSize = 42000;
}
/// @notice Invalidate challenges a block header by checking that the header is valid.
/// @param _blockIndex - The block index of the header to challenge.
function invalidateHeader(
uint256 _blockIndex
)
external
mustBeCanonical(_blockIndex)
mustBeWithinChallengeWindow(_blockIndex)
{
require(isHeaderChallengeEnabled, "header challenge is disabled");
bytes32 _hash = chain.chain(_blockIndex);
ICanonicalStateChain.Header memory header = chain.getHeaderByNum(
_blockIndex
);
// check header validity.
require(!_isHeaderValid(header, _hash, _blockIndex), "header is valid");
// rollback the chain.
chain.rollback(_blockIndex - 1, _hash);
}
/// @notice Checks if a header is valid.
/// @param _header - The header to check.
/// @param _hash - The hash of the header.
/// @param _blockIndex - The block index of the header.
/// @return True if the header is valid.
function _isHeaderValid(
ICanonicalStateChain.Header memory _header,
bytes32 _hash,
uint256 _blockIndex
) internal returns (bool) {
// check that the blocks epoch is greater than the previous epoch.
if (_header.epoch <= chain.getHeaderByNum(_blockIndex - 1).epoch) {
emit InvalidHeader(
_header.epoch,
_hash,
InvalidHeaderReason.InvalidEpoch
);
return false;
}
// check that the l2 height is greater than the previous l2 height.
if (
_header.l2Height <= chain.getHeaderByNum(_blockIndex - 1).l2Height
) {
emit InvalidHeader(
_header.epoch,
_hash,
InvalidHeaderReason.InvalidL2Height
);
return false;
}
// check that the prevHash is the previous block hash.
if (_header.prevHash != chain.chain(_blockIndex - 1)) {
emit InvalidHeader(
_header.epoch,
_hash,
InvalidHeaderReason.InvalidPrevHash
);
return false;
}
// check that the bundle size is less than the max bundle size.
if (
_header.l2Height - chain.getHeaderByNum(_blockIndex - 1).l2Height >
maxBundleSize
) {
emit InvalidHeader(
_header.epoch,
_hash,
InvalidHeaderReason.InvalidBundleSize
);
return false;
}
return true;
}
/// @notice Enables or disables the header challenge.
/// @param _status - The status to set.
/// @dev Only the owner can call this function.
function toggleHeaderChallenge(bool _status) external onlyOwner {
isHeaderChallengeEnabled = _status;
}
/// @notice Sets the maximum bundle size.
/// @param _maxBundleSize - The new maximum bundle size.
/// @dev Only the owner can call this function.
function setMaxBundleSize(uint256 _maxBundleSize) external onlyOwner {
maxBundleSize = _maxBundleSize;
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ChallengeBase.sol";
/// @title ChallengeL2Header
/// @author LightLink Hummingbird
/// @custom:version v1.1.0-beta
/// @notice ChallengeL2Header is a two party challenge game where the defender must provide
/// a valid L2 header to defend against a challenge.
///
/// The Challenge goes through the following steps:
/// 1. A challenger initiates a challenge by calling challengeL2Header with the rblock
/// number and the number of the L2 block it should contain.
/// 2. The defending block publisher must provide valid L2 headers to the chainOracle
/// for both the challenged block and the previous block.
/// 3. If the headers are valid, the defender wins the challenge and receives the
/// challenge fee.
/// 4. Otherwise the challenge expires and the challenger wins the challenge and the
/// block is rolled back.
contract ChallengeL2Header is ChallengeBase {
/// @notice The different states a L2 header challenge can be in.
/// @param None - The L2 header challenge has not been initiated.
/// @param Initiated - The L2 header challenge has been initiated by the challenger.
/// @param ChallengerWon - The L2 header challenge has been won by the challenger.
/// @param DefenderWon - The L2 header challenge has been won by the defender.
enum L2HeaderChallengeStatus {
None,
Initiated,
ChallengerWon,
DefenderWon
}
/// @notice The pointer to an L2 header.
/// @param rblock - The rblock hash of the L2 header.
/// @param number - The number of the L2 header.
struct L2HeaderPointer {
bytes32 rblock;
uint256 number;
}
/// @notice The data structure for an L2 header challenge.
/// @param blockNum - The number of the L2 header being challenged.
/// @param header - The header being challenged.
/// @param prevHeader - The previous header.
/// @param challengeEnd - The end of the challenge period.
/// @param challenger - The address of the challenger.
/// @param status - The status of the challenge.
/// @param claimed - Whether the challenge has been claimed.
struct L2HeaderChallenge {
uint256 blockNum;
L2HeaderPointer header;
L2HeaderPointer prevHeader;
uint256 challengeEnd;
address challenger;
L2HeaderChallengeStatus status;
bool claimed;
}
/// @notice Emitted when an L2 header challenge is updated.
/// @param challengeHash - The hash of the challenge.
/// @param l2Number - The number of the L2 header being challenged.
/// @param rblock - The rblock hash of the L2 header.
/// @param expiry - The expiry time of the challenge.
/// @param status - The status of the challenge.
event L2HeaderChallengeUpdate(
bytes32 indexed challengeHash,
uint256 indexed l2Number,
bytes32 rblock,
uint256 expiry,
L2HeaderChallengeStatus indexed status
);
/// @notice Stores the L2 header challenges.
mapping(bytes32 => L2HeaderChallenge) public l2HeaderChallenges;
/// @notice Whether the L2 header challenge is enabled.
/// @dev Is disabled by default.
bool public isL2HeaderChallengeEnabled;
/// @notice Challenges an L2 header by providing the rblock number and the L2 number.
/// @param _rblockNum - The rblock number of the L2 header.
/// @param _l2Num - The number of the L2 header.
/// @return The hash of the challenge.
function challengeL2Header(
uint256 _rblockNum,
uint256 _l2Num
)
external
payable
mustBeCanonical(_rblockNum)
mustBeWithinChallengeWindow(_rblockNum)
requireChallengeFee
returns (bytes32)
{
require(isL2HeaderChallengeEnabled, "L2 header challenge is disabled");
// 1. Load the rblock and the previous rblock
bytes32 rblockHash = chain.chain(_rblockNum);
ICanonicalStateChain.Header memory rblock = chain.getHeaderByNum(
_rblockNum
);
ICanonicalStateChain.Header memory prevRBlock = chain.getHeaderByNum(
_rblockNum - 1
);
// 2. Check that this exact L2 header is not already challenged
bytes32 challengeHash = keccak256(abi.encodePacked(rblockHash, _l2Num));
require(
l2HeaderChallenges[challengeHash].status ==
L2HeaderChallengeStatus.None,
"challenge already exists"
);
// 3. Check that the L2 header is within the rblock bundle range
require(
_l2Num > prevRBlock.l2Height && _l2Num <= rblock.l2Height,
"L2 header must be within the rblock bundle range"
);
// 4. Check that the L2 header is not the first in the first rblock
require(
!(_rblockNum == 1 && _l2Num == prevRBlock.l2Height + 1),
"Cannot challenge the first L2 header in the first rblock"
);
// 5. Create pointer to the L2 header
L2HeaderPointer memory header = L2HeaderPointer(rblockHash, _l2Num);
// 6. Create a pointer the previous L2 header
L2HeaderPointer memory prevHeader = L2HeaderPointer(
rblockHash,
_l2Num - 1
);
if (_l2Num == prevRBlock.l2Height + 1) {
// If the L2 header is the first in the rblock, then the previous header is in the previous rblock
prevHeader = L2HeaderPointer(rblock.prevHash, prevRBlock.l2Height);
}
// 7. Create the challenge
l2HeaderChallenges[challengeHash] = L2HeaderChallenge(
_rblockNum,
header,
prevHeader,
block.timestamp + challengePeriod,
msg.sender,
L2HeaderChallengeStatus.Initiated,
false
);
// 8. Emit the challenge event
emit L2HeaderChallengeUpdate(
challengeHash,
_l2Num,
rblockHash,
block.timestamp + challengePeriod,
L2HeaderChallengeStatus.Initiated
);
return challengeHash;
}
/// @notice Defends an L2 header challenge by providing the L2 header and the previous L2 header.
/// @param _challengeHash - The hash of the challenge.
/// @param _headerHash - The hash of the L2 header.
/// @param _headerPrevHash - The hash of the previous L2 header.
function defendL2Header(
bytes32 _challengeHash,
bytes32 _headerHash,
bytes32 _headerPrevHash
) external nonReentrant {
L2HeaderChallenge storage challenge = l2HeaderChallenges[
_challengeHash
];
require(
challenge.status == L2HeaderChallengeStatus.Initiated,
"challenge is not in the correct state"
);
// 0. Check that the header and previous headers are part of the correct rblocks
// - This prevents rolled back l2 headers from being used to defend
require(
chainOracle.headerToRblock(_headerHash) == challenge.header.rblock,
"l2 header not loaded for the given rblock"
);
require(
chainOracle.headerToRblock(_headerPrevHash) ==
challenge.prevHeader.rblock,
"previous l2 header not loaded for the given rblock"
);
// 1. Load the header and previous header from the ChainOracle
IChainOracle.L2Header memory header = chainOracle.getHeader(
_headerHash
);
IChainOracle.L2Header memory prevHeader = chainOracle.getHeader(
_headerPrevHash
);
// 2. Check the headers has the correct number
require(
header.number == challenge.header.number,
"header number does not match"
);
require(
prevHeader.number == challenge.prevHeader.number,
"previous header number does not match"
);
// 3. Check the blocks are sequential
require(
header.parentHash == _headerPrevHash,
"header does not point to the previous header"
);
// 4. Check the timestamp is correct
require(
header.timestamp >= prevHeader.timestamp,
"header timestamp is too late"
);
require(
header.timestamp < block.timestamp,
"header timestamp is in the future"
);
require(
prevHeader.timestamp < block.timestamp,
"previous header timestamp is the future"
);
// finalise the challenge
challenge.status = L2HeaderChallengeStatus.DefenderWon;
// emit the event
emit L2HeaderChallengeUpdate(
_challengeHash,
challenge.header.number,
challenge.header.rblock,
challenge.challengeEnd,
L2HeaderChallengeStatus.DefenderWon
);
}
/// @notice Settles an L2 header challenge by paying out the challenger.
/// @param _challengeHash - The hash of the challenge.
/// @dev Can only be called after the challenge period has ended and a
/// defender has not responded.
function settleL2HeaderChallenge(bytes32 _challengeHash) external {
L2HeaderChallenge storage challenge = l2HeaderChallenges[
_challengeHash
];
require(
challenge.status == L2HeaderChallengeStatus.Initiated,
"challenge is not in the correct state"
);
require(
block.timestamp > challenge.challengeEnd,
"challenge period has not ended"
);
// finalise the challenge
challenge.status = L2HeaderChallengeStatus.ChallengerWon;
// rollback the block
chain.rollback(challenge.blockNum - 1, challenge.header.rblock);
emit L2HeaderChallengeUpdate(
_challengeHash,
challenge.header.number,
challenge.header.rblock,
challenge.challengeEnd,
L2HeaderChallengeStatus.ChallengerWon
);
}
/// @notice Returns the hash of an L2 header challenge.
/// @param _rblockHash - The rblock hash of the L2 header.
/// @param _l2Num - The number of the L2 header.
function l2HeaderChallengeHash(
bytes32 _rblockHash,
uint256 _l2Num
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_rblockHash, _l2Num));
}
/// @notice Toggles the L2 header challenges on or off.
/// @param _status - The status of the L2 header challenges.
/// @dev Only the owner can call this function.
function toggleL2HeaderChallenge(bool _status) external onlyOwner {
isL2HeaderChallengeEnabled = _status;
}
/// @notice Allows the challender or defender to claim the reward for an L2 header challenge.
/// @param _challengeKey - The key of the challenge.
function claimL2HeaderChallengeReward(
bytes32 _challengeKey
) external nonReentrant {
L2HeaderChallenge storage challenge = l2HeaderChallenges[_challengeKey];
require(
challenge.claimed == false,
"challenge has already been claimed"
);
require(
challenge.status == L2HeaderChallengeStatus.ChallengerWon ||
challenge.status == L2HeaderChallengeStatus.DefenderWon,
"challenge is not in the correct state"
);
challenge.claimed = true;
if (challenge.status == L2HeaderChallengeStatus.ChallengerWon) {
(bool success, ) = challenge.challenger.call{value: challengeFee}(
""
);
require(success, "failed to pay challenger");
} else {
(bool success, ) = defender.call{value: challengeFee}("");
require(success, "failed to pay defender");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICanonicalStateChain {
/// @notice The header struct represents a block header in the rollup chain.
/// @param epoch - Epoch refers to a block number on the Ethereum blockchain.
/// @param l2Height - L2Height is the index of the Last L2 Block in this bundle.
/// @param prevHash - PrevHash is the hash of the previous block bundle.
/// @param outputRoot - The output root = keccack(version_hash || keccack(state_root || withdrawal_root || latest_block_hash))
/// @param celestiaPointers - Pointer to the blocks contents on celestia.
/// See `Span` from https://docs.celestia.org/developers/blobstream-offchain#defining-a-chain
struct Header {
uint64 epoch;
uint64 l2Height;
bytes32 prevHash;
bytes32 outputRoot;
CelestiaPointer[] celestiaPointers;
}
/// @notice A pointer to a shares on Celestia.
/// @param height - The height of the block on Celestia.
/// @param shareStart - The start index of shares in block on Celestia.
/// @param shareLen - The length of the shares in block on Celestia.
struct CelestiaPointer {
uint64 height;
uint24 shareStart;
uint16 shareLen;
}
/// @notice The metadata of a block header.
/// @param timestamp - The timestamp the block was added.
/// @param publisher - The address of the publisher that added the block.
struct HeaderMetadata {
uint64 timestamp;
address publisher;
}
/// @notice Emitted when a new block is added to the chain.
/// @param blockNumber - The block number of the new block.
event BlockAdded(uint256 indexed blockNumber);
/// @notice Emitted when the chain is rolled back.
/// @param blockNumber - The block number the chain was rolled back to.
event Rolledback(uint256 indexed blockNumber);
/// @notice Emitted when the publisher address is changed.
/// @param publisher - The new publisher address.
event PublisherChanged(address indexed publisher);
/// @notice The address of the publisher. Publisher is the verified address
/// that can add new blocks to the chain. This address can be
/// replaced by the owner of the contract, (expected to be the
/// rollup contract).
/// @return The address of the publisher.
function publisher() external view returns (address);
/// @notice The address of the challenge contract. Challenge is the address
/// of the challenge contract. This contract can rollback the chain
/// after a successful challenge is made.
/// @return The address of the challenge contract.
function challenge() external view returns (address);
/// @notice The index of the last block in the chain.
/// @return The index of the last block in the chain.
function chainHead() external view returns (uint256);
/// @notice The canonical chain of block headers.
/// @return The block header.
function headers(bytes32) external view returns (Header memory);
/// @notice Returns the block header by hash.
/// @return The block header.
function getHeaderByHash(bytes32) external view returns (Header memory);
/// @notice The metadata of a block header.
/// @return The metadata of a block header.
function headerMetadata(
bytes32
) external view returns (HeaderMetadata memory);
/// @notice Returns the block hash by number.
/// @return The block hash.
function chain(uint256) external view returns (bytes32);
/// @notice Optimistically pushes block headers to the canonical chain.
/// The only fields that are checked are the epoch and prevHash.
/// @param _header - The block header to push.
function pushBlock(Header calldata _header) external;
/// @notice Returns the hash of a block header.
/// @param _header - The block header to hash.
/// @return The hash of the block header.
function hash(Header memory _header) external pure returns (bytes32);
/// @notice Returns the hash of a block header.
/// @param _index - The block number of the header.
/// @return The hash of the block header.
function getHeaderByNum(
uint256 _index
) external view returns (Header memory);
/// @notice Returns the header of the last block in the chain.
/// @return The header of the last block in the chain.
function getHead() external view returns (Header memory);
struct Output {
bytes32 outputRoot;
uint64 timestamp;
}
/// @notice get the output of a block.
/// @param _index - The block number of the output.
/// @return The output of the block.
function getL2Output(uint256 _index) external view returns (Output memory);
/// @notice Returns the starting timestamp of the chain.
/// @return The starting timestamp of the chain.
function startingTimestamp() external view returns (uint64);
/// @notice Rolls back the chain to a previous block number. Reverts
/// the chain to a previous state, It can only be called by
/// the challenge contract.
/// @param _blockNumber - The block number to rollback to.
/// @param _blockhash - The block hash to rollback to.
function rollback(uint256 _blockNumber, bytes32 _blockhash) external;
/// @notice Sets the publisher address.
/// @param _publisher - The new publisher address.
function setPublisher(address _publisher) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "blobstream-contracts/src/lib/verifier/DAVerifier.sol";
interface IChainOracle {
/// @notice The shares range struct represents the range of shares in a block.
/// @param start - The start index of the shares in the block.
/// @param end - The end index of the shares in the block.
struct ShareRange {
uint256 start;
uint256 end;
}
/// @notice An L2 Header.
/// @param parentHash - The hash of the parent block.
/// @param uncleHash - The hash of the uncle block.
/// @param beneficiary - The address of the beneficiary.
/// @param stateRoot - The state root hash.
/// @param transactionsRoot - The transactions root hash.
/// @param receiptsRoot - The receipts root hash.
/// @param logsBloom - The logs bloom filter.
/// @param difficulty - The difficulty of the block.
/// @param number - The block number.
/// @param gasLimit - The gas limit of the block.
/// @param gasUsed - The gas used in the block.
/// @param timestamp - The timestamp of the block.
/// @param extraData - The extra data of the block.
/// @param mixHash - The mix hash of the block.
/// @param nonce - The nonce of the block.
struct L2Header {
bytes32 parentHash;
bytes32 uncleHash;
address beneficiary;
bytes32 stateRoot;
bytes32 transactionsRoot;
bytes32 receiptsRoot;
bytes logsBloom;
uint256 difficulty;
uint256 number;
uint256 gasLimit;
uint256 gasUsed;
uint256 timestamp;
bytes extraData;
bytes32 mixHash;
uint256 nonce;
}
/// @notice A Legacy Transaction.
/// @param nonce - The nonce of the transaction.
/// @param gasPrice - The gas price of the transaction.
/// @param gas - The gas limit of the transaction.
/// @param to - The address of the recipient.
/// @param value - The value of the transaction.
/// @param data - The data of the transaction.
/// @param r - The r value of the signature.
/// @param s - The s value of the signature.
/// @param v - The v value of the signature.
struct LegacyTx {
uint64 nonce;
uint256 gasPrice;
uint64 gas;
address to;
uint256 value;
bytes data;
uint256 r;
uint256 s;
uint256 v;
}
/// @notice A Deposit Transaction.
/// @param chainId - The chain ID of the transaction.
/// @param nonce - The nonce of the transaction.
/// @param gasPrice - The gas price of the transaction.
/// @param gas - The gas limit of the transaction.
/// @param to - The address of the recipient.
/// @param value - The value of the transaction.
/// @param data - The data of the transaction.
/// @param r - The r value of the signature.
/// @param s - The s value of the signature.
/// @param v - The v value of the signature.
struct DepositTx {
uint256 chainId;
uint64 nonce;
uint256 gasPrice;
uint64 gas;
address to;
uint256 value;
bytes data;
uint256 r;
uint256 s;
uint256 v;
}
/// @notice Loads some shares that were uploaded to the Data
/// Availability layer. It verifies the shares are included in a
/// given rblock (bundle) and stores them in the contract.
/// @param _rblock - The rblock (bundle) that the shares are related to.
/// @param _pointer - The pointer to the shares in the rblock.
/// @param _proof - The proof that the shares are available and part of the
/// rblocks dataroot commitment.
/// @return The share key that the shares are stored under.
function provideShares(
bytes32 _rblock,
uint8 _pointer,
SharesProof memory _proof
) external returns (bytes32);
/// @notice Decodes the shares into an L2 header and stores it
/// in the contract.
/// @param _shareKey - The share key that the header is related to.
/// @param _range - The range of the shares that contain the header.
/// @return The hash of the header.
function provideHeader(
bytes32 _shareKey,
ShareRange[] calldata _range
) external returns (bytes32);
/// @notice Decodes the shares into a transaction and stores it
/// in the contract.
/// @param _shareKey - The share key that the transaction is related to.
/// @param _range - The range of the shares that contain the transaction.
/// @return The hash of the transaction.
function provideLegacyTx(
bytes32 _shareKey,
ShareRange[] calldata _range
) external returns (bytes32);
/// @notice Calulates the share key from the rblock and share data.
/// @param _rblock - The rblock that the shares are related to.
/// @param _shareData - The share data.
/// @return The share key.
function ShareKey(
bytes32 _rblock,
bytes[] memory _shareData
) external pure returns (bytes32);
/// @notice Stores shares that are provided to the contract.
/// @param _key - The key of the shares.
/// @return The shares.
function shares(bytes32 _key) external view returns (bytes[] memory);
/// @notice Stores headers that are provided to the contract.
/// @param _headerHash - The hash of the header.
/// @return The header.
function headers(
bytes32 _headerHash
) external view returns (L2Header memory);
/// @notice Stores transactions that are provided to the contract.
/// @param _txHash - The hash of the transaction.
/// @return The transaction.
function transactions(
bytes32 _txHash
) external view returns (DepositTx memory);
/// @notice Stores the header to rblock mapping.
/// @param _headerHash - The hash of the header.
/// @return The rblock.
function headerToRblock(
bytes32 _headerHash
) external view returns (bytes32);
/// @notice Returns the header for a given header hash.
/// @param _headerHash - The hash of the header.
/// @return The header.
function getHeader(
bytes32 _headerHash
) external view returns (L2Header memory);
/// @notice Returns the transaction for a given transaction hash.
/// @param _txHash - The hash of the transaction.
/// @return The transaction.
function getTransaction(
bytes32 _txHash
) external view returns (DepositTx memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
library console {
address constant CONSOLE_ADDRESS =
0x000000000000000000636F6e736F6c652e6c6f67;
function _sendLogPayloadImplementation(bytes memory payload) internal view {
address consoleAddress = CONSOLE_ADDRESS;
/// @solidity memory-safe-assembly
assembly {
pop(
staticcall(
gas(),
consoleAddress,
add(payload, 32),
mload(payload),
0,
0
)
)
}
}
function _castToPure(
function(bytes memory) internal view fnIn
) internal pure returns (function(bytes memory) pure fnOut) {
assembly {
fnOut := fnIn
}
}
function _sendLogPayload(bytes memory payload) internal pure {
_castToPure(_sendLogPayloadImplementation)(payload);
}
function log() internal pure {
_sendLogPayload(abi.encodeWithSignature("log()"));
}
function logInt(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function logUint(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function logString(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function logBool(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function logAddress(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function logBytes(bytes memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
}
function logBytes1(bytes1 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
}
function logBytes2(bytes2 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
}
function logBytes3(bytes3 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
}
function logBytes4(bytes4 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
}
function logBytes5(bytes5 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
}
function logBytes6(bytes6 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
}
function logBytes7(bytes7 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
}
function logBytes8(bytes8 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
}
function logBytes9(bytes9 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
}
function logBytes10(bytes10 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
}
function logBytes11(bytes11 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
}
function logBytes12(bytes12 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
}
function logBytes13(bytes13 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
}
function logBytes14(bytes14 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
}
function logBytes15(bytes15 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
}
function logBytes16(bytes16 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
}
function logBytes17(bytes17 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
}
function logBytes18(bytes18 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
}
function logBytes19(bytes19 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
}
function logBytes20(bytes20 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
}
function logBytes21(bytes21 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
}
function logBytes22(bytes22 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
}
function logBytes23(bytes23 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
}
function logBytes24(bytes24 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
}
function logBytes25(bytes25 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
}
function logBytes26(bytes26 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
}
function logBytes27(bytes27 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
}
function logBytes28(bytes28 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
}
function logBytes29(bytes29 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
}
function logBytes30(bytes30 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
}
function logBytes31(bytes31 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
}
function logBytes32(bytes32 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
}
function log(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function log(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function log(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function log(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function log(uint256 p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
}
function log(uint256 p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
}
function log(uint256 p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
}
function log(uint256 p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
}
function log(string memory p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
}
function log(string memory p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
}
function log(string memory p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
}
function log(string memory p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
}
function log(bool p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
}
function log(bool p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
}
function log(bool p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
}
function log(bool p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
}
function log(address p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
}
function log(address p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
}
function log(address p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
}
function log(address p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
}
function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
}
function log(uint256 p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
}
function log(uint256 p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
}
function log(uint256 p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
}
function log(uint256 p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
}
function log(uint256 p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
}
function log(uint256 p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
}
function log(uint256 p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
}
function log(uint256 p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
}
function log(string memory p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
}
function log(string memory p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
}
function log(string memory p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
}
function log(string memory p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
}
function log(string memory p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
}
function log(string memory p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
}
function log(string memory p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
}
function log(string memory p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
}
function log(string memory p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
}
function log(string memory p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
}
function log(string memory p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
}
function log(string memory p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
}
function log(bool p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
}
function log(bool p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
}
function log(bool p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
}
function log(bool p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
}
function log(bool p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
}
function log(bool p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
}
function log(bool p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
}
function log(bool p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
}
function log(bool p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
}
function log(bool p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
}
function log(bool p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
}
function log(bool p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
}
function log(bool p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
}
function log(bool p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
}
function log(bool p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
}
function log(bool p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
}
function log(address p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
}
function log(address p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
}
function log(address p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
}
function log(address p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
}
function log(address p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
}
function log(address p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
}
function log(address p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
}
function log(address p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
}
function log(address p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
}
function log(address p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
}
function log(address p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
}
function log(address p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
}
function log(address p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
}
function log(address p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
}
function log(address p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
}
function log(address p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_blockHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"_pointerIndex","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"_shareIndex","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"_blockIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_expiry","type":"uint256"},{"indexed":true,"internalType":"enum ChallengeDataAvailability.ChallengeDAStatus","name":"_status","type":"uint8"}],"name":"ChallengeDAUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_blockIndex","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"_hash","type":"bytes32"},{"indexed":true,"internalType":"enum ChallengeHeader.InvalidHeaderReason","name":"_reason","type":"uint8"}],"name":"InvalidHeader","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"l2Number","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"rblock","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":true,"internalType":"enum ChallengeL2Header.L2HeaderChallengeStatus","name":"status","type":"uint8"}],"name":"L2HeaderChallengeUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chain","outputs":[{"internalType":"contract ICanonicalStateChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainOracle","outputs":[{"internalType":"contract IChainOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_blockIndex","type":"uint256"},{"internalType":"uint8","name":"_pointerIndex","type":"uint8"},{"internalType":"uint32","name":"_shareIndex","type":"uint32"}],"name":"challengeDataRootInclusion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"challengeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rblockNum","type":"uint256"},{"internalType":"uint256","name":"_l2Num","type":"uint256"}],"name":"challengeL2Header","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"challengePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengeReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengeWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeKey","type":"bytes32"}],"name":"claimDAChallengeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeKey","type":"bytes32"}],"name":"claimL2HeaderChallengeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"daChallenges","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"uint256","name":"blockIndex","type":"uint256"},{"internalType":"uint8","name":"pointerIndex","type":"uint8"},{"internalType":"uint32","name":"shareIndex","type":"uint32"},{"internalType":"address","name":"challenger","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"enum ChallengeDataAvailability.ChallengeDAStatus","name":"status","type":"uint8"},{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daNamespace","outputs":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daOracle","outputs":[{"internalType":"contract IDAOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_blockHash","type":"bytes32"},{"internalType":"uint8","name":"_pointerIndex","type":"uint8"},{"internalType":"uint32","name":"_shareIndex","type":"uint32"}],"name":"dataRootInclusionChallengeKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeKey","type":"bytes32"},{"components":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"components":[{"internalType":"uint256","name":"beginKey","type":"uint256"},{"internalType":"uint256","name":"endKey","type":"uint256"},{"components":[{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"min","type":"tuple"},{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"max","type":"tuple"},{"internalType":"bytes32","name":"digest","type":"bytes32"}],"internalType":"struct NamespaceNode[]","name":"sideNodes","type":"tuple[]"}],"internalType":"struct NamespaceMerkleMultiproof[]","name":"shareProofs","type":"tuple[]"},{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"namespace","type":"tuple"},{"components":[{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"min","type":"tuple"},{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"max","type":"tuple"},{"internalType":"bytes32","name":"digest","type":"bytes32"}],"internalType":"struct NamespaceNode[]","name":"rowRoots","type":"tuple[]"},{"components":[{"internalType":"bytes32[]","name":"sideNodes","type":"bytes32[]"},{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"numLeaves","type":"uint256"}],"internalType":"struct BinaryMerkleProof[]","name":"rowProofs","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"tupleRootNonce","type":"uint256"},{"components":[{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"bytes32","name":"dataRoot","type":"bytes32"}],"internalType":"struct DataRootTuple","name":"tuple","type":"tuple"},{"components":[{"internalType":"bytes32[]","name":"sideNodes","type":"bytes32[]"},{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"numLeaves","type":"uint256"}],"internalType":"struct BinaryMerkleProof","name":"proof","type":"tuple"}],"internalType":"struct AttestationProof","name":"attestationProof","type":"tuple"}],"internalType":"struct SharesProof","name":"_proof","type":"tuple"}],"name":"defendDataRootInclusion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeHash","type":"bytes32"},{"internalType":"bytes32","name":"_headerHash","type":"bytes32"},{"internalType":"bytes32","name":"_headerPrevHash","type":"bytes32"}],"name":"defendL2Header","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalizationSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chain","type":"address"},{"internalType":"address","name":"_daOracle","type":"address"},{"internalType":"address","name":"_chainOracle","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_blockIndex","type":"uint256"}],"name":"invalidateHeader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isDAChallengeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isHeaderChallengeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isL2HeaderChallengeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_rblockHash","type":"bytes32"},{"internalType":"uint256","name":"_l2Num","type":"uint256"}],"name":"l2HeaderChallengeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"l2HeaderChallenges","outputs":[{"internalType":"uint256","name":"blockNum","type":"uint256"},{"components":[{"internalType":"bytes32","name":"rblock","type":"bytes32"},{"internalType":"uint256","name":"number","type":"uint256"}],"internalType":"struct ChallengeL2Header.L2HeaderPointer","name":"header","type":"tuple"},{"components":[{"internalType":"bytes32","name":"rblock","type":"bytes32"},{"internalType":"uint256","name":"number","type":"uint256"}],"internalType":"struct ChallengeL2Header.L2HeaderPointer","name":"prevHeader","type":"tuple"},{"internalType":"uint256","name":"challengeEnd","type":"uint256"},{"internalType":"address","name":"challenger","type":"address"},{"internalType":"enum ChallengeL2Header.L2HeaderChallengeStatus","name":"status","type":"uint8"},{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBundleSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeFee","type":"uint256"}],"name":"setChallengeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengePeriod","type":"uint256"}],"name":"setChallengePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeReward","type":"uint256"}],"name":"setChallengeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeWindow","type":"uint256"}],"name":"setChallengeWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes1","name":"version","type":"bytes1"},{"internalType":"bytes28","name":"id","type":"bytes28"}],"internalType":"struct Namespace","name":"_namespace","type":"tuple"}],"name":"setDANamespace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_daOracle","type":"address"}],"name":"setDAOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_defender","type":"address"}],"name":"setDefender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxBundleSize","type":"uint256"}],"name":"setMaxBundleSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeKey","type":"bytes32"}],"name":"settleDataRootInclusion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_challengeHash","type":"bytes32"}],"name":"settleL2HeaderChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"toggleDAChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"toggleHeaderChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"toggleL2HeaderChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a0806040523461002a5730608052614d9b9081610030823960805181818161165001526117f60152f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c806301c1aa0d14612e455780630200501d1461294e5780630eea9bab146122cd578063113e70fb14612238578063163a7177146121a057806317eef5b1146120e75780631b0ec391146120b75780631bd8f9ca14612099578063325898b1146120765780633323d3e414611b7457806335bf82f614611ac657806339e87c2214611aa35780633ea0c15e14611a855780634329b10114611a08578063485bc239146119d05780634c1b6e4b146119b25780634f1ef286146117b857806351ad15cf146116ba57806352d1902d1461163d57806355c20747146116065780635ae45d8b14610fe65780635bba0ea914610e475780635d475fdd14610da35780635dade41214610a855780636da802c8146109df578063715018a6146109745780637d3020ad146108be5780637f4c91c51461089557806380a2558a14610872578063861a1412146108555780638da5cb5b1461081f57806395618a28146107e7578063988c6671146107ab57806398e2dffb14610781578063a3be6534146106e9578063ad3cb1cc1461068c578063bc67745114610669578063bfcf449514610640578063c0c53b8b14610465578063c763e5a11461043c578063ee223c0214610413578063f2fde38b146103e6578063f3f480d9146103c8578063f8a22c6c1461024e5763fa8e8de21461020c57600080fd5b3461024b57604036600319011261024b57602060405181810190600435825260243560408201526040815261024081612ee8565b519020604051908152f35b80fd5b503461024b57602036600319011261024b57600435808252607160205260408220906006820190815491610293600160ff8560a01c1661028d81613184565b1461321e565b600584019283544211156103835760ff60a01b1916600160a11b1790556006548354600019810193916001600160a01b031690841161036f57859060018601948554823b1561036b57604484928360405195869485936334c9bca560e01b8552600485015260248401525af1801561036057610348575b505060407f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec2916002809601549454905482519182526020820152a480f35b61035190612f34565b61035c57843861030a565b8480fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526011600452602486fd5b60405162461bcd60e51b815260206004820152601e60248201527f6368616c6c656e676520706572696f6420686173206e6f7420656e64656400006044820152606490fd5b503461024b578060031936011261024b576020600154604051908152f35b503461024b57602036600319011261024b576104106104036131a4565b61040b61393f565b6138cb565b80f35b503461024b578060031936011261024b576008546040516001600160a01b039091168152602090f35b503461024b578060031936011261024b576006546040516001600160a01b039091168152602090f35b503461024b57606036600319011261024b5761047f6131a4565b6001600160a01b03602435818116929083900361063b576044359082821680920361063b577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009384549360ff8560401c1615946001600160401b03811680159081610633575b6001149081610629575b159081610620575b5061060e5767ffffffffffffffff1981166001178755856105ef575b5061051c61446d565b61052461446d565b61052c61446d565b610535336138cb565b61053d61446d565b61054561446d565b6001600080516020614d46833981519152556203f48087556202a3006001556714d1120d7b1600006002556702c68af0bb1400006003556001600160601b0360a01b9216826006541617600655816008541617600855600554161760055561a410603c556105b1575080f35b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff19166801000000000000000117865538610513565b60405163f92ee8a960e01b8152600490fd5b905015386104f7565b303b1591506104ef565b8791506104e5565b600080fd5b503461024b578060031936011261024b576005546040516001600160a01b039091168152602090f35b503461024b57602036600319011261024b5761068361393f565b600435603c5580f35b503461024b578060031936011261024b576106db604080516106ad81612f19565b6005815260208101640352e302e360dc1b8152825193849260208452518092816020860152858501906131fb565b601f01601f19168101030190f35b503461024b57602036600319011261024b576107036131a4565b61070b61393f565b6001600160a01b03168015610730576001600160601b0360a01b600854161760085580f35b60405162461bcd60e51b815260206004820152602360248201527f64614f7261636c652063616e6e6f7420626520746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b503461024b578060031936011261024b576107a3602091600154905490613570565b604051908152f35b503461024b57602036600319011261024b576004358015158091036107e3576107d261393f565b60ff8019603b5416911617603b5580f35b5080fd5b503461024b57602036600319011261024b576004358015158091036107e35761080e61393f565b60ff80196072541691161760725580f35b503461024b578060031936011261024b57600080516020614ce6833981519152546040516001600160a01b039091168152602090f35b503461024b578060031936011261024b5760209054604051908152f35b503461024b578060031936011261024b57602060ff607054166040519015158152f35b503461024b578060031936011261024b576004546040516001600160a01b039091168152602090f35b503461024b57602036600319011261024b576004356108db61393f565b662386f26fc1000081101580610962575b156108f75760035580f35b60405162461bcd60e51b815260206004820152603860248201527f6368616c6c656e676520726577617264206d757374206265206265747765656e60448201527f20302e303120657468657220616e6420313020657468657200000000000000006064820152608490fd5b50678ac7230489e800008111156108ec565b503461024b578060031936011261024b5761098d61393f565b600080516020614ce683398151915280546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461024b57602036600319011261024b57604061012091600435815260716020522060ff815491610a13600182016131dd565b610a1f600383016131dd565b916020600660058301549201549381868660a01c16946040519889528051828a015201516040880152805160608801520151608086015260a085015260018060a01b03821660c0850152610a7281613184565b60e084015260a81c161515610100820152f35b503461024b576020908160031936011261024b576004359160018060a01b0360065416926040516247a8e360e11b81528281600481885afa8015610d98578490610d69575b610ad791508211156136dc565b610ae2811515613728565b60405193631614b30360e21b9283865282600487015260249581818881865afa908115610c85578691610d3c575b5060405190630a2a343960e21b825260048201526040818881865afa908115610c85576001600160401b03610b5d92610b55928991610d0d575b505116875490613570565b4211156137aa565b60ff603b541615610cca5760405193845282600485015280848781855afa938415610cbf578594610c90575b5060405163392af9bf60e11b81526004810184905285818881865afa908115610c855785610bc09286928991610c63575b50613dab565b610c2e57506000198201918211610c1a57938484953b1561035c5784928360449260405196879586946334c9bca560e01b865260048601528401525af1801561036057610c0a5750f35b610c1390612f34565b61024b5780f35b5050634e487b7160e01b8252506011600452fd5b606490600f876040519262461bcd60e51b845260048401528201526e1a195859195c881a5cc81d985b1a59608a1b6044820152fd5b610c7f91503d808b833e610c778183612f62565b8101906133ec565b38610bba565b6040513d88823e3d90fd5b9080945081813d8311610cb8575b610ca88183612f62565b8101031261063b57519238610b89565b503d610c9e565b6040513d87823e3d90fd5b606490601c876040519262461bcd60e51b845260048401528201527f686561646572206368616c6c656e67652069732064697361626c6564000000006044820152fd5b610d2f915060403d604011610d35575b610d278183612f62565b810190613774565b38610b4a565b503d610d1d565b90508181813d8311610d62575b610d538183612f62565b8101031261063b575138610b10565b503d610d49565b508281813d8311610d91575b610d7f8183612f62565b8101031261063b57610ad79051610aca565b503d610d75565b6040513d86823e3d90fd5b503461024b57602036600319011261024b57600435610dc061393f565b61a8c081101580610e3a575b15610dd75760015580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e676520706572696f64206d757374206265206265747765656e60448201527420313220686f75727320616e642033207765656b7360581b6064820152608490fd5b50621baf80811115610dcc565b503461024b57602036600319011261024b57610e61613978565b6004358152606f60205260408120906004820191825492610e8a600160ff861661028d81613184565b60038201938454421115610fa15760ff191660021790556006546001820180549092916001600160a01b0316906000198101908111610f8d57825490823b15610f895790604486928360405195869485936334c9bca560e01b8552600485015260248401525af18015610d9857610f67575b50600080516020614d26833981519152600293948483549301549354905490610f4f60405192839263ffffffff60ff89169860081c168460409194939263ffffffff606083019616825260208201520152565b0390a46001600080516020614d468339815191525580f35b600293610f82600080516020614d2683398151915292612f34565b9350610efc565b8580fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601960248201527f6368616c6c656e676520686173206e6f742065787069726564000000000000006044820152606490fd5b50604036600319011261024b576006546040516247a8e360e11b81526001600160a01b0390911690602081600481855afa80156115315783906115d2575b611033915060043511156136dc565b6110406004351515613728565b604051631614b30360e21b808252600480359083015290602081602481865afa908115610d985784916115a0575b5060405190630a2a343960e21b82526004820152604081602481865afa8015610d98576001600160401b03610b55916110b3938791611581575b505116855490613570565b6110c060025434146137f6565b60ff607254161561153c576040519081526004356004820152602081602481855afa9081156115315783916114fb575b5060405163392af9bf60e11b81526004803590820152918383602481845afa928315610d985784936114df575b506004356000198101116114cb57836024916040519283809263392af9bf60e11b82526000196004350160048301525afa908115610d985784916114b1575b50604051602081019083825260243560408201526040815261117d81612ee8565b5190209283855260716020526111a960ff600660408820015460a01c166111a381613184565b1561383b565b6001600160401b036020830151166024351180611498575b1561143a5760016004351480611418575b6113ad57604051916111e383612f19565b8383526024356020840181905260001981011161036f5760405161120681612f19565b848152600019602435016020820152916001600160401b0361122d816020850151166138b3565b166024351461137c575b505061124560015442613570565b6040519160e083018381106001600160401b038211176113685760019594936020989389899460069460405260043584528184019788526040840190815260608401928352816080850198338a52604060a08701998d8b5260c0880199818b5281526071845220955186555180518c870155015160028501555180516003850155015160048301555160058201550192858060a01b0390511683549251916112ec83613184565b6112f583613184565b60ff60a81b9051151560a81b169269ffffffffffffffffffff60b01b16179060ff60a01b9060a01b161717905561132d825442613570565b60405191825284820152827f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec2604060243593a4604051908152f35b634e487b7160e01b88526041600452602488fd5b6001600160401b0391925060406020910151920151166040519161139f83612f19565b825260208201523880611237565b60405162461bcd60e51b815260206004820152603860248201527f43616e6e6f74206368616c6c656e676520746865206669727374204c3220686560448201527f6164657220696e207468652066697273742072626c6f636b00000000000000006064820152608490fd5b506001600160401b03611430816020850151166138b3565b16602435146111d2565b60405162461bcd60e51b815260206004820152603060248201527f4c3220686561646572206d7573742062652077697468696e207468652072626c60448201526f6f636b2062756e646c652072616e676560801b6064820152608490fd5b506001600160401b0360208201511660243511156111c1565b6114c591503d8086833e610c778183612f62565b3861115c565b634e487b7160e01b84526011600452602484fd5b6114f49193503d8086833e610c778183612f62565b913861111d565b90506020813d602011611529575b8161151660209383612f62565b810103126115255751386110f0565b8280fd5b3d9150611509565b6040513d85823e3d90fd5b60405162461bcd60e51b815260206004820152601f60248201527f4c3220686561646572206368616c6c656e67652069732064697361626c6564006044820152606490fd5b61159a915060403d604011610d3557610d278183612f62565b386110a8565b90506020813d6020116115ca575b816115bb60209383612f62565b8101031261036b57513861106e565b3d91506115ae565b506020813d6020116115fe575b816115ec60209383612f62565b81010312611525576110339051611024565b3d91506115df565b503461024b578060031936011261024b57604060075481519060ff60f81b8160f81b16825263ffffffff199060181b166020820152f35b503461024b578060031936011261024b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036116a85760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60405163703e46dd60e11b8152600490fd5b503461024b57602036600319011261024b576116d4613978565b6004358152606f6020526040812081600482016117318154916116fd60ff8460081c161561357d565b60ff83169061170b82613184565b61010060028314948580156117a5575b6117249061321e565b61ff001916179055613184565b156117765780808061176194600260018060a01b0391015460281c16600254905af161175b6135d4565b50613649565b6001600080516020614d468339815191525580f35b6004546002546117a093508291829182916001600160a01b03165af161179a6135d4565b50613604565b611761565b506117af84613184565b6003841461171b565b50604036600319011261024b576117cd6131a4565b6024356001600160401b038111611525576117ec903690600401612fb5565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114908115611984575b506116a85761182f61393f565b8216916040516352d1902d60e01b8152602081600481875afa859181611950575b5061186e57604051634c9c8ce360e01b815260048101859052602490fd5b9284937f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908181036119385750823b1561191f5780546001600160a01b0319168217905560405184917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a28351156119035750808360206118ff95519101845af46118f96135d4565b91614a07565b5080f35b9250505034611910575080f35b63b398979f60e01b8152600490fd5b604051634c9c8ce360e01b815260048101839052602490fd5b60249060405190632a87526960e21b82526004820152fd5b9091506020813d60201161197c575b8161196c60209383612f62565b81010312610f8957519038611850565b3d915061195f565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141538611822565b503461024b578060031936011261024b576020603c54604051908152f35b503461024b57602036600319011261024b576004358015158091036107e3576119f761393f565b60ff80196070541691161760705580f35b503461024b57604036600319011261024b57604051611a2681612f19565b6004356001600160f81b0319811681036115255781526024359063ffffffff19821682036115255760208101918252611a5d61393f565b5160f81c60075491610100600160e81b03905160181c169162ffffff60e81b16171760075580f35b503461024b578060031936011261024b576020600354604051908152f35b503461024b578060031936011261024b57602060ff607254166040519015158152f35b503461024b57602036600319011261024b57600435611ae361393f565b662386f26fc1000081101580611b62575b15611aff5760025580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e676520666565206d757374206265206265747765656e20302e60448201527418189032ba3432b91030b7321018981032ba3432b960591b6064820152608490fd5b50678ac7230489e80000811115611af4565b50606036600319011261024b57600435611b8c6131ba565b611b946131ca565b6006546040516247a8e360e11b815260209592916001600160a01b0316908681600481855afa8015610d98578490612047575b611bd491508611156136dc565b611bdf851515613728565b604051631614b30360e21b80825260048201879052936024919088828481875afa918215611fa6578192612018575b5060405191630a2a343960e21b835260048301526040828481875afa918215611fa6578192611ff7575b50611c53610b556001600160401b0380945116835490613570565b611c6060025434146137f6565b60ff6070541615611fb35760405195865287600487015288868481875afa958615611fa6578196611f77575b508281611c9a878a8a613695565b95868252606f8c52611cb960ff6004604085200154166111a381613184565b6040519283809263392af9bf60e11b82528d60048301525afa90811561036057906080918391611f5d575b500160ff815151981697881015611f21578962ffffff8082611d078c8651613538565b51015116928a63ffffffff8a16948510159384611ed1575b5050505015611e7a57611d3460015442613570565b926040519461010086019186831090831117611e68575089946001999897948c94600080516020614d2683398151915298946004946040528a84528684019189835260408501928d8452606086019283526040608087019233845260a08801968752606f60c089019b60018d5260e08a019b838d528352522095518655518e86015564ffffffff0060ff6002870194511684549351926001650100000000009060c81b03905160281b169366ffffffffffffff60c81b16179160081b161717905551600382015501915190611e0882613184565b611e1182613184565b60ff61ff0084549251151560081b1692169061ffff191617179055611e5d611e3a875442613570565b6040519384938460409194939263ffffffff606083019616825260208201520152565b0390a4604051908152f35b634e487b7160e01b8452604160045283fd5b60405162461bcd60e51b8152600481018b9052602a818601527f696e76616c696420736861726520696e6465783a206e6f7420696e20706f696e604482015269746572732072616e676560b01b6064820152608490fd5b839450818394611ef692611eeb60409561ffff9751613538565b510151169451613538565b5101511601818111611f0e5716811038808a8d611d1f565b634e487b7160e01b845260116004528584fd5b60405162461bcd60e51b8152600481018b9052601581860152740d2dcecc2d8d2c840e0ded2dce8cae440d2dcc8caf605b1b6044820152606490fd5b611f7191503d8085833e610c778183612f62565b38611ce4565b9095508881813d8311611f9f575b611f8f8183612f62565b81010312610f8957519438611c8c565b503d611f85565b50604051903d90823e3d90fd5b60405162461bcd60e51b8152600481018a9052601a818501527f4441206368616c6c656e676573206172652064697361626c65640000000000006044820152606490fd5b61201191925060403d604011610d3557610d278183612f62565b9038611c38565b9091508881813d8311612040575b6120308183612f62565b810103126107e357519038611c0e565b503d612026565b508681813d831161206f575b61205d8183612f62565b8101031261036b57611bd49051611bc7565b503d612053565b503461024b578060031936011261024b57602060ff603b54166040519015158152f35b503461024b578060031936011261024b576020600254604051908152f35b503461024b57606036600319011261024b5760206107a36120d66131ba565b6120de6131ca565b90600435613695565b503461024b57602036600319011261024b57612101613978565b600435815260716020526006604082200181600260ff8354612128828260a81c161561357d565b61214b828260a01c1661213a81613184565b84811490811561218c575b5061321e565b60a882901b1916600160a81b1780855560a01c1661216881613184565b03611776578080806117619460018060a01b03905416600254905af161175b6135d4565b6003915061219981613184565b1438612145565b503461024b57602036600319011261024b576121ba6131a4565b6121c261393f565b6001600160a01b031680156121e7576001600160601b0360a01b600454161760045580f35b60405162461bcd60e51b815260206004820152602360248201527f646566656e6465722063616e6e6f7420626520746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b503461024b57602036600319011261024b576040610100916004358152606f6020522060ff81549160018101546002820154916004600382015491015492848416926040519687526020870152848116604087015263ffffffff8160081c16606087015260018060a01b039060281c16608086015260a08501526122bb81613184565b60c084015260081c16151560e0820152f35b503461024b576003196040368201126107e357602435906001600160401b0382116115255760e0818336030112611525576040519160c083018381106001600160401b0382111761293a5760405280600401356001600160401b03811161035c5781013660238201121561035c5760048101359061234a82612f83565b916123586040519384612f62565b80835260051b81016024016020830136821161288d5760248301905b82821061290b5750505050835260248101356001600160401b03811161035c5781013660238201121561035c5760048101356123af81612f83565b916123bd6040519384612f62565b8183526024602084019260051b8201019036821161288d5760248101925b828410612891575050505060208401526123f83660448301612ffc565b604084015260848101356001600160401b03811161035c576124209060043691840101613047565b606084015260a48101356001600160401b03811161035c5781013660238201121561035c5760048101359061245482612f83565b916124626040519384612f62565b80835260051b81016024016020830136821161288d5760248301905b82821061285a5750505050608084015260c4810135906001600160401b03821161035c570160808136039283011261036b5760408051926124be84612ee8565b60048301358452602319011261036b576040516124da81612f19565b602482013581526044820135602082015260208301526064810135906001600160401b03821161035c57600461251392369201016130e8565b604082015260a0820152612525613978565b6004358252606f6020526040822060018060a01b0360065416906024846001830154936040519283809263392af9bf60e11b82528760048301525afa908115610cbf578591612840575b50608060048301549161258a600160ff851661028d81613184565b0151936001600160401b036125a860028501549660ff881690613538565b515116602060a0830151015151036127fb5760408101516126086125fa604051926125d284612f19565b60075460f881901b6001600160f81b031916855260181b63ffffffff19166020850152613fee565b9162ffffff19918291613fee565b169116036127c25760085460a082015160209081015101516126349183906001600160a01b03166139a8565b50156127655761265061264a6080830151613515565b51613d8d565b5090602061266f608061266583850151613515565b5151930151613515565b51015191828102928184041490151715612751579061268d91613570565b9263ffffffff8560081c168094036126ee57600394610f4f60ff9287600080516020614d26833981519152958519161760048701558786549601549060405194859416978460409194939263ffffffff606083019616825260208201520152565b60405162461bcd60e51b815260206004820152603560248201527f70726f6f66206d7573742062652070726f766964656420666f722074686520636044820152740d0c2d8d8cadccecac840e6d0c2e4ca40d2dcc8caf605b1b6064820152608490fd5b634e487b7160e01b87526011600452602487fd5b60405162461bcd60e51b815260206004820152602f60248201527f6661696c656420746f207665726966792073686172657320746f20646174612060448201526e1c9bdbdd081d1d5c1b19481c9bdbdd608a1b6064820152608490fd5b60405162461bcd60e51b8152602060048201526011602482015270696e76616c6964206e616d65737061636560781b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f696e76616c69642063656c6573746961206865696768740000000000000000006044820152606490fd5b61285491503d8087833e610c778183612f62565b3861256f565b81356001600160401b0381116128895760209161287e8392602436918901016130e8565b81520191019061247e565b8980fd5b8780fd5b83356001600160401b0381116128895782016060602319823603011261288957604051916128be83612ee8565b60248201358352604482013560208401526064820135926001600160401b038411612907576128f7602094936024869536920101613047565b60408201528152019301926123db565b8b80fd5b81356001600160401b0381116128895760209161292f839260243691890101612fb5565b815201910190612374565b634e487b7160e01b85526041600452602485fd5b503461024b57606036600319011261024b57602490604480359060043590843590612977613978565b82855260209060718252604086209060068201908154906129a3600160ff8460a01c1661028d81613184565b60018060a01b0360055416604051968b8789637afdc39160e01b9283825284600483015281865afa988915612d2a578c99612e16575b506001870154809903612dc157604051908152600481018b905287818e81865afa908115612d2a578c91612d94575b50600387015403612d355760405163172c2b0f60e31b8082526004820192909252908b828e81865afa918215612d2a578d8d928d928495612d0e575b506040519586938492835260048301525afa918215612d03578b92612cdf575b50610100998a8201519a6002880154809c03612c9c57830151600488015403612c4b57815103612bf257610160809101908151920191825111612bae5751421115612b61574290511015612b0f575060ff60a01b1916600360a01b17905560050154604080519384529183015260039392917f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec29190a46001600080516020614d468339815191525580f35b847f70726576696f7573206865616465722074696d657374616d702069732074686560849260278d6040519462461bcd60e51b86526004860152840152820152662066757475726560c81b6064820152fd5b60405162461bcd60e51b8152600481018790526021818d01527f6865616465722074696d657374616d7020697320696e2074686520667574757281840152606560f81b6064820152608490fd5b5060405162461bcd60e51b815260048101879052601c818d01527f6865616465722074696d657374616d7020697320746f6f206c6174650000000081840152606490fd5b5060405162461bcd60e51b815260048101879052602c818d01527f68656164657220646f6573206e6f7420706f696e7420746f2074686520707265818401526b3b34b7bab9903432b0b232b960a11b6064820152608490fd5b60405162461bcd60e51b8152600481018990526025818f01527f70726576696f757320686561646572206e756d62657220646f6573206e6f742081860152640dac2e8c6d60db1b6064820152608490fd5b6064898f87601c7f686561646572206e756d62657220646f6573206e6f74206d6174636800000000926040519462461bcd60e51b86526004860152840152820152fd5b612cfc9192503d808d833e612cf48183612f62565b8101906132d1565b9038612a64565b6040513d8d823e3d90fd5b612d239195503d8086833e612cf48183612f62565b9338612a44565b6040513d8e823e3d90fd5b5060405162461bcd60e51b8152600481018790526032818d01527f70726576696f7573206c3220686561646572206e6f74206c6f6164656420666f8184015271722074686520676976656e2072626c6f636b60701b6064820152608490fd5b90508781813d8311612dba575b612dab8183612f62565b81010312612907575138612a08565b503d612da1565b60405162461bcd60e51b8152600481018990526029818f01527f6c3220686561646572206e6f74206c6f6164656420666f7220746865206769768186015268656e2072626c6f636b60b81b6064820152608490fd5b9098508781813d8311612e3e575b612e2e8183612f62565b81010312612907575197386129d9565b503d612e24565b503461024b57602036600319011261024b57600435612e6261393f565b61a8c081101580612edb575b15612e7857815580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e67652077696e646f77206d757374206265206265747765656e60448201527420313220686f75727320616e642033207765656b7360581b6064820152608490fd5b50621baf80811115612e6e565b606081019081106001600160401b03821117612f0357604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b03821117612f0357604052565b6001600160401b038111612f0357604052565b608081019081106001600160401b03821117612f0357604052565b90601f801991011681019081106001600160401b03821117612f0357604052565b6001600160401b038111612f035760051b60200190565b6001600160401b038111612f0357601f01601f191660200190565b81601f8201121561063b57803590612fcc82612f9a565b92612fda6040519485612f62565b8284526020838301011161063b57816000926020809301838601378301015290565b919082604091031261063b5760405161301481612f19565b9182908035906001600160f81b03198216820361063b57908252602001359063ffffffff198216820361063b5760200152565b81601f8201121561063b57803590602061306083612f83565b936040906130716040519687612f62565b8486526020860191602060a08097028601019482861161063b57602001925b8584106130a1575050505050505090565b868484031261063b5784879183516130b881612ee8565b6130c28688612ffc565b81526130d086868901612ffc565b83820152608087013585820152815201930192613090565b91909160608184031261063b576040519061310282612ee8565b819381356001600160401b03811161063b57820181601f8201121561063b57602091813561312f81612f83565b9261313d6040519485612f62565b818452848085019260051b82010192831161063b578401905b8282106131755750505083528082013590830152604090810135910152565b81358152908401908401613156565b6004111561318e57565b634e487b7160e01b600052602160045260246000fd5b600435906001600160a01b038216820361063b57565b6024359060ff8216820361063b57565b6044359063ffffffff8216820361063b57565b906040516131ea81612f19565b602060018294805484520154910152565b60005b83811061320e5750506000910152565b81810151838201526020016131fe565b1561322557565b60405162461bcd60e51b815260206004820152602560248201527f6368616c6c656e6765206973206e6f7420696e2074686520636f727265637420604482015264737461746560d81b6064820152608490fd5b51906001600160a01b038216820361063b57565b81601f8201121561063b5780516132a281612f9a565b926132b06040519485612f62565b8184526020828401011161063b576132ce91602080850191016131fb565b90565b9060208282031261063b5781516001600160401b039283821161063b5701906101e092838383031261063b5760405193840184811082821117612f0357604052825184526020830151602085015261332b60408401613278565b6040850152606083015160608501526080830151608085015260a083015160a085015260c083015181811161063b578261336691850161328c565b60c085015260e083015160e08501526101008084015190850152610120808401519085015261014080840151908501526101608084015190850152610180918284015191821161063b576133bb91840161328c565b908301526101a080820151908301526101c0809101519082015290565b51906001600160401b038216820361063b57565b906020808383031261063b5782516001600160401b039384821161063b57019060a08284031261063b5760409081519460a0860186811082821117612f03578352613436846133d8565b86526134438285016133d8565b82870152828401518387015260609360608101516060880152608081015191821161063b57019184601f8401121561063b5782519061348182612f83565b9561348e82519788612f62565b82875283606081890194028601019481861161063b578401925b8584106134be5750505050505050608082015290565b868483031261063b578251906134d382612ee8565b6134dc856133d8565b82528585015162ffffff8116810361063b5786830152838501519061ffff8216820361063b57828792868b9501528152019301926134a8565b8051156135225760200190565b634e487b7160e01b600052603260045260246000fd5b80518210156135225760209160051b010190565b600101908160011161355a57565b634e487b7160e01b600052601160045260246000fd5b9190820180921161355a57565b1561358457565b60405162461bcd60e51b815260206004820152602260248201527f6368616c6c656e67652068617320616c7265616479206265656e20636c61696d604482015261195960f21b6064820152608490fd5b3d156135ff573d906135e582612f9a565b916135f36040519384612f62565b82523d6000602084013e565b606090565b1561360b57565b60405162461bcd60e51b81526020600482015260166024820152753330b4b632b2103a37903830bc903232b332b73232b960511b6044820152606490fd5b1561365057565b60405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f20706179206368616c6c656e67657200000000000000006044820152606490fd5b604080516020810192835260f89390931b6001600160f81b0319169083015260e09290921b6001600160e01b0319166041820152602581526136d681612ee8565b51902090565b156136e357565b60405162461bcd60e51b815260206004820152601a60248201527f626c6f636b206e6f7420696e2074686520636861696e207965740000000000006044820152606490fd5b1561372f57565b60405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74206368616c6c656e67652067656e6573697320626c6f636b00006044820152606490fd5b9081604091031261063b576137a260206040519261379184612f19565b61379a816133d8565b845201613278565b602082015290565b156137b157565b60405162461bcd60e51b815260206004820152601d60248201527f626c6f636b20697320746f6f206f6c6420746f206368616c6c656e67650000006044820152606490fd5b156137fd57565b60405162461bcd60e51b815260206004820152601660248201527518da185b1b195b99d948199959481b9bdd081c185a5960521b6044820152606490fd5b1561384257565b60405162461bcd60e51b815260206004820152601860248201527f6368616c6c656e676520616c72656164792065786973747300000000000000006044820152606490fd5b9061010091820391821161355a57565b60001981019190821161355a57565b9190820391821161355a57565b9060016001600160401b038093160191821161355a57565b6001600160a01b0390811690811561392657600080516020614ce683398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020614ce6833981519152546001600160a01b0316330361396057565b60405163118cdaa760e01b8152336004820152602490fd5b600080516020614d4683398151915260028154146139965760029055565b604051633ee5aeb560e01b8152600490fd5b916139c5919392606085015160808601519060a087015192614057565b9015613d86575060208201515160608301515103613d7d576000805b60208401518051831015613a2b57600191613a1d6020613a0486613a2395613538565b510151613a158660208a0151613538565b5151906138a6565b90613570565b9101906139e1565b50905091909181515103613d7457600090815b60208201518051841015613d68576020613a5b85613a6c93613538565b510151613a15856020860151613538565b93613a83835183613a7d8882613570565b91614223565b600b81949294101561318e5780613d5b5750613aa3856060860151613538565b5190613ab3866020870151613538565b5191604086015197613ac58651614333565b9660005b8751811015613b9e5760206000613b488d613af7613ae7868e613538565b5191613af16142ee565b50613fee565b90613b37604051918683019386855262ffffff1916602184015282603e91613b27815180928b86860191016131fb565b810103601e810184520182612f62565b6040519283928392519283916131fb565b8101039060025afa15613b925760019060005160405190613b6882612ee8565b8d82528d60208301526040820152613b80828c613538565b52613b8b818b613538565b5001613ac9565b6040513d6000823e3d90fd5b5096955092969190939750600094613bba604089015151614333565b95805b89518082141580613d4d575b15613c16578a82613bee856040613be6613c0a96613c10986146e2565b940151613538565b51613bf9868d613538565b52613c04858c613538565b50613570565b9161445e565b90613bbd565b5050509294509290969495613c2e602082015161474b565b60019381851b918083046002149015171561355a5760008083613c61938880969210613d45575b9082869594928861477c565b5050939093925b613d0a575b5050509081613c919251613c82835191613fee565b9062ffffff1980958192613fee565b169116149283613cde575b5082613ccb575b505015613cc15750600191613cb791613570565b9301919092613a3e565b6000955093505050565b6040919250810151910151143880613ca3565b90925060208301519080613cff613cf9602086015194613fee565b93613fee565b169116149138613c9c565b90919260408201518051851015613d3b578391613d2a86613d3193613538565b5190614889565b9301919081613c68565b5092829150613c6d565b859150613c55565b5060408b0151518310613bc9565b9550509250505060009190565b50505050600190600090565b50600090600790565b60009150600590565b6000925090565b6040015160038116613da25760021c90600090565b50600090600890565b80516006546001600160a01b0316939192916001600160401b0391821690600019810190811161355a57604080519663392af9bf60e11b938489528360048a01526000988981602481865afa908115613fe4578a929188918491613fca575b5051161015613fad57506020928388018681511684518781528360048201528b81602481885afa908115613f6857899188918e8092613f92575b50500151161015613f7257888401518451631614b30360e21b815260048101849052908682602481885afa918215613f6857908c949392918592613f32575b5003613f11578760249151169685519485938492835260048301525afa918215613f085750908492918891613eee575b500151169003818111610f8d5781603c54911611613ed45750505050600190565b6003925116600080516020614d068339815191528480a490565b613f0291503d808a833e610c778183612f62565b38613eb3565b513d89823e3d90fd5b505050505050506002925116600080516020614d068339815191528480a490565b888092949596508193503d8311613f61575b613f4e8183612f62565b8101031261290757518b93929138613e83565b503d613f44565b86513d8e823e3d90fd5b5050505050506001925116600080516020614d068339815191528480a490565b613fa692503d8091833e610c778183612f62565b388e613e44565b9693505050505116600080516020614d068339815191528380a490565b613fde91503d8086833e610c778183612f62565b38613e0a565b84513d8c823e3d90fd5b80516020918201516040516001600160f81b031990921692820192835263ffffffff19166021820152601d815261402481612f19565b51905162ffffff19918282169190601d8110614042575b5050905090565b83919250601d0360031b1b161680388061403b565b9192939093805192602080948184015192604080950151838651958694631f3302a960e01b865260048601528051602486015201516044840152608060648401528560e484019180519260606084870152835180915286610104870194019060005b818110614207575050508581015160a4860152015160c48401528290039082906001600160a01b03165afa9081156141fc576000916141c6575b50156141b95783518551036141ac5760005b845181101561419e5761418361412561411e8389613538565b5151613fee565b61413b86614133858b613538565b510151613fee565b9084614147858b613538565b5101519085519262ffffff198092168985015216603d830152605a9081830152815261417281612f47565b61417c8388613538565b5185614383565b1561419057600101614105565b505050505050600090600290565b505050505050600190600090565b5050505050600090600690565b5050505050600090600490565b8481813d83116141f5575b6141db8183612f62565b810103126107e3575190811515820361024b5750386140f3565b503d6141d1565b82513d6000823e3d90fd5b825186528c988a9850958601958b9550909201916001016140b9565b91908181116142e65782518082119081156142dc575b506142d45761424881836138a6565b9261425284612f83565b936142606040519586612f62565b80855261426f601f1991612f83565b0160005b8181106142c3575050815b83811061428f575050505090600090565b806142bc61429f60019385613538565b516142aa86846138a6565b906142b5828a613538565b5287613538565b500161427e565b806060602080938901015201614273565b505090600a90565b9050821138614239565b505090600990565b604051906142fb82612ee8565b6000604083815161430b81612f19565b8381528360208201528152815161432181612f19565b83815283602082015260208201520152565b9061433d82612f83565b61434a6040519182612f62565b828152809261435b601f1991612f83565b019060005b82811061436c57505050565b6020906143776142ee565b82828501015201614360565b604082018051929391926001811161443f5750835151614436575b602084019182518251111561442c5760006143e7602092604051613b37602182878101948786526143d7815180928b86860191016131fb565b8101036001810184520182612f62565b8101039060025afa15613b9257600051935191825115614415579061441193949151905190614557565b1490565b5051600114159050614425571490565b5050600090565b5050505050600090565b50505050600090565b6144508551519160208701516144ae565b1461439e5750505050600090565b600019811461355a5760010190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561449c57565b604051631afcd79f60e31b8152600490fd5b909160005b60018481831b10156144df578101809111156144b357634e487b7160e01b600052601160045260246000fd5b509291909261010090810390811161355a576144fa90613887565b91600161450684613897565b1b9161451183613897565b811161451d5750505090565b919250906001830361453157505050600190565b8261454261454e94614548936138a6565b926138a6565b906144ae565b6132ce9061354c565b909182156146815760018314614630578351156145eb576145778361474b565b61458a6145848651613897565b86614a6a565b928181106145c757816145426145aa96936145a4936138a6565b90614557565b6145c1826145bb6132ce9451613897565b90613538565b51614b2e565b6145d19450614557565b906145e46132ce92916145bb8151613897565b5190614b2e565b60405162461bcd60e51b815260206004820181905260248201527f6578706563746564206174206c65617374206f6e6520696e6e657220686173686044820152606490fd5b929150505161463c5790565b60405162461bcd60e51b815260206004820152601760248201527f756e657870656374656420696e6e6572206861736865730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152603360248201527f63616e6e6f742063616c6c20636f6d70757465526f6f744861736820776974686044820152722030206e756d626572206f66206c656176657360681b6064820152608490fd5b90918160005b83151580614740575b15614709576146ff9061445e565b9260011c926146e8565b92506147199061471e92946138a6565b614b70565b60001981019190821161355a5781600192821161473a57501b90565b90501b90565b5083600116156146f1565b6001811061063b5761475c81614b70565b600019810190811161355a576001901b9081146147765790565b60011c90565b93959492909261478a6142ee565b50600161479784846138a6565b146148445784518211801590614836575b61481a576147d5906147c26147bd85856138a6565b61474b565b976147cd8986613570565b85878961477c565b5091976147f096929591946147ea9190613570565b9161477c565b9194909392909115156001146148115761480991614889565b929190600090565b50929190600090565b93604091935061482e959692500151614bb0565b929391929091565b5060208501518310156147a8565b939495918086949294511115908161487b575b5061486a5750604061482e940151614bb0565b805161482e95509193919250614b91565b905060208601511138614857565b906148926142ee565b506148a08251825190614bc6565b916000916040918251936148b385612f19565b8085526020809501526148e181516148d26148cc614c06565b91613fee565b9062ffffff1980938192613fee565b169116146000146149c3576148f4614c06565b925b6149008351613fee565b918561490e88860151613fee565b940151918161491d8251613fee565b8861492a8b850151613fee565b93015194828a5198818d8b0199600160f81b8b521660218b015216603e890152605b88015216607b86015216609884015260b583015260b5825260e082018281106001600160401b03821117612f035785928161499060009482895283519283916131fb565b8101039060025afa156149b857600051928251946149ad86612ee8565b855284015282015290565b50513d6000823e3d90fd5b825181806149db613cf96149d5614c06565b94613fee565b169116146000146149f05784820151926148f6565b614a01858301518685015190614c40565b926148f6565b90614a2e5750805115614a1c57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614a61575b614a3f575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614a37565b919082518111614ad157614a7d81612f83565b90614a8b6040519283612f62565b808252601f19614a9a82612f83565b0136602084013760005b818110614ab2575090925050565b80614abf60019287613538565b51614aca8286613538565b5201614aa4565b60405162461bcd60e51b815260206004820152602f60248201527f496e76616c69642072616e67653a205f626567696e206f72205f656e6420617260448201526e65206f7574206f6620626f756e647360881b6064820152608490fd5b614b5d6000916020936040519085820192600160f81b84526021830152604182015260418152613b3781612f47565b8101039060025afa15613b925760005190565b806000915b614b7d575090565b90614b879061445e565b9060011c80614b75565b90614ba89291949394614ba26142ee565b50614c7b565b919392909190565b90614bbe9291614ba26142ee565b919390929190565b9060006020604051614bd781612f19565b8281520152614be582613fee565b62ffffff1980614bf484613fee565b1691161015614c01575090565b905090565b60006020604051614c1681612f19565b8281520152604051614c2781612f19565b6001600160f81b0319815263ffffffff19602082015290565b9060006020604051614c5181612f19565b8281520152614c5f82613fee565b62ffffff1980614c6e84613fee565b1691161115614c01575090565b90809392614c876142ee565b508251908115918215614cda575b508115614ccf575b50614cbe57614cab91613538565b516001830180931161355a579190600090565b5050614cc86142ee565b9190600190565b905081101538614c9d565b831015915038614c9556fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300ea46f8ad2711844c28d6aa0fe8ed10b1ac38bdcdc6df7ba3b8f3bfc35232f31b6c1c38434bf7781d35ea9020730ba834cfde2300c18c12141e82e3662d6c45669b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220cfde574c4593203fc6cfec8a585ed7644e003a73041d087092e5e3e1abc0c31564736f6c63430008160033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c806301c1aa0d14612e455780630200501d1461294e5780630eea9bab146122cd578063113e70fb14612238578063163a7177146121a057806317eef5b1146120e75780631b0ec391146120b75780631bd8f9ca14612099578063325898b1146120765780633323d3e414611b7457806335bf82f614611ac657806339e87c2214611aa35780633ea0c15e14611a855780634329b10114611a08578063485bc239146119d05780634c1b6e4b146119b25780634f1ef286146117b857806351ad15cf146116ba57806352d1902d1461163d57806355c20747146116065780635ae45d8b14610fe65780635bba0ea914610e475780635d475fdd14610da35780635dade41214610a855780636da802c8146109df578063715018a6146109745780637d3020ad146108be5780637f4c91c51461089557806380a2558a14610872578063861a1412146108555780638da5cb5b1461081f57806395618a28146107e7578063988c6671146107ab57806398e2dffb14610781578063a3be6534146106e9578063ad3cb1cc1461068c578063bc67745114610669578063bfcf449514610640578063c0c53b8b14610465578063c763e5a11461043c578063ee223c0214610413578063f2fde38b146103e6578063f3f480d9146103c8578063f8a22c6c1461024e5763fa8e8de21461020c57600080fd5b3461024b57604036600319011261024b57602060405181810190600435825260243560408201526040815261024081612ee8565b519020604051908152f35b80fd5b503461024b57602036600319011261024b57600435808252607160205260408220906006820190815491610293600160ff8560a01c1661028d81613184565b1461321e565b600584019283544211156103835760ff60a01b1916600160a11b1790556006548354600019810193916001600160a01b031690841161036f57859060018601948554823b1561036b57604484928360405195869485936334c9bca560e01b8552600485015260248401525af1801561036057610348575b505060407f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec2916002809601549454905482519182526020820152a480f35b61035190612f34565b61035c57843861030a565b8480fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526011600452602486fd5b60405162461bcd60e51b815260206004820152601e60248201527f6368616c6c656e676520706572696f6420686173206e6f7420656e64656400006044820152606490fd5b503461024b578060031936011261024b576020600154604051908152f35b503461024b57602036600319011261024b576104106104036131a4565b61040b61393f565b6138cb565b80f35b503461024b578060031936011261024b576008546040516001600160a01b039091168152602090f35b503461024b578060031936011261024b576006546040516001600160a01b039091168152602090f35b503461024b57606036600319011261024b5761047f6131a4565b6001600160a01b03602435818116929083900361063b576044359082821680920361063b577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009384549360ff8560401c1615946001600160401b03811680159081610633575b6001149081610629575b159081610620575b5061060e5767ffffffffffffffff1981166001178755856105ef575b5061051c61446d565b61052461446d565b61052c61446d565b610535336138cb565b61053d61446d565b61054561446d565b6001600080516020614d46833981519152556203f48087556202a3006001556714d1120d7b1600006002556702c68af0bb1400006003556001600160601b0360a01b9216826006541617600655816008541617600855600554161760055561a410603c556105b1575080f35b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff19166801000000000000000117865538610513565b60405163f92ee8a960e01b8152600490fd5b905015386104f7565b303b1591506104ef565b8791506104e5565b600080fd5b503461024b578060031936011261024b576005546040516001600160a01b039091168152602090f35b503461024b57602036600319011261024b5761068361393f565b600435603c5580f35b503461024b578060031936011261024b576106db604080516106ad81612f19565b6005815260208101640352e302e360dc1b8152825193849260208452518092816020860152858501906131fb565b601f01601f19168101030190f35b503461024b57602036600319011261024b576107036131a4565b61070b61393f565b6001600160a01b03168015610730576001600160601b0360a01b600854161760085580f35b60405162461bcd60e51b815260206004820152602360248201527f64614f7261636c652063616e6e6f7420626520746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b503461024b578060031936011261024b576107a3602091600154905490613570565b604051908152f35b503461024b57602036600319011261024b576004358015158091036107e3576107d261393f565b60ff8019603b5416911617603b5580f35b5080fd5b503461024b57602036600319011261024b576004358015158091036107e35761080e61393f565b60ff80196072541691161760725580f35b503461024b578060031936011261024b57600080516020614ce6833981519152546040516001600160a01b039091168152602090f35b503461024b578060031936011261024b5760209054604051908152f35b503461024b578060031936011261024b57602060ff607054166040519015158152f35b503461024b578060031936011261024b576004546040516001600160a01b039091168152602090f35b503461024b57602036600319011261024b576004356108db61393f565b662386f26fc1000081101580610962575b156108f75760035580f35b60405162461bcd60e51b815260206004820152603860248201527f6368616c6c656e676520726577617264206d757374206265206265747765656e60448201527f20302e303120657468657220616e6420313020657468657200000000000000006064820152608490fd5b50678ac7230489e800008111156108ec565b503461024b578060031936011261024b5761098d61393f565b600080516020614ce683398151915280546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461024b57602036600319011261024b57604061012091600435815260716020522060ff815491610a13600182016131dd565b610a1f600383016131dd565b916020600660058301549201549381868660a01c16946040519889528051828a015201516040880152805160608801520151608086015260a085015260018060a01b03821660c0850152610a7281613184565b60e084015260a81c161515610100820152f35b503461024b576020908160031936011261024b576004359160018060a01b0360065416926040516247a8e360e11b81528281600481885afa8015610d98578490610d69575b610ad791508211156136dc565b610ae2811515613728565b60405193631614b30360e21b9283865282600487015260249581818881865afa908115610c85578691610d3c575b5060405190630a2a343960e21b825260048201526040818881865afa908115610c85576001600160401b03610b5d92610b55928991610d0d575b505116875490613570565b4211156137aa565b60ff603b541615610cca5760405193845282600485015280848781855afa938415610cbf578594610c90575b5060405163392af9bf60e11b81526004810184905285818881865afa908115610c855785610bc09286928991610c63575b50613dab565b610c2e57506000198201918211610c1a57938484953b1561035c5784928360449260405196879586946334c9bca560e01b865260048601528401525af1801561036057610c0a5750f35b610c1390612f34565b61024b5780f35b5050634e487b7160e01b8252506011600452fd5b606490600f876040519262461bcd60e51b845260048401528201526e1a195859195c881a5cc81d985b1a59608a1b6044820152fd5b610c7f91503d808b833e610c778183612f62565b8101906133ec565b38610bba565b6040513d88823e3d90fd5b9080945081813d8311610cb8575b610ca88183612f62565b8101031261063b57519238610b89565b503d610c9e565b6040513d87823e3d90fd5b606490601c876040519262461bcd60e51b845260048401528201527f686561646572206368616c6c656e67652069732064697361626c6564000000006044820152fd5b610d2f915060403d604011610d35575b610d278183612f62565b810190613774565b38610b4a565b503d610d1d565b90508181813d8311610d62575b610d538183612f62565b8101031261063b575138610b10565b503d610d49565b508281813d8311610d91575b610d7f8183612f62565b8101031261063b57610ad79051610aca565b503d610d75565b6040513d86823e3d90fd5b503461024b57602036600319011261024b57600435610dc061393f565b61a8c081101580610e3a575b15610dd75760015580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e676520706572696f64206d757374206265206265747765656e60448201527420313220686f75727320616e642033207765656b7360581b6064820152608490fd5b50621baf80811115610dcc565b503461024b57602036600319011261024b57610e61613978565b6004358152606f60205260408120906004820191825492610e8a600160ff861661028d81613184565b60038201938454421115610fa15760ff191660021790556006546001820180549092916001600160a01b0316906000198101908111610f8d57825490823b15610f895790604486928360405195869485936334c9bca560e01b8552600485015260248401525af18015610d9857610f67575b50600080516020614d26833981519152600293948483549301549354905490610f4f60405192839263ffffffff60ff89169860081c168460409194939263ffffffff606083019616825260208201520152565b0390a46001600080516020614d468339815191525580f35b600293610f82600080516020614d2683398151915292612f34565b9350610efc565b8580fd5b634e487b7160e01b85526011600452602485fd5b60405162461bcd60e51b815260206004820152601960248201527f6368616c6c656e676520686173206e6f742065787069726564000000000000006044820152606490fd5b50604036600319011261024b576006546040516247a8e360e11b81526001600160a01b0390911690602081600481855afa80156115315783906115d2575b611033915060043511156136dc565b6110406004351515613728565b604051631614b30360e21b808252600480359083015290602081602481865afa908115610d985784916115a0575b5060405190630a2a343960e21b82526004820152604081602481865afa8015610d98576001600160401b03610b55916110b3938791611581575b505116855490613570565b6110c060025434146137f6565b60ff607254161561153c576040519081526004356004820152602081602481855afa9081156115315783916114fb575b5060405163392af9bf60e11b81526004803590820152918383602481845afa928315610d985784936114df575b506004356000198101116114cb57836024916040519283809263392af9bf60e11b82526000196004350160048301525afa908115610d985784916114b1575b50604051602081019083825260243560408201526040815261117d81612ee8565b5190209283855260716020526111a960ff600660408820015460a01c166111a381613184565b1561383b565b6001600160401b036020830151166024351180611498575b1561143a5760016004351480611418575b6113ad57604051916111e383612f19565b8383526024356020840181905260001981011161036f5760405161120681612f19565b848152600019602435016020820152916001600160401b0361122d816020850151166138b3565b166024351461137c575b505061124560015442613570565b6040519160e083018381106001600160401b038211176113685760019594936020989389899460069460405260043584528184019788526040840190815260608401928352816080850198338a52604060a08701998d8b5260c0880199818b5281526071845220955186555180518c870155015160028501555180516003850155015160048301555160058201550192858060a01b0390511683549251916112ec83613184565b6112f583613184565b60ff60a81b9051151560a81b169269ffffffffffffffffffff60b01b16179060ff60a01b9060a01b161717905561132d825442613570565b60405191825284820152827f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec2604060243593a4604051908152f35b634e487b7160e01b88526041600452602488fd5b6001600160401b0391925060406020910151920151166040519161139f83612f19565b825260208201523880611237565b60405162461bcd60e51b815260206004820152603860248201527f43616e6e6f74206368616c6c656e676520746865206669727374204c3220686560448201527f6164657220696e207468652066697273742072626c6f636b00000000000000006064820152608490fd5b506001600160401b03611430816020850151166138b3565b16602435146111d2565b60405162461bcd60e51b815260206004820152603060248201527f4c3220686561646572206d7573742062652077697468696e207468652072626c60448201526f6f636b2062756e646c652072616e676560801b6064820152608490fd5b506001600160401b0360208201511660243511156111c1565b6114c591503d8086833e610c778183612f62565b3861115c565b634e487b7160e01b84526011600452602484fd5b6114f49193503d8086833e610c778183612f62565b913861111d565b90506020813d602011611529575b8161151660209383612f62565b810103126115255751386110f0565b8280fd5b3d9150611509565b6040513d85823e3d90fd5b60405162461bcd60e51b815260206004820152601f60248201527f4c3220686561646572206368616c6c656e67652069732064697361626c6564006044820152606490fd5b61159a915060403d604011610d3557610d278183612f62565b386110a8565b90506020813d6020116115ca575b816115bb60209383612f62565b8101031261036b57513861106e565b3d91506115ae565b506020813d6020116115fe575b816115ec60209383612f62565b81010312611525576110339051611024565b3d91506115df565b503461024b578060031936011261024b57604060075481519060ff60f81b8160f81b16825263ffffffff199060181b166020820152f35b503461024b578060031936011261024b577f0000000000000000000000004fc6a6a2e3864709ae6adcf29280da01c95aa10b6001600160a01b031630036116a85760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60405163703e46dd60e11b8152600490fd5b503461024b57602036600319011261024b576116d4613978565b6004358152606f6020526040812081600482016117318154916116fd60ff8460081c161561357d565b60ff83169061170b82613184565b61010060028314948580156117a5575b6117249061321e565b61ff001916179055613184565b156117765780808061176194600260018060a01b0391015460281c16600254905af161175b6135d4565b50613649565b6001600080516020614d468339815191525580f35b6004546002546117a093508291829182916001600160a01b03165af161179a6135d4565b50613604565b611761565b506117af84613184565b6003841461171b565b50604036600319011261024b576117cd6131a4565b6024356001600160401b038111611525576117ec903690600401612fb5565b6001600160a01b037f0000000000000000000000004fc6a6a2e3864709ae6adcf29280da01c95aa10b8116308114908115611984575b506116a85761182f61393f565b8216916040516352d1902d60e01b8152602081600481875afa859181611950575b5061186e57604051634c9c8ce360e01b815260048101859052602490fd5b9284937f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908181036119385750823b1561191f5780546001600160a01b0319168217905560405184917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a28351156119035750808360206118ff95519101845af46118f96135d4565b91614a07565b5080f35b9250505034611910575080f35b63b398979f60e01b8152600490fd5b604051634c9c8ce360e01b815260048101839052602490fd5b60249060405190632a87526960e21b82526004820152fd5b9091506020813d60201161197c575b8161196c60209383612f62565b81010312610f8957519038611850565b3d915061195f565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416141538611822565b503461024b578060031936011261024b576020603c54604051908152f35b503461024b57602036600319011261024b576004358015158091036107e3576119f761393f565b60ff80196070541691161760705580f35b503461024b57604036600319011261024b57604051611a2681612f19565b6004356001600160f81b0319811681036115255781526024359063ffffffff19821682036115255760208101918252611a5d61393f565b5160f81c60075491610100600160e81b03905160181c169162ffffff60e81b16171760075580f35b503461024b578060031936011261024b576020600354604051908152f35b503461024b578060031936011261024b57602060ff607254166040519015158152f35b503461024b57602036600319011261024b57600435611ae361393f565b662386f26fc1000081101580611b62575b15611aff5760025580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e676520666565206d757374206265206265747765656e20302e60448201527418189032ba3432b91030b7321018981032ba3432b960591b6064820152608490fd5b50678ac7230489e80000811115611af4565b50606036600319011261024b57600435611b8c6131ba565b611b946131ca565b6006546040516247a8e360e11b815260209592916001600160a01b0316908681600481855afa8015610d98578490612047575b611bd491508611156136dc565b611bdf851515613728565b604051631614b30360e21b80825260048201879052936024919088828481875afa918215611fa6578192612018575b5060405191630a2a343960e21b835260048301526040828481875afa918215611fa6578192611ff7575b50611c53610b556001600160401b0380945116835490613570565b611c6060025434146137f6565b60ff6070541615611fb35760405195865287600487015288868481875afa958615611fa6578196611f77575b508281611c9a878a8a613695565b95868252606f8c52611cb960ff6004604085200154166111a381613184565b6040519283809263392af9bf60e11b82528d60048301525afa90811561036057906080918391611f5d575b500160ff815151981697881015611f21578962ffffff8082611d078c8651613538565b51015116928a63ffffffff8a16948510159384611ed1575b5050505015611e7a57611d3460015442613570565b926040519461010086019186831090831117611e68575089946001999897948c94600080516020614d2683398151915298946004946040528a84528684019189835260408501928d8452606086019283526040608087019233845260a08801968752606f60c089019b60018d5260e08a019b838d528352522095518655518e86015564ffffffff0060ff6002870194511684549351926001650100000000009060c81b03905160281b169366ffffffffffffff60c81b16179160081b161717905551600382015501915190611e0882613184565b611e1182613184565b60ff61ff0084549251151560081b1692169061ffff191617179055611e5d611e3a875442613570565b6040519384938460409194939263ffffffff606083019616825260208201520152565b0390a4604051908152f35b634e487b7160e01b8452604160045283fd5b60405162461bcd60e51b8152600481018b9052602a818601527f696e76616c696420736861726520696e6465783a206e6f7420696e20706f696e604482015269746572732072616e676560b01b6064820152608490fd5b839450818394611ef692611eeb60409561ffff9751613538565b510151169451613538565b5101511601818111611f0e5716811038808a8d611d1f565b634e487b7160e01b845260116004528584fd5b60405162461bcd60e51b8152600481018b9052601581860152740d2dcecc2d8d2c840e0ded2dce8cae440d2dcc8caf605b1b6044820152606490fd5b611f7191503d8085833e610c778183612f62565b38611ce4565b9095508881813d8311611f9f575b611f8f8183612f62565b81010312610f8957519438611c8c565b503d611f85565b50604051903d90823e3d90fd5b60405162461bcd60e51b8152600481018a9052601a818501527f4441206368616c6c656e676573206172652064697361626c65640000000000006044820152606490fd5b61201191925060403d604011610d3557610d278183612f62565b9038611c38565b9091508881813d8311612040575b6120308183612f62565b810103126107e357519038611c0e565b503d612026565b508681813d831161206f575b61205d8183612f62565b8101031261036b57611bd49051611bc7565b503d612053565b503461024b578060031936011261024b57602060ff603b54166040519015158152f35b503461024b578060031936011261024b576020600254604051908152f35b503461024b57606036600319011261024b5760206107a36120d66131ba565b6120de6131ca565b90600435613695565b503461024b57602036600319011261024b57612101613978565b600435815260716020526006604082200181600260ff8354612128828260a81c161561357d565b61214b828260a01c1661213a81613184565b84811490811561218c575b5061321e565b60a882901b1916600160a81b1780855560a01c1661216881613184565b03611776578080806117619460018060a01b03905416600254905af161175b6135d4565b6003915061219981613184565b1438612145565b503461024b57602036600319011261024b576121ba6131a4565b6121c261393f565b6001600160a01b031680156121e7576001600160601b0360a01b600454161760045580f35b60405162461bcd60e51b815260206004820152602360248201527f646566656e6465722063616e6e6f7420626520746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b503461024b57602036600319011261024b576040610100916004358152606f6020522060ff81549160018101546002820154916004600382015491015492848416926040519687526020870152848116604087015263ffffffff8160081c16606087015260018060a01b039060281c16608086015260a08501526122bb81613184565b60c084015260081c16151560e0820152f35b503461024b576003196040368201126107e357602435906001600160401b0382116115255760e0818336030112611525576040519160c083018381106001600160401b0382111761293a5760405280600401356001600160401b03811161035c5781013660238201121561035c5760048101359061234a82612f83565b916123586040519384612f62565b80835260051b81016024016020830136821161288d5760248301905b82821061290b5750505050835260248101356001600160401b03811161035c5781013660238201121561035c5760048101356123af81612f83565b916123bd6040519384612f62565b8183526024602084019260051b8201019036821161288d5760248101925b828410612891575050505060208401526123f83660448301612ffc565b604084015260848101356001600160401b03811161035c576124209060043691840101613047565b606084015260a48101356001600160401b03811161035c5781013660238201121561035c5760048101359061245482612f83565b916124626040519384612f62565b80835260051b81016024016020830136821161288d5760248301905b82821061285a5750505050608084015260c4810135906001600160401b03821161035c570160808136039283011261036b5760408051926124be84612ee8565b60048301358452602319011261036b576040516124da81612f19565b602482013581526044820135602082015260208301526064810135906001600160401b03821161035c57600461251392369201016130e8565b604082015260a0820152612525613978565b6004358252606f6020526040822060018060a01b0360065416906024846001830154936040519283809263392af9bf60e11b82528760048301525afa908115610cbf578591612840575b50608060048301549161258a600160ff851661028d81613184565b0151936001600160401b036125a860028501549660ff881690613538565b515116602060a0830151015151036127fb5760408101516126086125fa604051926125d284612f19565b60075460f881901b6001600160f81b031916855260181b63ffffffff19166020850152613fee565b9162ffffff19918291613fee565b169116036127c25760085460a082015160209081015101516126349183906001600160a01b03166139a8565b50156127655761265061264a6080830151613515565b51613d8d565b5090602061266f608061266583850151613515565b5151930151613515565b51015191828102928184041490151715612751579061268d91613570565b9263ffffffff8560081c168094036126ee57600394610f4f60ff9287600080516020614d26833981519152958519161760048701558786549601549060405194859416978460409194939263ffffffff606083019616825260208201520152565b60405162461bcd60e51b815260206004820152603560248201527f70726f6f66206d7573742062652070726f766964656420666f722074686520636044820152740d0c2d8d8cadccecac840e6d0c2e4ca40d2dcc8caf605b1b6064820152608490fd5b634e487b7160e01b87526011600452602487fd5b60405162461bcd60e51b815260206004820152602f60248201527f6661696c656420746f207665726966792073686172657320746f20646174612060448201526e1c9bdbdd081d1d5c1b19481c9bdbdd608a1b6064820152608490fd5b60405162461bcd60e51b8152602060048201526011602482015270696e76616c6964206e616d65737061636560781b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f696e76616c69642063656c6573746961206865696768740000000000000000006044820152606490fd5b61285491503d8087833e610c778183612f62565b3861256f565b81356001600160401b0381116128895760209161287e8392602436918901016130e8565b81520191019061247e565b8980fd5b8780fd5b83356001600160401b0381116128895782016060602319823603011261288957604051916128be83612ee8565b60248201358352604482013560208401526064820135926001600160401b038411612907576128f7602094936024869536920101613047565b60408201528152019301926123db565b8b80fd5b81356001600160401b0381116128895760209161292f839260243691890101612fb5565b815201910190612374565b634e487b7160e01b85526041600452602485fd5b503461024b57606036600319011261024b57602490604480359060043590843590612977613978565b82855260209060718252604086209060068201908154906129a3600160ff8460a01c1661028d81613184565b60018060a01b0360055416604051968b8789637afdc39160e01b9283825284600483015281865afa988915612d2a578c99612e16575b506001870154809903612dc157604051908152600481018b905287818e81865afa908115612d2a578c91612d94575b50600387015403612d355760405163172c2b0f60e31b8082526004820192909252908b828e81865afa918215612d2a578d8d928d928495612d0e575b506040519586938492835260048301525afa918215612d03578b92612cdf575b50610100998a8201519a6002880154809c03612c9c57830151600488015403612c4b57815103612bf257610160809101908151920191825111612bae5751421115612b61574290511015612b0f575060ff60a01b1916600360a01b17905560050154604080519384529183015260039392917f89389219f04af163105506312f99d6ca034af96d3ee1128efc6a9619ee2aeec29190a46001600080516020614d468339815191525580f35b847f70726576696f7573206865616465722074696d657374616d702069732074686560849260278d6040519462461bcd60e51b86526004860152840152820152662066757475726560c81b6064820152fd5b60405162461bcd60e51b8152600481018790526021818d01527f6865616465722074696d657374616d7020697320696e2074686520667574757281840152606560f81b6064820152608490fd5b5060405162461bcd60e51b815260048101879052601c818d01527f6865616465722074696d657374616d7020697320746f6f206c6174650000000081840152606490fd5b5060405162461bcd60e51b815260048101879052602c818d01527f68656164657220646f6573206e6f7420706f696e7420746f2074686520707265818401526b3b34b7bab9903432b0b232b960a11b6064820152608490fd5b60405162461bcd60e51b8152600481018990526025818f01527f70726576696f757320686561646572206e756d62657220646f6573206e6f742081860152640dac2e8c6d60db1b6064820152608490fd5b6064898f87601c7f686561646572206e756d62657220646f6573206e6f74206d6174636800000000926040519462461bcd60e51b86526004860152840152820152fd5b612cfc9192503d808d833e612cf48183612f62565b8101906132d1565b9038612a64565b6040513d8d823e3d90fd5b612d239195503d8086833e612cf48183612f62565b9338612a44565b6040513d8e823e3d90fd5b5060405162461bcd60e51b8152600481018790526032818d01527f70726576696f7573206c3220686561646572206e6f74206c6f6164656420666f8184015271722074686520676976656e2072626c6f636b60701b6064820152608490fd5b90508781813d8311612dba575b612dab8183612f62565b81010312612907575138612a08565b503d612da1565b60405162461bcd60e51b8152600481018990526029818f01527f6c3220686561646572206e6f74206c6f6164656420666f7220746865206769768186015268656e2072626c6f636b60b81b6064820152608490fd5b9098508781813d8311612e3e575b612e2e8183612f62565b81010312612907575197386129d9565b503d612e24565b503461024b57602036600319011261024b57600435612e6261393f565b61a8c081101580612edb575b15612e7857815580f35b60405162461bcd60e51b815260206004820152603560248201527f6368616c6c656e67652077696e646f77206d757374206265206265747765656e60448201527420313220686f75727320616e642033207765656b7360581b6064820152608490fd5b50621baf80811115612e6e565b606081019081106001600160401b03821117612f0357604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b03821117612f0357604052565b6001600160401b038111612f0357604052565b608081019081106001600160401b03821117612f0357604052565b90601f801991011681019081106001600160401b03821117612f0357604052565b6001600160401b038111612f035760051b60200190565b6001600160401b038111612f0357601f01601f191660200190565b81601f8201121561063b57803590612fcc82612f9a565b92612fda6040519485612f62565b8284526020838301011161063b57816000926020809301838601378301015290565b919082604091031261063b5760405161301481612f19565b9182908035906001600160f81b03198216820361063b57908252602001359063ffffffff198216820361063b5760200152565b81601f8201121561063b57803590602061306083612f83565b936040906130716040519687612f62565b8486526020860191602060a08097028601019482861161063b57602001925b8584106130a1575050505050505090565b868484031261063b5784879183516130b881612ee8565b6130c28688612ffc565b81526130d086868901612ffc565b83820152608087013585820152815201930192613090565b91909160608184031261063b576040519061310282612ee8565b819381356001600160401b03811161063b57820181601f8201121561063b57602091813561312f81612f83565b9261313d6040519485612f62565b818452848085019260051b82010192831161063b578401905b8282106131755750505083528082013590830152604090810135910152565b81358152908401908401613156565b6004111561318e57565b634e487b7160e01b600052602160045260246000fd5b600435906001600160a01b038216820361063b57565b6024359060ff8216820361063b57565b6044359063ffffffff8216820361063b57565b906040516131ea81612f19565b602060018294805484520154910152565b60005b83811061320e5750506000910152565b81810151838201526020016131fe565b1561322557565b60405162461bcd60e51b815260206004820152602560248201527f6368616c6c656e6765206973206e6f7420696e2074686520636f727265637420604482015264737461746560d81b6064820152608490fd5b51906001600160a01b038216820361063b57565b81601f8201121561063b5780516132a281612f9a565b926132b06040519485612f62565b8184526020828401011161063b576132ce91602080850191016131fb565b90565b9060208282031261063b5781516001600160401b039283821161063b5701906101e092838383031261063b5760405193840184811082821117612f0357604052825184526020830151602085015261332b60408401613278565b6040850152606083015160608501526080830151608085015260a083015160a085015260c083015181811161063b578261336691850161328c565b60c085015260e083015160e08501526101008084015190850152610120808401519085015261014080840151908501526101608084015190850152610180918284015191821161063b576133bb91840161328c565b908301526101a080820151908301526101c0809101519082015290565b51906001600160401b038216820361063b57565b906020808383031261063b5782516001600160401b039384821161063b57019060a08284031261063b5760409081519460a0860186811082821117612f03578352613436846133d8565b86526134438285016133d8565b82870152828401518387015260609360608101516060880152608081015191821161063b57019184601f8401121561063b5782519061348182612f83565b9561348e82519788612f62565b82875283606081890194028601019481861161063b578401925b8584106134be5750505050505050608082015290565b868483031261063b578251906134d382612ee8565b6134dc856133d8565b82528585015162ffffff8116810361063b5786830152838501519061ffff8216820361063b57828792868b9501528152019301926134a8565b8051156135225760200190565b634e487b7160e01b600052603260045260246000fd5b80518210156135225760209160051b010190565b600101908160011161355a57565b634e487b7160e01b600052601160045260246000fd5b9190820180921161355a57565b1561358457565b60405162461bcd60e51b815260206004820152602260248201527f6368616c6c656e67652068617320616c7265616479206265656e20636c61696d604482015261195960f21b6064820152608490fd5b3d156135ff573d906135e582612f9a565b916135f36040519384612f62565b82523d6000602084013e565b606090565b1561360b57565b60405162461bcd60e51b81526020600482015260166024820152753330b4b632b2103a37903830bc903232b332b73232b960511b6044820152606490fd5b1561365057565b60405162461bcd60e51b815260206004820152601860248201527f6661696c656420746f20706179206368616c6c656e67657200000000000000006044820152606490fd5b604080516020810192835260f89390931b6001600160f81b0319169083015260e09290921b6001600160e01b0319166041820152602581526136d681612ee8565b51902090565b156136e357565b60405162461bcd60e51b815260206004820152601a60248201527f626c6f636b206e6f7420696e2074686520636861696e207965740000000000006044820152606490fd5b1561372f57565b60405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74206368616c6c656e67652067656e6573697320626c6f636b00006044820152606490fd5b9081604091031261063b576137a260206040519261379184612f19565b61379a816133d8565b845201613278565b602082015290565b156137b157565b60405162461bcd60e51b815260206004820152601d60248201527f626c6f636b20697320746f6f206f6c6420746f206368616c6c656e67650000006044820152606490fd5b156137fd57565b60405162461bcd60e51b815260206004820152601660248201527518da185b1b195b99d948199959481b9bdd081c185a5960521b6044820152606490fd5b1561384257565b60405162461bcd60e51b815260206004820152601860248201527f6368616c6c656e676520616c72656164792065786973747300000000000000006044820152606490fd5b9061010091820391821161355a57565b60001981019190821161355a57565b9190820391821161355a57565b9060016001600160401b038093160191821161355a57565b6001600160a01b0390811690811561392657600080516020614ce683398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020614ce6833981519152546001600160a01b0316330361396057565b60405163118cdaa760e01b8152336004820152602490fd5b600080516020614d4683398151915260028154146139965760029055565b604051633ee5aeb560e01b8152600490fd5b916139c5919392606085015160808601519060a087015192614057565b9015613d86575060208201515160608301515103613d7d576000805b60208401518051831015613a2b57600191613a1d6020613a0486613a2395613538565b510151613a158660208a0151613538565b5151906138a6565b90613570565b9101906139e1565b50905091909181515103613d7457600090815b60208201518051841015613d68576020613a5b85613a6c93613538565b510151613a15856020860151613538565b93613a83835183613a7d8882613570565b91614223565b600b81949294101561318e5780613d5b5750613aa3856060860151613538565b5190613ab3866020870151613538565b5191604086015197613ac58651614333565b9660005b8751811015613b9e5760206000613b488d613af7613ae7868e613538565b5191613af16142ee565b50613fee565b90613b37604051918683019386855262ffffff1916602184015282603e91613b27815180928b86860191016131fb565b810103601e810184520182612f62565b6040519283928392519283916131fb565b8101039060025afa15613b925760019060005160405190613b6882612ee8565b8d82528d60208301526040820152613b80828c613538565b52613b8b818b613538565b5001613ac9565b6040513d6000823e3d90fd5b5096955092969190939750600094613bba604089015151614333565b95805b89518082141580613d4d575b15613c16578a82613bee856040613be6613c0a96613c10986146e2565b940151613538565b51613bf9868d613538565b52613c04858c613538565b50613570565b9161445e565b90613bbd565b5050509294509290969495613c2e602082015161474b565b60019381851b918083046002149015171561355a5760008083613c61938880969210613d45575b9082869594928861477c565b5050939093925b613d0a575b5050509081613c919251613c82835191613fee565b9062ffffff1980958192613fee565b169116149283613cde575b5082613ccb575b505015613cc15750600191613cb791613570565b9301919092613a3e565b6000955093505050565b6040919250810151910151143880613ca3565b90925060208301519080613cff613cf9602086015194613fee565b93613fee565b169116149138613c9c565b90919260408201518051851015613d3b578391613d2a86613d3193613538565b5190614889565b9301919081613c68565b5092829150613c6d565b859150613c55565b5060408b0151518310613bc9565b9550509250505060009190565b50505050600190600090565b50600090600790565b60009150600590565b6000925090565b6040015160038116613da25760021c90600090565b50600090600890565b80516006546001600160a01b0316939192916001600160401b0391821690600019810190811161355a57604080519663392af9bf60e11b938489528360048a01526000988981602481865afa908115613fe4578a929188918491613fca575b5051161015613fad57506020928388018681511684518781528360048201528b81602481885afa908115613f6857899188918e8092613f92575b50500151161015613f7257888401518451631614b30360e21b815260048101849052908682602481885afa918215613f6857908c949392918592613f32575b5003613f11578760249151169685519485938492835260048301525afa918215613f085750908492918891613eee575b500151169003818111610f8d5781603c54911611613ed45750505050600190565b6003925116600080516020614d068339815191528480a490565b613f0291503d808a833e610c778183612f62565b38613eb3565b513d89823e3d90fd5b505050505050506002925116600080516020614d068339815191528480a490565b888092949596508193503d8311613f61575b613f4e8183612f62565b8101031261290757518b93929138613e83565b503d613f44565b86513d8e823e3d90fd5b5050505050506001925116600080516020614d068339815191528480a490565b613fa692503d8091833e610c778183612f62565b388e613e44565b9693505050505116600080516020614d068339815191528380a490565b613fde91503d8086833e610c778183612f62565b38613e0a565b84513d8c823e3d90fd5b80516020918201516040516001600160f81b031990921692820192835263ffffffff19166021820152601d815261402481612f19565b51905162ffffff19918282169190601d8110614042575b5050905090565b83919250601d0360031b1b161680388061403b565b9192939093805192602080948184015192604080950151838651958694631f3302a960e01b865260048601528051602486015201516044840152608060648401528560e484019180519260606084870152835180915286610104870194019060005b818110614207575050508581015160a4860152015160c48401528290039082906001600160a01b03165afa9081156141fc576000916141c6575b50156141b95783518551036141ac5760005b845181101561419e5761418361412561411e8389613538565b5151613fee565b61413b86614133858b613538565b510151613fee565b9084614147858b613538565b5101519085519262ffffff198092168985015216603d830152605a9081830152815261417281612f47565b61417c8388613538565b5185614383565b1561419057600101614105565b505050505050600090600290565b505050505050600190600090565b5050505050600090600690565b5050505050600090600490565b8481813d83116141f5575b6141db8183612f62565b810103126107e3575190811515820361024b5750386140f3565b503d6141d1565b82513d6000823e3d90fd5b825186528c988a9850958601958b9550909201916001016140b9565b91908181116142e65782518082119081156142dc575b506142d45761424881836138a6565b9261425284612f83565b936142606040519586612f62565b80855261426f601f1991612f83565b0160005b8181106142c3575050815b83811061428f575050505090600090565b806142bc61429f60019385613538565b516142aa86846138a6565b906142b5828a613538565b5287613538565b500161427e565b806060602080938901015201614273565b505090600a90565b9050821138614239565b505090600990565b604051906142fb82612ee8565b6000604083815161430b81612f19565b8381528360208201528152815161432181612f19565b83815283602082015260208201520152565b9061433d82612f83565b61434a6040519182612f62565b828152809261435b601f1991612f83565b019060005b82811061436c57505050565b6020906143776142ee565b82828501015201614360565b604082018051929391926001811161443f5750835151614436575b602084019182518251111561442c5760006143e7602092604051613b37602182878101948786526143d7815180928b86860191016131fb565b8101036001810184520182612f62565b8101039060025afa15613b9257600051935191825115614415579061441193949151905190614557565b1490565b5051600114159050614425571490565b5050600090565b5050505050600090565b50505050600090565b6144508551519160208701516144ae565b1461439e5750505050600090565b600019811461355a5760010190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561449c57565b604051631afcd79f60e31b8152600490fd5b909160005b60018481831b10156144df578101809111156144b357634e487b7160e01b600052601160045260246000fd5b509291909261010090810390811161355a576144fa90613887565b91600161450684613897565b1b9161451183613897565b811161451d5750505090565b919250906001830361453157505050600190565b8261454261454e94614548936138a6565b926138a6565b906144ae565b6132ce9061354c565b909182156146815760018314614630578351156145eb576145778361474b565b61458a6145848651613897565b86614a6a565b928181106145c757816145426145aa96936145a4936138a6565b90614557565b6145c1826145bb6132ce9451613897565b90613538565b51614b2e565b6145d19450614557565b906145e46132ce92916145bb8151613897565b5190614b2e565b60405162461bcd60e51b815260206004820181905260248201527f6578706563746564206174206c65617374206f6e6520696e6e657220686173686044820152606490fd5b929150505161463c5790565b60405162461bcd60e51b815260206004820152601760248201527f756e657870656374656420696e6e6572206861736865730000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152603360248201527f63616e6e6f742063616c6c20636f6d70757465526f6f744861736820776974686044820152722030206e756d626572206f66206c656176657360681b6064820152608490fd5b90918160005b83151580614740575b15614709576146ff9061445e565b9260011c926146e8565b92506147199061471e92946138a6565b614b70565b60001981019190821161355a5781600192821161473a57501b90565b90501b90565b5083600116156146f1565b6001811061063b5761475c81614b70565b600019810190811161355a576001901b9081146147765790565b60011c90565b93959492909261478a6142ee565b50600161479784846138a6565b146148445784518211801590614836575b61481a576147d5906147c26147bd85856138a6565b61474b565b976147cd8986613570565b85878961477c565b5091976147f096929591946147ea9190613570565b9161477c565b9194909392909115156001146148115761480991614889565b929190600090565b50929190600090565b93604091935061482e959692500151614bb0565b929391929091565b5060208501518310156147a8565b939495918086949294511115908161487b575b5061486a5750604061482e940151614bb0565b805161482e95509193919250614b91565b905060208601511138614857565b906148926142ee565b506148a08251825190614bc6565b916000916040918251936148b385612f19565b8085526020809501526148e181516148d26148cc614c06565b91613fee565b9062ffffff1980938192613fee565b169116146000146149c3576148f4614c06565b925b6149008351613fee565b918561490e88860151613fee565b940151918161491d8251613fee565b8861492a8b850151613fee565b93015194828a5198818d8b0199600160f81b8b521660218b015216603e890152605b88015216607b86015216609884015260b583015260b5825260e082018281106001600160401b03821117612f035785928161499060009482895283519283916131fb565b8101039060025afa156149b857600051928251946149ad86612ee8565b855284015282015290565b50513d6000823e3d90fd5b825181806149db613cf96149d5614c06565b94613fee565b169116146000146149f05784820151926148f6565b614a01858301518685015190614c40565b926148f6565b90614a2e5750805115614a1c57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580614a61575b614a3f575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614a37565b919082518111614ad157614a7d81612f83565b90614a8b6040519283612f62565b808252601f19614a9a82612f83565b0136602084013760005b818110614ab2575090925050565b80614abf60019287613538565b51614aca8286613538565b5201614aa4565b60405162461bcd60e51b815260206004820152602f60248201527f496e76616c69642072616e67653a205f626567696e206f72205f656e6420617260448201526e65206f7574206f6620626f756e647360881b6064820152608490fd5b614b5d6000916020936040519085820192600160f81b84526021830152604182015260418152613b3781612f47565b8101039060025afa15613b925760005190565b806000915b614b7d575090565b90614b879061445e565b9060011c80614b75565b90614ba89291949394614ba26142ee565b50614c7b565b919392909190565b90614bbe9291614ba26142ee565b919390929190565b9060006020604051614bd781612f19565b8281520152614be582613fee565b62ffffff1980614bf484613fee565b1691161015614c01575090565b905090565b60006020604051614c1681612f19565b8281520152604051614c2781612f19565b6001600160f81b0319815263ffffffff19602082015290565b9060006020604051614c5181612f19565b8281520152614c5f82613fee565b62ffffff1980614c6e84613fee565b1691161115614c01575090565b90809392614c876142ee565b508251908115918215614cda575b508115614ccf575b50614cbe57614cab91613538565b516001830180931161355a579190600090565b5050614cc86142ee565b9190600190565b905081101538614c9d565b831015915038614c9556fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300ea46f8ad2711844c28d6aa0fe8ed10b1ac38bdcdc6df7ba3b8f3bfc35232f31b6c1c38434bf7781d35ea9020730ba834cfde2300c18c12141e82e3662d6c45669b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220cfde574c4593203fc6cfec8a585ed7644e003a73041d087092e5e3e1abc0c31564736f6c63430008160033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.