Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- DevnetInbox
- Optimization enabled
- true
- Compiler version
- v0.8.30+commit.73712a01
- Optimization runs
- 200
- EVM Version
- prague
- Verified at
- 2026-01-19T07:54:10.532945Z
Constructor Arguments
0x000000000000000000000000121b61af720bf2f147893d4b27a6ac93709373e8000000000000000000000000cfb57e95cbab87bfd167b3eddd5c11e2d1613b2200000000000000000000000053789e39e3310737e8c8ced483032aac25b39ded000000000000000000000000cbf1639b8809adff74bd59ec292e436107852cc9000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c58000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Arg [0] (address) : 0x121b61af720bf2f147893d4b27a6ac93709373e8
Arg [1] (address) : 0xcfb57e95cbab87bfd167b3eddd5c11e2d1613b22
Arg [2] (address) : 0x53789e39e3310737e8c8ced483032aac25b39ded
Arg [3] (address) : 0xcbf1639b8809adff74bd59ec292e436107852cc9
Arg [4] (address) : 0xa20182131658295f37c1a1efdbdc89eff97d9c58
Arg [5] (uint64) : 0
Arg [6] (uint64) : 0
Arg [7] (uint48) : 0
contracts/layer1/devnet/DevnetInbox.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { Inbox } from "src/layer1/core/impl/Inbox.sol";
import { LibFasterReentryLock } from "src/layer1/mainnet/LibFasterReentryLock.sol";
import "./DevnetInbox_Layout.sol"; // DO NOT DELETE
/// @title DevnetInbox
/// @dev This contract extends the base Inbox contract for devnet deployment
/// with optimized reentrancy lock implementation.
/// @custom:security-contact security@taiko.xyz
contract DevnetInbox is Inbox {
// ---------------------------------------------------------------
// Constants
// ---------------------------------------------------------------
/// @dev Ring buffer size for storing proposal hashes.
/// Assumptions:
/// - D = 2: Proposals may continue without finalization for up to 2 days.
/// - P = 6: On average, 1 proposal is submitted every 6 Ethereum slots (≈72s).
///
/// Calculation:
/// _RING_BUFFER_SIZE = (86400 * D) / 12 / P
/// = (86400 * 2) / 12 / 6
/// = 2400
uint48 private constant _RING_BUFFER_SIZE = 100;
// ---------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------
constructor(
address _proofVerifier,
address _proposerChecker,
address _proverWhitelist,
address _signalService,
address _bondToken,
uint64 _minBond,
uint64 _livenessBond,
uint48 _withdrawalDelay
)
Inbox(Config({
proofVerifier: _proofVerifier,
proposerChecker: _proposerChecker,
proverWhitelist: _proverWhitelist,
signalService: _signalService,
bondToken: _bondToken,
minBond: _minBond,
livenessBond: _livenessBond,
withdrawalDelay: _withdrawalDelay,
provingWindow: 2 hours,
permissionlessProvingDelay: 24 hours,
maxProofSubmissionDelay: 3 minutes, // We want this to be lower than the proposal cadence
ringBufferSize: _RING_BUFFER_SIZE,
basefeeSharingPctg: 75,
minForcedInclusionCount: 1,
forcedInclusionDelay: 0,
forcedInclusionFeeInGwei: 10_000_000, // 0.01 ETH base fee
forcedInclusionFeeDoubleThreshold: 50, // fee doubles at 50 pending
minCheckpointDelay: 384 seconds, // 1 epoch
permissionlessInclusionMultiplier: 5
}))
{ }
// ---------------------------------------------------------------
// Internal Functions
// ---------------------------------------------------------------
function _storeReentryLock(uint8 _reentry) internal override {
LibFasterReentryLock.storeReentryLock(_reentry);
}
function _loadReentryLock() internal view override returns (uint8) {
return LibFasterReentryLock.loadReentryLock();
}
}
contracts/shared/common/IResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IResolver
/// @notice This contract acts as a bridge for name-to-address resolution.
/// @custom:security-contact security@taiko.xyz
interface IResolver {
error RESOLVED_TO_ZERO_ADDRESS();
/// @notice Resolves a name to its address deployed on a specified chain.
/// @param _chainId The chainId of interest.
/// @param _name Name whose address is to be resolved.
/// @param _allowZeroAddress If set to true, does not throw if the resolved
/// address is `address(0)`.
/// @return Address associated with the given name on the specified
/// chain.
function resolve(
uint256 _chainId,
bytes32 _name,
bool _allowZeroAddress
)
external
view
returns (address);
}
node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
contracts/layer1/core/iface/IForcedInclusionStore.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { LibBlobs } from "../libs/LibBlobs.sol";
/// @title IForcedInclusionStore
/// @custom:security-contact security@taiko.xyz
interface IForcedInclusionStore {
/// @notice Represents a forced inclusion that will be stored onchain.
struct ForcedInclusion {
/// @notice The fee in Gwei that was paid to submit the forced inclusion.
uint64 feeInGwei;
/// @notice The proposal's blob slice.
LibBlobs.BlobSlice blobSlice;
}
/// @dev Event emitted when a forced inclusion is stored.
event ForcedInclusionSaved(ForcedInclusion forcedInclusion);
/// @notice Saves a forced inclusion request
/// A priority fee must be paid to the contract
/// @dev Only one blob reference can be saved per forced inclusion
/// @param _blobReference The blob locator that contains the transaction data
function saveForcedInclusion(LibBlobs.BlobReference memory _blobReference) external payable;
/// @notice Returns the current dynamic forced inclusion fee based on queue size
/// The fee scales linearly with queue size using the formula:
/// fee = baseFee × (1 + numPending / threshold)
/// Examples with threshold = 100 and baseFee = 0.01 ETH:
/// - 0 pending: fee = 0.01 × (1 + 0/100) = 0.01 ETH (1× base)
/// - 50 pending: fee = 0.01 × (1 + 50/100) = 0.015 ETH (1.5× base)
/// - 100 pending: fee = 0.01 × (1 + 100/100) = 0.02 ETH (2× base, DOUBLED)
/// - 150 pending: fee = 0.01 × (1 + 150/100) = 0.025 ETH (2.5× base)
/// - 200 pending: fee = 0.01 × (1 + 200/100) = 0.03 ETH (3× base, TRIPLED)
/// @return feeInGwei_ The current fee in Gwei
function getCurrentForcedInclusionFee() external view returns (uint64 feeInGwei_);
/// @notice Returns forced inclusions stored starting from a given index.
/// @dev Returns an empty array if `_start` is outside the valid range [head, tail) or if
/// `_maxCount` is zero. Otherwise returns actual stored entries from the queue.
/// @param _start The queue index to start reading from (must be in range [head, tail)).
/// @param _maxCount Maximum number of inclusions to return. Passing zero returns an empty
/// array.
/// @return inclusions_ Forced inclusions from the queue starting at `_start`. The actual length
/// will be `min(_maxCount, tail - _start)`, or zero if `_start` is out of range.
function getForcedInclusions(
uint48 _start,
uint48 _maxCount
)
external
view
returns (ForcedInclusion[] memory inclusions_);
/// @notice Returns the queue pointers for the forced inclusion store.
/// @return head_ Index of the oldest forced inclusion in the queue.
/// @return tail_ Index of the next free slot in the queue.
function getForcedInclusionState() external view returns (uint48 head_, uint48 tail_);
}
node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
contracts/layer1/verifiers/IProofVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IProofVerifier
/// @notice Interface for verifying validity proofs for state transitions
/// @custom:security-contact security@taiko.xyz
interface IProofVerifier {
/// @notice Verifies a validity proof for a state transition
/// @dev This function must revert if the proof is invalid
/// @param _proposalAge The age in seconds of the proposal being proven. Only set for
/// single-proposal proofs (calculated as block.timestamp - proposal.timestamp).
/// For multi-proposal batches, this is always 0, meaning "not applicable".
/// Verifiers should interpret _proposalAge == 0 as "not applicable" rather than
/// "instant proof". This parameter enables age-based verification logic, such as
/// detecting and handling prover-killer proposals differently.
/// @param _commitmentHash Hash of the last proposal hash and commitment data
/// @param _proof The proof data
function verifyProof(
uint256 _proposalAge,
bytes32 _commitmentHash,
bytes calldata _proof
)
external
view;
}
contracts/layer1/core/libs/LibBlobs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title LibBlobs
/// @notice Library for handling blobs.
/// @custom:security-contact security@taiko.xyz
library LibBlobs {
/// @notice Represents a segment of data that is stored in multiple consecutive blobs created
/// in this transaction.
struct BlobReference {
/// @notice The starting index of the blob.
uint16 blobStartIndex;
/// @notice The number of blobs.
uint16 numBlobs;
/// @notice The field-element offset within the blob data.
uint24 offset;
}
/// @notice Represents a frame of data that is stored in multiple blobs. Note the size is
/// encoded as a bytes32 at the offset location.
struct BlobSlice {
/// @notice The blobs containing the proposal's content.
bytes32[] blobHashes;
/// @notice The byte offset of the proposal's content in the containing blobs.
uint24 offset;
/// @notice The timestamp when the frame was created.
uint48 timestamp;
}
// ---------------------------------------------------------------
// Functions
// ---------------------------------------------------------------
/// @dev Validates a blob locator and converts it to a blob slice.
/// @param _blobReference The blob locator to validate.
/// @return The blob slice.
function validateBlobReference(BlobReference memory _blobReference)
internal
view
returns (BlobSlice memory)
{
require(_blobReference.numBlobs > 0, NoBlobs());
bytes32[] memory blobHashes = new bytes32[](_blobReference.numBlobs);
for (uint256 i; i < _blobReference.numBlobs; ++i) {
blobHashes[i] = blobhash(_blobReference.blobStartIndex + i);
require(blobHashes[i] != 0, BlobNotFound());
}
return BlobSlice({
blobHashes: blobHashes,
offset: _blobReference.offset,
timestamp: uint48(block.timestamp)
});
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error BlobNotFound();
error NoBlobs();
}
contracts/shared/signal/ISignalService.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./ICheckpointStore.sol";
/// @title ISignalService
/// @notice The SignalService contract serves as a secure cross-chain message
/// passing system. It defines methods for sending and verifying signals with
/// merkle proofs. The trust assumption is that the target chain has secure
/// access to the merkle root (such as Taiko injects it in the anchor
/// transaction). With this, verifying a signal is reduced to simply verifying
/// a merkle proof.
/// @custom:security-contact security@taiko.xyz
interface ISignalService is ICheckpointStore {
/// @dev DEPRECATED
/// @dev Caching is no longer supported
enum CacheOption {
CACHE_NOTHING,
CACHE_SIGNAL_ROOT,
CACHE_STATE_ROOT,
CACHE_BOTH
}
struct HopProof {
/// @notice This hop's destination chain ID. If there is a next hop, this ID is the next
/// hop's source chain ID.
uint64 chainId;
/// @notice The ID of a source chain block whose state root has been synced to the hop's
/// destination chain.
/// Note that this block ID must be greater than or equal to the block ID where the signal
/// was sent on the source chain.
uint64 blockId;
/// @notice The state root or signal root of the source chain at the above blockId. This
/// value has been synced to the destination chain.
/// @dev To get both the blockId and the rootHash, apps should subscribe to the
/// ChainDataSynced event or query `topBlockId` first using the source chain's ID and
/// LibStrings.H_STATE_ROOT to get the most recent block ID synced, then call
/// `getSyncedChainData` to read the synchronized data.
bytes32 rootHash;
/// @notice Options to cache either the state roots or signal roots of middle-hops to the
/// current chain.
/// @dev DEPRECATED - this value will be ignored
CacheOption cacheOption;
/// @notice The signal service's account proof. If this value is empty, then `rootHash` will
/// be used as the signal root, otherwise, `rootHash` will be used as the state root.
bytes[] accountProof;
/// @notice The signal service's storage proof.
bytes[] storageProof;
}
/// @notice Emitted when a signal is sent.
/// @param app The address that initiated the signal.
/// @param signal The signal (message) that was sent.
/// @param slot The location in storage where this signal is stored.
/// @param value The value of the signal.
event SignalSent(address app, bytes32 signal, bytes32 slot, bytes32 value);
/// @notice Send a signal (message) by setting the storage slot to the same value as the signal
/// itself.
/// @param _signal The signal (message) to send.
/// @return slot_ The location in storage where this signal is stored.
function sendSignal(bytes32 _signal) external returns (bytes32 slot_);
/// @notice Checks whether a signal has been received on the target chain and caches the result if successful.
/// @param _chainId The identifier for the source chain from which the
/// signal originated.
/// @param _app The address that initiated the signal.
/// @param _signal The signal (message) to send.
/// @param _proof Merkle proof that the signal was persisted on the
/// source chain. If this proof is empty, then we check if this signal has been marked as
/// received by TaikoL2.
/// @return numCacheOps_ The number of newly cached items.
function proveSignalReceived(
uint64 _chainId,
address _app,
bytes32 _signal,
bytes calldata _proof
)
external
returns (uint256 numCacheOps_);
/// @notice Verifies if a signal has been received on the target chain.
/// This is the "readonly" version of proveSignalReceived.
/// @param _chainId The identifier for the source chain from which the
/// signal originated.
/// @param _app The address that initiated the signal.
/// @param _signal The signal (message) to send.
/// @param _proof Merkle proof that the signal was persisted on the
/// source chain. If this proof is empty, then we check if this signal has been marked as
/// received by TaikoL2.
function verifySignalReceived(
uint64 _chainId,
address _app,
bytes32 _signal,
bytes calldata _proof
)
external
view;
/// @notice Verifies if a particular signal has already been sent.
/// @param _app The address that initiated the signal.
/// @param _signal The signal (message) that was sent.
/// @return true if the signal has been sent, otherwise false.
function isSignalSent(address _app, bytes32 _signal) external view returns (bool);
/// @notice Verifies if a particular signal has already been sent.
/// @param _signalSlot The location in storage where this signal is stored.
function isSignalSent(bytes32 _signalSlot) external view returns (bool);
}
contracts/layer1/core/iface/IProposerChecker.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IProposerChecker
/// @notice Interface for checking if an address is authorized to propose blocks
/// @custom:security-contact security@taiko.xyz
interface IProposerChecker {
error InvalidProposer();
/// @notice Checks if an address is a valid proposer
/// @param _proposer The address to check
/// @param _lookaheadData Encoded lookahead metadata used by preconf-aware proposer checkers.
/// @return endOfSubmissionWindowTimestamp_ The timestamp of the last slot where the current
/// preconfer can propose.
/// @dev This function must revert if the address is not a valid proposer
function checkProposer(
address _proposer,
bytes calldata _lookaheadData
)
external
returns (uint48 endOfSubmissionWindowTimestamp_);
}
contracts/shared/libs/LibMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title LibMath
/// @dev This library offers additional math functions for uint256.
/// @custom:security-contact security@taiko.xyz
library LibMath {
/// @dev Returns the smaller of the two given values.
/// @param _a The first number to compare.
/// @param _b The second number to compare.
/// @return The smaller of the two numbers.
function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a > _b ? _b : _a;
}
/// @dev Returns the larger of the two given values.
/// @param _a The first number to compare.
/// @param _b The second number to compare.
/// @return The larger of the two numbers.
function max(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a > _b ? _a : _b;
}
function capToUint64(uint256 _value) internal pure returns (uint64) {
return uint64(min(_value, type(uint64).max));
}
}
contracts/layer1/core/libs/LibForcedInclusion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IForcedInclusionStore } from "../iface/IForcedInclusionStore.sol";
import { LibBlobs } from "../libs/LibBlobs.sol";
import { LibMath } from "src/shared/libs/LibMath.sol";
/// @title LibForcedInclusion
/// @dev Library for storing and managing forced inclusion requests. Forced inclusions
/// allow users to pay a fee to ensure their transactions are included in a block. The library
/// maintains a FIFO queue of inclusion requests.
/// @dev Inclusion delay is measured in seconds, since we don't have an easy way to get batch number
/// in the Shasta design.
/// @dev Forced inclusions are limited to 1 blob only, and one L2 block only(this and other protocol
/// constrains are enforced by the node and verified by the prover)
/// @custom:security-contact security@taiko.xyz
library LibForcedInclusion {
using LibMath for uint48;
using LibMath for uint256;
// ---------------------------------------------------------------
// Structs
// ---------------------------------------------------------------
/// @dev Storage for the forced inclusion queue. This struct uses 2 slots.
/// @dev 2 slots used
struct Storage {
mapping(uint256 id => IForcedInclusionStore.ForcedInclusion inclusion) queue;
/// @notice The index of the oldest forced inclusion in the queue. This is where items will
/// be dequeued.
uint48 head;
/// @notice The index of the next free slot in the queue. This is where items will be
/// enqueued.
uint48 tail;
}
// ---------------------------------------------------------------
// Public Functions
// ---------------------------------------------------------------
/// @dev See `IForcedInclusionStore.saveForcedInclusion`
function saveForcedInclusion(
Storage storage $,
uint64 _baseFeeInGwei,
uint64 _feeDoubleThreshold,
LibBlobs.BlobReference memory _blobReference
)
public
returns (uint256 refund_)
{
LibBlobs.BlobSlice memory blobSlice = LibBlobs.validateBlobReference(_blobReference);
require(blobSlice.blobHashes.length == 1, OnlySingleBlobAllowed());
uint64 requiredFeeInGwei =
getCurrentForcedInclusionFee($, _baseFeeInGwei, _feeDoubleThreshold);
uint256 requiredFee = requiredFeeInGwei * 1 gwei;
require(msg.value >= requiredFee, InsufficientFee());
IForcedInclusionStore.ForcedInclusion memory inclusion =
IForcedInclusionStore.ForcedInclusion({
feeInGwei: requiredFeeInGwei, blobSlice: blobSlice
});
$.queue[$.tail++] = inclusion;
emit IForcedInclusionStore.ForcedInclusionSaved(inclusion);
// Calculate and return refund amount
unchecked {
refund_ = msg.value - requiredFee;
}
}
/// @dev See `IForcedInclusionStore.getCurrentForcedInclusionFee`
function getCurrentForcedInclusionFee(
Storage storage $,
uint64 _baseFeeInGwei,
uint64 _feeDoubleThreshold
)
public
view
returns (uint64 feeInGwei_)
{
require(_feeDoubleThreshold > 0, InvalidFeeDoubleThreshold());
(uint48 head, uint48 tail) = ($.head, $.tail);
uint256 numPending = uint256(tail - head);
// Linear scaling formula: fee = baseFee × (threshold + numPending) / threshold
// This is mathematically equivalent to: fee = baseFee × (1 + numPending / threshold)
// but avoids floating point arithmetic
uint256 multipliedFee = _baseFeeInGwei * (_feeDoubleThreshold + numPending);
feeInGwei_ = uint64((multipliedFee / _feeDoubleThreshold).min(type(uint64).max));
}
/// @notice Returns forced inclusions stored starting from a given index.
/// @dev Returns an empty array if `_start` is outside the valid range [head, tail) or if
/// `_maxCount` is zero. Otherwise returns actual stored entries from the queue.
/// @param _start The queue index to start reading from (must be in range [head, tail)).
/// @param _maxCount Maximum number of inclusions to return. Passing zero returns an empty
/// array.
/// @return inclusions_ Forced inclusions from the queue starting at `_start`. The actual length
/// will be `min(_maxCount, tail - _start)`, or zero if `_start` is out of range.
function getForcedInclusions(
Storage storage $,
uint48 _start,
uint48 _maxCount
)
internal
view
returns (IForcedInclusionStore.ForcedInclusion[] memory inclusions_)
{
unchecked {
(uint48 head, uint48 tail) = ($.head, $.tail);
if (_start < head || _start >= tail || _maxCount == 0) {
return new IForcedInclusionStore.ForcedInclusion[](0);
}
uint256 count = uint256(tail - _start).min(_maxCount);
inclusions_ = new IForcedInclusionStore.ForcedInclusion[](count);
for (uint256 i; i < count; ++i) {
inclusions_[i] = $.queue[i + _start];
}
}
}
/// @dev Returns the queue pointers for the forced inclusion storage.
/// @param $ Storage instance tracking the forced inclusion queue.
/// @return head_ Index of the next forced inclusion to dequeue.
/// @return tail_ Index where the next forced inclusion will be enqueued.
function getForcedInclusionState(Storage storage $)
internal
view
returns (uint48 head_, uint48 tail_)
{
(head_, tail_) = ($.head, $.tail);
}
// ---------------------------------------------------------------
// Internal functions
// ---------------------------------------------------------------
/// @dev Checks if the oldest remaining forced inclusion is due
/// @param $ Storage reference
/// @param _head Current queue head position
/// @param _tail Current queue tail position
/// @param _forcedInclusionDelay Delay in seconds before inclusion is due
/// @return True if the oldest remaining inclusion is due for processing
function isOldestForcedInclusionDue(
Storage storage $,
uint48 _head,
uint48 _tail,
uint16 _forcedInclusionDelay
)
internal
view
returns (bool)
{
unchecked {
if (_head == _tail) return false;
uint256 timestamp = $.queue[_head].blobSlice.timestamp;
if (timestamp == 0) return false;
return block.timestamp >= timestamp + _forcedInclusionDelay;
}
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error InsufficientFee();
error InvalidFeeDoubleThreshold();
error OnlySingleBlobAllowed();
}
contracts/layer1/core/libs/LibInboxSetup.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IInbox } from "../iface/IInbox.sol";
import { LibHashOptimized } from "./LibHashOptimized.sol";
/// @title LibInboxSetup
/// @notice Library for Inbox setup code (constructor validation, activation).
/// @dev Using public functions in a library forces external linking, reducing deployment size
/// of the main contract at the cost of a small runtime gas overhead for the DELEGATECALL.
/// @custom:security-contact security@taiko.xyz
library LibInboxSetup {
// ---------------------------------------------------------------
// Public Functions (externally linked)
// ---------------------------------------------------------------
/// @dev The time window during which activate() can be called after the first activation.
uint256 public constant ACTIVATION_WINDOW = 2 hours;
/// @dev Minimum ring buffer size to keep one slot reserved in capacity calculations.
uint48 public constant MIN_RING_BUFFER_SIZE = 2;
/// @dev Validates the Inbox configuration parameters.
/// @param _config The configuration to validate.
function validateConfig(IInbox.Config memory _config) public pure {
// Validate in the order fields are defined in Config struct.
require(_config.proofVerifier != address(0), ProofVerifierZero());
require(_config.proposerChecker != address(0), ProposerCheckerZero());
require(_config.signalService != address(0), SignalServiceZero());
require(_config.bondToken != address(0), BondTokenZero());
require(_config.provingWindow != 0, ProvingWindowZero());
require(
_config.permissionlessProvingDelay > _config.provingWindow,
PermissionlessProvingDelayTooSmall()
);
require(_config.ringBufferSize >= MIN_RING_BUFFER_SIZE, RingBufferSizeTooSmall());
require(_config.basefeeSharingPctg <= 100, BasefeeSharingPctgTooLarge());
require(_config.minForcedInclusionCount != 0, MinForcedInclusionCountZero());
require(_config.forcedInclusionFeeInGwei != 0, ForcedInclusionFeeInGweiZero());
require(
_config.forcedInclusionFeeDoubleThreshold != 0, ForcedInclusionFeeDoubleThresholdZero()
);
require(
_config.permissionlessInclusionMultiplier > 1,
PermissionlessInclusionMultiplierTooSmall()
);
}
/// @dev Validates activation and computes the initial state for inbox activation.
/// @param _lastPacayaBlockHash The block hash of the last Pacaya block.
/// @param _activationTimestamp The current activation timestamp (0 if not yet activated).
/// @return activationTimestamp_ The activation timestamp to use.
/// @return state_ The initial CoreState.
/// @return proposal_ The genesis proposal.
/// @return genesisProposalHash_ The hash of the genesis proposal (id=0).
function activate(
bytes32 _lastPacayaBlockHash,
uint48 _activationTimestamp
)
public
view
returns (
uint48 activationTimestamp_,
IInbox.CoreState memory state_,
IInbox.Proposal memory proposal_,
bytes32 genesisProposalHash_
)
{
// Validate activation parameters
require(_lastPacayaBlockHash != 0, InvalidLastPacayaBlockHash());
if (_activationTimestamp == 0) {
activationTimestamp_ = uint48(block.timestamp);
} else {
require(
block.timestamp <= ACTIVATION_WINDOW + _activationTimestamp,
ActivationPeriodExpired()
);
activationTimestamp_ = _activationTimestamp;
}
// Set lastProposalBlockId to 1 to ensure the first proposal happens at block 2 or later.
// This prevents reading blockhash(0) in propose(), which would return 0x0 and create
// an invalid origin block hash. The EVM hardcodes blockhash(0) to 0x0, so we must
// ensure proposals never reference the genesis block.
state_.nextProposalId = 1;
state_.lastProposalBlockId = 1;
state_.lastFinalizedTimestamp = uint48(block.timestamp);
state_.lastFinalizedBlockHash = _lastPacayaBlockHash;
genesisProposalHash_ = LibHashOptimized.hashProposal(proposal_);
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error ActivationPeriodExpired();
error BasefeeSharingPctgTooLarge();
error BondTokenZero();
error ForcedInclusionFeeDoubleThresholdZero();
error ForcedInclusionFeeInGweiZero();
error InvalidLastPacayaBlockHash();
error MinForcedInclusionCountZero();
error PermissionlessProvingDelayTooSmall();
error PermissionlessInclusionMultiplierTooSmall();
error ProofVerifierZero();
error ProposerCheckerZero();
error ProvingWindowZero();
error RingBufferSizeTooSmall();
error SignalServiceZero();
}
node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @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.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
contracts/layer1/devnet/DevnetInbox_Layout.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title DevnetInboxLayout
/// @notice Storage layout documentation for DevnetInbox
/// @dev This file is auto-generated by gen-layouts.sh. DO NOT EDIT MANUALLY.
/// @custom:security-contact security@taiko.xyz
// solhint-disable max-line-length
// _initialized | uint8 | Slot: 0 | Offset: 0 | Bytes: 1
// _initializing | bool | Slot: 0 | Offset: 1 | Bytes: 1
// __gap | uint256[50] | Slot: 1 | Offset: 0 | Bytes: 1600
// _owner | address | Slot: 51 | Offset: 0 | Bytes: 20
// __gap | uint256[49] | Slot: 52 | Offset: 0 | Bytes: 1568
// _pendingOwner | address | Slot: 101 | Offset: 0 | Bytes: 20
// __gap | uint256[49] | Slot: 102 | Offset: 0 | Bytes: 1568
// __gapFromOldAddressResolver | uint256[50] | Slot: 151 | Offset: 0 | Bytes: 1600
// __reentry | uint8 | Slot: 201 | Offset: 0 | Bytes: 1
// __paused | uint8 | Slot: 201 | Offset: 1 | Bytes: 1
// __gap | uint256[49] | Slot: 202 | Offset: 0 | Bytes: 1568
// activationTimestamp | uint48 | Slot: 251 | Offset: 0 | Bytes: 6
// _coreState | struct IInbox.CoreState | Slot: 252 | Offset: 0 | Bytes: 64
// _proposalHashes | mapping(uint256 => bytes32) | Slot: 254 | Offset: 0 | Bytes: 32
// _forcedInclusionStorage | struct LibForcedInclusion.Storage | Slot: 255 | Offset: 0 | Bytes: 64
// _bondStorage | struct LibBonds.Storage | Slot: 257 | Offset: 0 | Bytes: 32
// __gap | uint256[43] | Slot: 258 | Offset: 0 | Bytes: 1376
contracts/layer1/core/iface/IBondManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title IBondManager
/// @notice Interface for managing bonds on L1 in the Taiko protocol.
/// @custom:security-contact security@taiko.xyz
interface IBondManager {
// ---------------------------------------------------------------
// Structs
// ---------------------------------------------------------------
/// @notice Represents a bond for a given address.
struct Bond {
/// @notice The bond balance in gwei.
uint64 balance;
/// @notice The timestamp when the withdrawal was requested.
/// @dev 0 = active, >0 = withdrawal requested timestamp
uint48 withdrawalRequestedAt;
}
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
/// @notice Emitted when a bond is deposited.
/// @param depositor The account that made the deposit.
/// @param recipient The account that received the bond credit.
/// @param amount The amount deposited in gwei.
event BondDeposited(address indexed depositor, address indexed recipient, uint64 amount);
/// @notice Emitted when a bond is withdrawn.
/// @param account The account that withdrew the bond.
/// @param amount The amount withdrawn in gwei.
event BondWithdrawn(address indexed account, uint64 amount);
/// @notice Emitted when a withdrawal is requested.
/// @param account The account requesting withdrawal.
/// @param withdrawableAt The timestamp when withdrawal becomes unrestricted.
event WithdrawalRequested(address indexed account, uint48 withdrawableAt);
/// @notice Emitted when a withdrawal request is cancelled.
/// @param account The account cancelling the withdrawal request.
event WithdrawalCancelled(address indexed account);
/// @notice Emitted when a liveness bond is settled.
/// @param payer The account that paid the liveness bond.
/// @param payee The account that received the liveness bond.
/// @param livenessBond The value of the liveness bond in gwei.
/// @param credited The amount of the liveness bond that was credited to the payee in gwei.
/// @param slashed The amount of the liveness bond that was slashed in gwei.
event LivenessBondSettled(
address indexed payer,
address indexed payee,
uint64 livenessBond,
uint64 credited,
uint64 slashed
);
// ---------------------------------------------------------------
// Transactional Functions
// ---------------------------------------------------------------
/// @notice Deposits bond tokens for the caller.
/// @dev Clears the caller's pending withdrawal request, if any.
/// @param _amount The amount to deposit in gwei.
function deposit(uint64 _amount) external;
/// @notice Deposits bond tokens for a recipient.
/// @dev Recipient must be non-zero. Does not cancel the recipient's pending withdrawal,
/// even if the recipient is the caller.
/// @param _recipient The address to credit the bond to.
/// @param _amount The amount to deposit in gwei.
function depositTo(address _recipient, uint64 _amount) external;
/// @notice Withdraws bond to a recipient.
/// @dev Withdrawals are subject to a delay so bond operations can be resolved properly.
/// The user can always withdraw any excess amount without delays.
/// If this withdrawal debits the entire bond balance, any pending withdrawal request is
/// cleared.
/// @param _to The recipient of withdrawn funds.
/// @param _amount The amount to withdraw in gwei.
function withdraw(address _to, uint64 _amount) external;
/// @notice Requests to start the withdrawal process.
/// @dev Account cannot perform bond-restricted actions after requesting withdrawal.
function requestWithdrawal() external;
/// @notice Cancels withdrawal request to reactivate the account.
/// @dev Can be called during or after the withdrawal delay period.
function cancelWithdrawal() external;
// ---------------------------------------------------------------
// View Functions
// ---------------------------------------------------------------
/// @notice Gets the bond state of an address.
/// @param _address The address to get the bond state for.
/// @return bond_ The bond struct for the address.
function getBond(address _address) external view returns (Bond memory bond_);
}
node_modules/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
contracts/layer1/core/libs/LibHashOptimized.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { IInbox } from "../iface/IInbox.sol";
import { EfficientHashLib } from "solady/src/utils/EfficientHashLib.sol";
/// @title LibHashOptimized
/// @notice Optimized hashing functions using Solady's EfficientHashLib(when more efficient than keccak256)
/// @dev This library provides gas-optimized implementations of all hashing functions
/// used in the Inbox contract, replacing standard keccak256(abi.encode(...)) calls
/// with more efficient alternatives from Solady's EfficientHashLib(when more efficient than keccak256).
/// @custom:security-contact security@taiko.xyz
library LibHashOptimized {
// ---------------------------------------------------------------
// Core Structure Hashing Functions
// ---------------------------------------------------------------
/// @notice Hashing for proposal data.
/// @dev Uses keccak256(abi.encode(...)) to hash the proposal. Contrarty to the intuition,
/// this is as efficient if not more than using `EfficientHashLib` in this case because
/// the structure of the data(nested dynamic arryas).
/// @param _proposal The proposal to hash
/// @return The hash of the proposal
function hashProposal(IInbox.Proposal memory _proposal) internal pure returns (bytes32) {
/// forge-lint: disable-start(asm-keccak256)
return keccak256(abi.encode(_proposal));
}
/// @notice Optimized hashing for commitment data.
/// @param _commitment The commitment data to hash.
/// @return The hash of the commitment.
function hashCommitment(IInbox.Commitment memory _commitment) internal pure returns (bytes32) {
unchecked {
IInbox.Transition[] memory transitions = _commitment.transitions;
uint256 transitionsLength = transitions.length;
// Commitment layout (abi.encode):
// [0] offset to commitment (0x20)
//
// Commitment static section (starts at word 1):
// [1] firstProposalId
// [2] firstProposalParentBlockHash
// [3] lastProposalHash
// [4] actualProver
// [5] endBlockNumber
// [6] endStateRoot
// [7] offset to transitions (0xe0)
//
// Transitions array (starts at word 8):
// [8] length
// [9...] transition elements (3 words each)
uint256 totalWords = 9 + transitionsLength * 3;
bytes32[] memory buffer = EfficientHashLib.malloc(totalWords);
// Top-level head
EfficientHashLib.set(buffer, 0, bytes32(uint256(0x20)));
// Commitment static fields
EfficientHashLib.set(buffer, 1, bytes32(uint256(_commitment.firstProposalId)));
EfficientHashLib.set(buffer, 2, _commitment.firstProposalParentBlockHash);
EfficientHashLib.set(buffer, 3, _commitment.lastProposalHash);
EfficientHashLib.set(buffer, 4, bytes32(uint256(uint160(_commitment.actualProver))));
EfficientHashLib.set(buffer, 5, bytes32(uint256(_commitment.endBlockNumber)));
EfficientHashLib.set(buffer, 6, _commitment.endStateRoot);
EfficientHashLib.set(buffer, 7, bytes32(uint256(0xe0)));
// Transitions array
EfficientHashLib.set(buffer, 8, bytes32(transitionsLength));
uint256 base = 9;
for (uint256 i; i < transitionsLength; ++i) {
IInbox.Transition memory transition = transitions[i];
EfficientHashLib.set(buffer, base, bytes32(uint256(uint160(transition.proposer))));
EfficientHashLib.set(buffer, base + 1, bytes32(uint256(transition.timestamp)));
EfficientHashLib.set(buffer, base + 2, transition.blockHash);
base += 3;
}
bytes32 result = EfficientHashLib.hash(buffer);
EfficientHashLib.free(buffer);
return result;
}
}
}
contracts/layer1/mainnet/LibFasterReentryLock.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title LibFasterReentryLock
/// @custom:security-contact security@taiko.xyz
library LibFasterReentryLock {
/// @dev The slot in transient storage of the reentry lock.
/// This is the result of keccak256("ownerUUPS.reentry_slot") plus 1. The addition aims to
/// prevent hash collisions with slots defined in EIP-1967, where slots are derived by
/// keccak256("something") - 1, and with slots in SignalService, calculated directly with
/// keccak256("something").
bytes32 private constant _REENTRY_SLOT =
0xa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b;
function storeReentryLock(uint8 _reentry) internal {
assembly {
tstore(_REENTRY_SLOT, _reentry)
}
}
function loadReentryLock() internal view returns (uint8 reentry_) {
assembly {
reentry_ := tload(_REENTRY_SLOT)
}
}
}
node_modules/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
contracts/layer1/core/libs/LibBonds.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IBondManager } from "../iface/IBondManager.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// @title LibBonds
/// @notice Library for bond ledger operations and settlement.
/// @custom:security-contact security@taiko.xyz
library LibBonds {
using SafeERC20 for IERC20;
// ---------------------------------------------------------------
// Constants
// ---------------------------------------------------------------
uint256 internal constant GWEI_UNIT = 1 gwei;
// ---------------------------------------------------------------
// Storage
// ---------------------------------------------------------------
/// @dev Storage layout for bond balances. Each bond packs into one slot.
struct Storage {
mapping(address account => IBondManager.Bond bond) bonds;
}
// ---------------------------------------------------------------
// Internal Functions meant to be called by contracts that use this library
// ---------------------------------------------------------------
/// @dev Deposits bond tokens in gwei units and credits the recipient.
/// If `_cancelWithdrawal` is true, the pending withdrawal request is cleared.
function deposit(
Storage storage $,
IERC20 _bondToken,
address _depositor,
address _recipient,
uint64 _amount,
bool _cancelWithdrawal
)
internal
{
if (_recipient == address(0)) revert InvalidAddress();
_creditBond($, _recipient, _amount);
if (_cancelWithdrawal && $.bonds[_recipient].withdrawalRequestedAt != 0) {
$.bonds[_recipient].withdrawalRequestedAt = 0;
}
_bondToken.safeTransferFrom(_depositor, address(this), _toTokenAmount(_amount));
emit IBondManager.BondDeposited(_depositor, _recipient, _amount);
}
/// @dev Withdraws bond tokens in gwei units to a recipient.
/// If the full balance is withdrawn, the pending withdrawal request is cleared.
function withdraw(
Storage storage $,
IERC20 _bondToken,
address _from,
address _to,
uint64 _amount,
uint64 _minBond,
uint48 _withdrawalDelay
)
internal
returns (uint64 debited_)
{
if (_to == address(0)) revert InvalidAddress();
IBondManager.Bond storage bond_ = $.bonds[_from];
uint64 balance = bond_.balance;
uint64 amount = _amount > balance ? balance : _amount;
if (
bond_.withdrawalRequestedAt == 0
|| block.timestamp < bond_.withdrawalRequestedAt + _withdrawalDelay
) {
require(balance - amount >= _minBond, MustMaintainMinBond());
}
debited_ = _debitBond($, _from, amount);
if (debited_ == balance && bond_.withdrawalRequestedAt != 0) {
bond_.withdrawalRequestedAt = 0;
}
_bondToken.safeTransfer(_to, _toTokenAmount(debited_));
emit IBondManager.BondWithdrawn(_from, debited_);
}
/// @dev Requests a withdrawal. Withdrawals are unrestricted after the delay.
function requestWithdrawal(
Storage storage $,
address _account,
uint48 _withdrawalDelay
)
internal
{
IBondManager.Bond memory bond_ = $.bonds[_account];
if (bond_.balance == 0) revert NoBondToWithdraw();
if (bond_.withdrawalRequestedAt != 0) revert WithdrawalAlreadyRequested();
bond_.withdrawalRequestedAt = uint48(block.timestamp);
$.bonds[_account] = bond_;
emit IBondManager.WithdrawalRequested(_account, uint48(block.timestamp + _withdrawalDelay));
}
/// @dev Cancels a pending withdrawal request.
function cancelWithdrawal(Storage storage $, address _account) internal {
IBondManager.Bond storage bond_ = $.bonds[_account];
if (bond_.withdrawalRequestedAt == 0) revert NoWithdrawalRequested();
bond_.withdrawalRequestedAt = 0;
emit IBondManager.WithdrawalCancelled(_account);
}
/// @dev Returns the bond state for an account.
function getBond(
Storage storage $,
address _account
)
internal
view
returns (IBondManager.Bond memory)
{
return $.bonds[_account];
}
/// @dev Checks if an account has sufficient bond and is active.
function hasSufficientBond(
Storage storage $,
address _account,
uint64 _minBond
)
internal
view
returns (bool)
{
IBondManager.Bond storage bond_ = $.bonds[_account];
return bond_.balance >= _minBond && bond_.withdrawalRequestedAt == 0;
}
/// @dev Applies a liveness bond slash with a 50/50 split (payee/burn).
/// @param $ Storage reference.
/// @param _payer Account whose bond is debited.
/// @param _payee Account credited with half of the debited bond.
/// @param _livenessBond Liveness bond amount in gwei.
function settleLivenessBond(
Storage storage $,
address _payer,
address _payee,
uint64 _livenessBond
)
internal
{
// We try to debit the full liveness bond, but since it is best effort
// the amount may be lower.
uint64 debited = _debitBond($, _payer, _livenessBond);
if (debited == 0) return;
uint64 payeeAmount = debited / 2;
uint64 slashedAmount = debited - payeeAmount;
if (payeeAmount > 0) {
_creditBond($, _payee, payeeAmount);
}
emit IBondManager.LivenessBondSettled(
_payer, _payee, _livenessBond, payeeAmount, slashedAmount
);
}
// ---------------------------------------------------------------
// Private Functions
// ---------------------------------------------------------------
/// @dev Debits a bond with best effort.
function _debitBond(
Storage storage $,
address _account,
uint64 _amount
)
private
returns (uint64 debited_)
{
IBondManager.Bond storage bond_ = $.bonds[_account];
if (bond_.balance <= _amount) {
debited_ = bond_.balance;
bond_.balance = 0;
} else {
debited_ = _amount;
bond_.balance = bond_.balance - _amount;
}
}
/// @dev Credits a bond balance.
function _creditBond(Storage storage $, address _account, uint64 _amount) private {
IBondManager.Bond storage bond_ = $.bonds[_account];
bond_.balance = bond_.balance + _amount;
}
/// @dev Converts bond amounts in gwei to token units (18 decimals).
function _toTokenAmount(uint64 _amount) private pure returns (uint256) {
return uint256(_amount) * GWEI_UNIT;
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error InvalidAddress();
error MustMaintainMinBond();
error NoBondToWithdraw();
error NoWithdrawalRequested();
error WithdrawalAlreadyRequested();
}
contracts/layer1/core/libs/LibTransitionCodec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { IInbox } from "../iface/IInbox.sol";
import { LibPackUnpack as P } from "./LibPackUnpack.sol";
/// @title LibTransitionCodec
/// @notice Shared transition encode/decode helpers to avoid duplication across codecs.
/// @custom:security-contact security@taiko.xyz
library LibTransitionCodec {
uint256 internal constant TRANSITION_SIZE = 58;
function encodeTransition(
uint256 _ptr,
IInbox.Transition memory _transition
)
internal
pure
returns (uint256 newPtr_)
{
newPtr_ = P.packAddress(_ptr, _transition.proposer);
newPtr_ = P.packUint48(newPtr_, _transition.timestamp);
newPtr_ = P.packBytes32(newPtr_, _transition.blockHash);
}
function decodeTransition(uint256 _ptr)
internal
pure
returns (IInbox.Transition memory transition_, uint256 newPtr_)
{
(transition_.proposer, newPtr_) = P.unpackAddress(_ptr);
(transition_.timestamp, newPtr_) = P.unpackUint48(newPtr_);
(transition_.blockHash, newPtr_) = P.unpackBytes32(newPtr_);
}
}
contracts/layer1/core/iface/IInbox.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { LibBlobs } from "../libs/LibBlobs.sol";
/// @title IInbox
/// @notice Interface for the Shasta inbox contracts
/// @custom:security-contact security@taiko.xyz
interface IInbox {
/// @notice Configuration struct for Inbox constructor parameters
struct Config {
/// @notice The proof verifier contract
address proofVerifier;
/// @notice The proposer checker contract
address proposerChecker;
/// @notice The prover whitelist contract (address(0) means no whitelist)
address proverWhitelist;
/// @notice The signal service contract address
address signalService;
/// @notice The ERC20 bond token address
address bondToken;
/// @notice The minimum bond a proposer is required to have in gwei
uint64 minBond;
/// @notice The liveness bond amount in gwei
uint64 livenessBond;
/// @notice The withdrawal delay in seconds
uint48 withdrawalDelay;
/// @notice The proving window in seconds
uint48 provingWindow;
/// @notice The delay after which proving becomes permissionless when whitelist is enabled
/// @dev Must be greater than provingWindow
uint48 permissionlessProvingDelay;
/// @notice Maximum delay allowed between consecutive proofs to still be on time.
/// @dev Must be shorter than the expected proposal cadence to prevent backlog growth.
uint48 maxProofSubmissionDelay;
/// @notice The ring buffer size for storing proposal hashes
uint48 ringBufferSize;
/// @notice The percentage of basefee paid to coinbase
uint8 basefeeSharingPctg;
/// @notice The minimum number of forced inclusions that the proposer is forced to process
/// if they are due
uint256 minForcedInclusionCount;
/// @notice The delay for forced inclusions measured in seconds
uint16 forcedInclusionDelay;
/// @notice The base fee for forced inclusions in Gwei used in dynamic fee calculation
uint64 forcedInclusionFeeInGwei;
/// @notice Queue size at which the fee doubles
uint64 forcedInclusionFeeDoubleThreshold;
/// @notice The minimum delay between checkpoints in seconds
/// @dev Used to rate-limit checkpoint syncing in `prove`.
uint16 minCheckpointDelay;
/// @notice The multiplier to determine when a forced inclusion is too old so that proposing
/// becomes permissionless
uint8 permissionlessInclusionMultiplier;
}
/// @notice Represents a source of derivation data within a Proposal
struct DerivationSource {
/// @notice Whether this source is from a forced inclusion.
bool isForcedInclusion;
/// @notice Blobs that contain the source's manifest data.
LibBlobs.BlobSlice blobSlice;
}
/// @notice Represents a proposal for L2 blocks.
struct Proposal {
/// @notice Unique identifier for the proposal.
uint48 id;
/// @notice The L1 block timestamp when the proposal was accepted.
uint48 timestamp;
/// @notice The timestamp of the last slot where the current preconfer can propose.
uint48 endOfSubmissionWindowTimestamp;
/// @notice Address of the proposer.
address proposer;
/// @notice Hash of the parent proposal (zero for genesis).
bytes32 parentProposalHash;
/// @notice The L1 block number when the proposal was accepted.
uint48 originBlockNumber;
/// @notice The hash of the origin block.
bytes32 originBlockHash;
/// @notice The percentage of base fee paid to coinbase.
uint8 basefeeSharingPctg;
/// @notice Array of derivation sources, where each can be regular or forced inclusion.
DerivationSource[] sources;
}
/// @notice Represents the core state of the inbox.
/// @dev All 5 uint48 fields (30 bytes) pack into a single storage slot.
struct CoreState {
/// @notice The next proposal ID to be assigned.
uint48 nextProposalId;
/// @notice The L1 block number where the most recent proposal was made.
uint48 lastProposalBlockId;
/// @notice The ID of the last proven (finalized) proposal.
uint48 lastFinalizedProposalId;
/// @notice The timestamp when the last proposal was proven (finalized).
uint48 lastFinalizedTimestamp;
/// @notice The timestamp when the last checkpoint was saved.
/// @dev In genesis block, this is set to 0 to allow the first checkpoint to be saved.
uint48 lastCheckpointTimestamp;
/// @notice The block hash of the last proven (finalized) proposal.
bytes32 lastFinalizedBlockHash;
}
/// @notice Input data for the propose function
struct ProposeInput {
/// @notice The deadline timestamp for transaction inclusion (0 = no deadline).
uint48 deadline;
/// @notice Blob reference for proposal data.
LibBlobs.BlobReference blobReference;
/// @notice The number of forced inclusions that the proposer wants to process.
/// @dev This can be set to 0 if no forced inclusions are due, and there's none in the queue
/// that he wants to include.
uint8 numForcedInclusions;
}
/// @notice Transition data for a proposal used in prove
struct Transition {
/// @notice Address of the proposer.
address proposer;
/// @notice Timestamp of the proposal.
uint48 timestamp;
/// @notice end block hash for the proposal.
bytes32 blockHash;
}
/// @notice Commitment data that the prover commits to when submitting a proof.
struct Commitment {
/// @notice The ID of the first proposal being proven.
uint48 firstProposalId;
/// @notice The checkpoint hash of the parent of the first proposal, this is used
/// to verify checkpoint continuity in the proof.
bytes32 firstProposalParentBlockHash;
/// @notice The hash of the last proposal being proven.
bytes32 lastProposalHash;
/// @notice The actual prover who generated the proof.
address actualProver;
/// @notice The block number for the end L2 block in this proposal.
uint48 endBlockNumber;
/// @notice The state root for the end L2 block in this proposal.
bytes32 endStateRoot;
/// @notice Array of transitions for each proposal in the proof range.
Transition[] transitions;
}
/// @notice Input data for the prove function.
/// @dev This struct contains two categories of data:
/// 1. Commitment data - What the prover is actually proving. This must be fully
/// determined before proof generation and is the only input to the prover's
/// guest program.
/// 2. Usage options - Parameters that can be decided after proof generation
/// (e.g., whether to proactively write a checkpoint). The prover system can
/// choose or adjust these options using additional data during or after
/// proof generation.
struct ProveInput {
/// @notice The commitment data that the proof verifies.
Commitment commitment;
/// @notice Whether to force syncing the last checkpoint even if the minimum
/// delay has not passed.
/// @dev This allows checkpoint synchronization ahead of schedule.
bool forceCheckpointSync;
}
/// @notice Payload data emitted in the Proved event
struct ProvedEventPayload {
/// @notice The ID of the first proposal being proven.
uint48 firstProposalId;
/// @notice The ID of the first proposal that had not been proven before.
uint48 firstNewProposalId;
/// @notice The ID of the last proposal being proven.
uint48 lastProposalId;
/// @notice The actual prover who generated the proof.
address actualProver;
/// @notice Whether the checkpoint was synced.
bool checkpointSynced;
}
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
/// @notice Emitted when a new proposal is proposed.
/// @param id Unique identifier for the proposal.
/// @param proposer Address of the proposer.
/// @param parentProposalHash The hash of the parent proposal (zero for genesis).
/// @param endOfSubmissionWindowTimestamp Last slot timestamp where the preconfer can propose.
/// @param basefeeSharingPctg The percentage of base fee paid to coinbase.
/// @param sources Array of derivation sources for this proposal.
event Proposed(
uint48 indexed id,
address indexed proposer,
bytes32 parentProposalHash,
uint48 endOfSubmissionWindowTimestamp,
uint8 basefeeSharingPctg,
DerivationSource[] sources
);
/// @notice Emitted when a proof is submitted
/// @param firstProposalId The first proposal ID covered by the proof (may include finalized ids)
/// @param firstNewProposalId The first proposal ID that was newly proven by this proof
/// @param lastProposalId The last proposal ID covered by the proof
/// @param actualProver The prover that submitted the proof
/// @param checkpointSynced Whether a checkpoint was synced as part of this proof
event Proved(
uint48 firstProposalId,
uint48 firstNewProposalId,
uint48 lastProposalId,
address indexed actualProver,
bool checkpointSynced
);
// ---------------------------------------------------------------
// External Transactional Functions
// ---------------------------------------------------------------
/// @notice Proposes new L2 blocks and forced inclusions to the rollup using blobs for DA.
/// @param _lookahead Encoded data forwarded to the proposer checker (i.e. lookahead payloads).
/// @param _data The encoded ProposeInput struct.
function propose(bytes calldata _lookahead, bytes calldata _data) external;
/// @notice Verifies a batch proof covering multiple consecutive proposals and finalizes them.
/// @param _data The encoded ProveInput struct.
/// @param _proof The validity proof for the batch of proposals.
function prove(bytes calldata _data, bytes calldata _proof) external;
// ---------------------------------------------------------------
// External View Functions
// ---------------------------------------------------------------
/// @notice Returns the configuration parameters of the Inbox contract
/// @return config_ The configuration struct containing all immutable parameters
function getConfig() external view returns (Config memory config_);
/// @notice Returns the current core state.
/// @return The core state struct.
function getCoreState() external view returns (CoreState memory);
/// @notice Returns the proposal hash for a given proposal ID.
/// @param _proposalId The proposal ID to look up.
/// @return proposalHash_ The hash stored at the proposal's ring buffer slot.
function getProposalHash(uint256 _proposalId) external view returns (bytes32 proposalHash_);
}
node_modules/solady/src/utils/EfficientHashLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MALLOC-LESS HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(bytes32 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0))`.
function hash(uint256 v0) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
result := keccak256(0x00, 0x20)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1))`.
function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, v0)
mstore(0x20, v1)
result := keccak256(0x00, 0x40)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
result := keccak256(m, 0x60)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
result := keccak256(m, 0x80)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
result := keccak256(m, 0xa0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
result := keccak256(m, 0xc0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
result := keccak256(m, 0xe0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
result := keccak256(m, 0x100)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
result := keccak256(m, 0x120)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
result := keccak256(m, 0x140)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
result := keccak256(m, 0x160)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
result := keccak256(m, 0x180)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
result := keccak256(m, 0x1a0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
bytes32 v0,
bytes32 v1,
bytes32 v2,
bytes32 v3,
bytes32 v4,
bytes32 v5,
bytes32 v6,
bytes32 v7,
bytes32 v8,
bytes32 v9,
bytes32 v10,
bytes32 v11,
bytes32 v12,
bytes32 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
function hash(
uint256 v0,
uint256 v1,
uint256 v2,
uint256 v3,
uint256 v4,
uint256 v5,
uint256 v6,
uint256 v7,
uint256 v8,
uint256 v9,
uint256 v10,
uint256 v11,
uint256 v12,
uint256 v13
) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, v0)
mstore(add(m, 0x20), v1)
mstore(add(m, 0x40), v2)
mstore(add(m, 0x60), v3)
mstore(add(m, 0x80), v4)
mstore(add(m, 0xa0), v5)
mstore(add(m, 0xc0), v6)
mstore(add(m, 0xe0), v7)
mstore(add(m, 0x100), v8)
mstore(add(m, 0x120), v9)
mstore(add(m, 0x140), v10)
mstore(add(m, 0x160), v11)
mstore(add(m, 0x180), v12)
mstore(add(m, 0x1a0), v13)
result := keccak256(m, 0x1c0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES32 BUFFER HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
}
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, bytes32 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Sets `buffer[i]` to `value`, without a bounds check.
/// Returns the `buffer` for function chaining.
function set(bytes32[] memory buffer, uint256 i, uint256 value)
internal
pure
returns (bytes32[] memory)
{
/// @solidity memory-safe-assembly
assembly {
mstore(add(buffer, shl(5, add(1, i))), value)
}
return buffer;
}
/// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
/// @solidity memory-safe-assembly
assembly {
buffer := mload(0x40)
mstore(buffer, n)
mstore(0x40, add(shl(5, add(1, n)), buffer))
}
}
/// @dev Frees memory that has been allocated for `buffer`.
/// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
function free(bytes32[] memory buffer) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(buffer)
mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EQUALITY CHECKS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a == abi.decode(b, (bytes32))`.
function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
}
}
/// @dev Returns `abi.decode(a, (bytes32)) == a`.
function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE SLICE HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hash(bytes memory b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
}
}
/// @dev Returns the keccak256 of the bytes.
function hash(bytes memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := keccak256(add(b, 0x20), mload(b))
}
}
/// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function hashCalldata(bytes calldata b, uint256 start, uint256 end)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := keccak256(mload(0x40), n)
}
}
/// @dev Returns the keccak256 of the bytes.
function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := keccak256(mload(0x40), b.length)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SHA2-256 HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
function sha2(bytes32 b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, b)
result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2(bytes memory b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
end := xor(end, mul(xor(end, n), lt(n, end)))
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(end, start), sub(end, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(b)
start := xor(start, mul(xor(start, n), lt(n, start)))
// forgefmt: disable-next-item
result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
mul(gt(n, start), sub(n, start)), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2(bytes memory b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
internal
view
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(end, start), sub(end, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
let n := mul(gt(b.length, start), sub(b.length, start))
calldatacopy(mload(0x40), add(b.offset, start), n)
result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
/// @dev Returns the sha256 of the bytes.
function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
calldatacopy(mload(0x40), b.offset, b.length)
result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
if iszero(returndatasize()) { invalid() }
}
}
}
contracts/layer1/core/impl/Inbox.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IBondManager } from "../iface/IBondManager.sol";
import { ICodec } from "../iface/ICodec.sol";
import { IForcedInclusionStore } from "../iface/IForcedInclusionStore.sol";
import { IInbox } from "../iface/IInbox.sol";
import { IProposerChecker } from "../iface/IProposerChecker.sol";
import { IProverWhitelist } from "../iface/IProverWhitelist.sol";
import { LibBlobs } from "../libs/LibBlobs.sol";
import { LibBonds } from "../libs/LibBonds.sol";
import { LibCodec } from "../libs/LibCodec.sol";
import { LibForcedInclusion } from "../libs/LibForcedInclusion.sol";
import { LibHashOptimized } from "../libs/LibHashOptimized.sol";
import { LibInboxSetup } from "../libs/LibInboxSetup.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IProofVerifier } from "src/layer1/verifiers/IProofVerifier.sol";
import { EssentialContract } from "src/shared/common/EssentialContract.sol";
import { LibAddress } from "src/shared/libs/LibAddress.sol";
import { LibMath } from "src/shared/libs/LibMath.sol";
import { ICheckpointStore } from "src/shared/signal/ICheckpointStore.sol";
import { ISignalService } from "src/shared/signal/ISignalService.sol";
/// @title Inbox
/// @notice Core contract for managing L2 proposals, proof verification, and forced inclusion in
/// Taiko's based rollup architecture.
/// @dev The Pacaya inbox contract is not being upgraded to the Shasta implementation;
/// instead, Shasta uses a separate inbox address.
/// @dev This contract implements the fundamental inbox logic including:
/// - Proposal submission with forced inclusion support
/// - Sequential proof verification
/// - Ring buffer storage for efficient state management
/// - Bond accounting and liveness bond processing
/// - Finalization of proven proposals with checkpoint rate limiting
/// @custom:security-contact security@taiko.xyz
contract Inbox is IInbox, ICodec, IForcedInclusionStore, IBondManager, EssentialContract {
using LibAddress for address;
using LibBonds for LibBonds.Storage;
using LibForcedInclusion for LibForcedInclusion.Storage;
using LibMath for uint48;
using LibMath for uint256;
// ---------------------------------------------------------------
// Structs
// ---------------------------------------------------------------
/// @notice Result from consuming forced inclusions
struct ConsumptionResult {
DerivationSource[] sources;
bool allowsPermissionless;
}
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
event InboxActivated(bytes32 lastPacayaBlockHash);
// ---------------------------------------------------------------
// Immutable Variables
// ---------------------------------------------------------------
/// @notice The proof verifier contract.
IProofVerifier internal immutable _proofVerifier;
/// @notice The proposer checker contract.
IProposerChecker internal immutable _proposerChecker;
/// @notice The prover whitelist contract (address(0) means no whitelist)
IProverWhitelist internal immutable _proverWhitelist;
/// @notice Signal service responsible for checkpoints.
ISignalService internal immutable _signalService;
/// @notice ERC20 token used as bond.
IERC20 internal immutable _bondToken;
/// @notice Minimum bond the proposer is required to have in gwei.
uint64 internal immutable _minBond;
/// @notice Liveness bond amount in gwei.
uint64 internal immutable _livenessBond;
/// @notice Time delay required before withdrawal after request.
uint48 internal immutable _withdrawalDelay;
/// @notice The proving window in seconds.
uint48 internal immutable _provingWindow;
/// @notice The delay after which proving becomes permissionless when whitelist is enabled.
uint48 internal immutable _permissionlessProvingDelay;
/// @notice Maximum delay allowed between sequential proofs to remain on time.
uint48 internal immutable _maxProofSubmissionDelay;
/// @notice The ring buffer size for storing proposal hashes.
uint48 internal immutable _ringBufferSize;
/// @notice The percentage of basefee paid to coinbase.
uint8 internal immutable _basefeeSharingPctg;
/// @notice The minimum number of forced inclusions that the proposer is forced to process if
/// they are due.
uint256 internal immutable _minForcedInclusionCount;
/// @notice The delay for forced inclusions measured in seconds.
uint16 internal immutable _forcedInclusionDelay;
/// @notice The base fee for forced inclusions in Gwei.
uint64 internal immutable _forcedInclusionFeeInGwei;
/// @notice Queue size at which the fee doubles. See Config for formula details.
uint64 internal immutable _forcedInclusionFeeDoubleThreshold;
/// @notice The minimum delay between checkpoints in seconds.
uint16 internal immutable _minCheckpointDelay;
/// @notice The multiplier to determine when a forced inclusion is too old so that proposing
/// becomes permissionless
uint8 internal immutable _permissionlessInclusionMultiplier;
// ---------------------------------------------------------------
// State Variables
// ---------------------------------------------------------------
/// @notice The timestamp when the first activation occurred.
uint48 public activationTimestamp;
/// @notice Persisted core state.
CoreState internal _coreState;
/// @dev Ring buffer for storing proposal hashes indexed by buffer slot
/// - bufferSlot: The ring buffer slot calculated as proposalId % ringBufferSize
/// - proposalHash: The keccak256 hash of the Proposal struct
mapping(uint256 bufferSlot => bytes32 proposalHash) internal _proposalHashes;
/// @dev Storage for forced inclusion requests
/// @dev 2 slots used
LibForcedInclusion.Storage private _forcedInclusionStorage;
/// @dev Storage for bond balances.
LibBonds.Storage private _bondStorage;
uint256[43] private __gap;
// ---------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------
/// @notice Initializes the Inbox contract
/// @param _config Configuration struct containing all constructor parameters
constructor(Config memory _config) {
LibInboxSetup.validateConfig(_config);
_proofVerifier = IProofVerifier(_config.proofVerifier);
_proposerChecker = IProposerChecker(_config.proposerChecker);
_proverWhitelist = IProverWhitelist(_config.proverWhitelist);
_signalService = ISignalService(_config.signalService);
_bondToken = IERC20(_config.bondToken);
_minBond = _config.minBond;
_livenessBond = _config.livenessBond;
_withdrawalDelay = _config.withdrawalDelay;
_provingWindow = _config.provingWindow;
_permissionlessProvingDelay = _config.permissionlessProvingDelay;
_maxProofSubmissionDelay = _config.maxProofSubmissionDelay;
_ringBufferSize = _config.ringBufferSize;
_basefeeSharingPctg = _config.basefeeSharingPctg;
_minForcedInclusionCount = _config.minForcedInclusionCount;
_forcedInclusionDelay = _config.forcedInclusionDelay;
_forcedInclusionFeeInGwei = _config.forcedInclusionFeeInGwei;
_forcedInclusionFeeDoubleThreshold = _config.forcedInclusionFeeDoubleThreshold;
_minCheckpointDelay = _config.minCheckpointDelay;
_permissionlessInclusionMultiplier = _config.permissionlessInclusionMultiplier;
}
// ---------------------------------------------------------------
// External Functions
// ---------------------------------------------------------------
/// @notice Initializes the owner of the inbox.
/// @param _owner The owner of this contract
function init(address _owner) external initializer {
__Essential_init(_owner);
}
/// @notice Activates the inbox so that it can start accepting proposals.
/// @dev Can be called multiple times within the activation window to handle reorgs.
/// @param _lastPacayaBlockHash The block hash of the last Pacaya block
function activate(bytes32 _lastPacayaBlockHash) external onlyOwner {
(
uint48 newActivationTimestamp,
CoreState memory state,
Proposal memory proposal,
bytes32 genesisProposalHash
) = LibInboxSetup.activate(_lastPacayaBlockHash, activationTimestamp);
activationTimestamp = newActivationTimestamp;
_coreState = state;
_setProposalHash(0, genesisProposalHash);
_emitProposedEvent(proposal);
emit InboxActivated(_lastPacayaBlockHash);
}
/// @inheritdoc IInbox
/// @notice Proposes new L2 blocks and forced inclusions to the rollup using blobs for DA.
/// @dev Key behaviors:
/// 1. Validates proposer authorization via `IProposerChecker`
/// 2. Process `input.numForcedInclusions` forced inclusions. The proposer is forced to
/// process at least `config.minForcedInclusionCount` if they are due.
/// 3. Updates core state and emits `Proposed` event
/// NOTE: This function can only be called once per block to prevent spams that can fill the
/// ring buffer.
function propose(bytes calldata _lookahead, bytes calldata _data) external nonReentrant {
unchecked {
ProposeInput memory input = LibCodec.decodeProposeInput(_data);
_validateProposeInput(input);
uint48 nextProposalId = _coreState.nextProposalId;
uint48 lastProposalBlockId = _coreState.lastProposalBlockId;
uint48 lastFinalizedProposalId = _coreState.lastFinalizedProposalId;
require(nextProposalId > 0, ActivationRequired());
Proposal memory proposal = _buildProposal(
input, _lookahead, nextProposalId, lastProposalBlockId, lastFinalizedProposalId
);
_coreState.nextProposalId = nextProposalId + 1;
_coreState.lastProposalBlockId = uint48(block.number);
_setProposalHash(proposal.id, LibHashOptimized.hashProposal(proposal));
_emitProposedEvent(proposal);
}
}
/// @inheritdoc IInbox
/// @dev When prover whitelist is enabled, only the whitested prover(s) can prove. If
/// there are not proofs submitted for `permissionlessProvingDelay` seconds, proving becomes
/// permisionless.
/// @dev The proof covers a contiguous range of proposals. The input contains an array of
/// Transition structs, each with the proposal's metadata and checkpoint hash. The proof range
/// can start at or before the last finalized proposal to handle race conditions where
/// proposals get finalized between proof generation and submission.
///
/// Example: Proving proposals 3-7 when lastFinalizedProposalId=4
///
/// lastFinalizedProposalId nextProposalId
/// ┆ ┆
/// ▼ ▼
/// 0 1 2 3 4 5 6 7 8 9
/// ■─────■─────■─────■─────■─────□─────□─────□─────□─────
/// ▲ ▲ ▲
/// ┆<-offset-> ┆ ┆
/// ┆ ┆
/// ┆<- input.transitions[] ->┆
/// firstProposalId lastProposalId
///
/// Key validation rules:
/// 1. firstProposalId <= lastFinalizedProposalId + 1 (can overlap with finalized range)
/// 2. lastProposalId < nextProposalId (cannot prove unproposed blocks)
/// 3. lastProposalId >= lastFinalizedProposalId + 1 (must advance at least one proposal)
/// 4. The block hash must link to the lastFinalizedBlockHash
///
/// @param _data Encoded ProveInput struct
/// @param _proof Validity proof for the batch of proposals
function prove(bytes calldata _data, bytes calldata _proof) external {
unchecked {
CoreState memory state = _coreState;
ProveInput memory input = LibCodec.decodeProveInput(_data);
// -------------------------------------------------------------------------------
// 1. Validate batch bounds and calculate offset of the first unfinalized proposal
// -------------------------------------------------------------------------------
Commitment memory commitment = input.commitment;
// `offset` is the index of the next-to-finalize proposal in the transitions array.
(uint256 numProposals, uint256 lastProposalId, uint48 offset) =
_validateCommitment(state, commitment);
uint256 proposalAge = block.timestamp - commitment.transitions[offset].timestamp;
bool isWhitelistEnabled = _checkProver(msg.sender, proposalAge);
// ---------------------------------------------------------
// 2. Verify checkpoint hash continuity and last proposal hash
// ---------------------------------------------------------
// The parent block hash must match the stored lastFinalizedBlockHash.
bytes32 expectedParentHash = offset == 0
? commitment.firstProposalParentBlockHash
: commitment.transitions[offset - 1].blockHash;
require(state.lastFinalizedBlockHash == expectedParentHash, ParentBlockHashMismatch());
require(
commitment.lastProposalHash == getProposalHash(lastProposalId),
LastProposalHashMismatch()
);
// ---------------------------------------------------------
// 3. Process bond instruction
// ---------------------------------------------------------
// Bond transfers only apply when whitelist is not enabled.
if (!isWhitelistEnabled) {
_processLivenessBond(commitment, offset);
}
// -----------------------------------------------------------------------------
// 4. Sync checkpoint
// -----------------------------------------------------------------------------
bool checkpointSynced = input.forceCheckpointSync
|| block.timestamp >= state.lastCheckpointTimestamp + _minCheckpointDelay;
if (checkpointSynced) {
_signalService.saveCheckpoint(
ICheckpointStore.Checkpoint({
blockNumber: commitment.endBlockNumber,
stateRoot: commitment.endStateRoot,
blockHash: commitment.transitions[numProposals - 1].blockHash
})
);
state.lastCheckpointTimestamp = uint48(block.timestamp);
}
// ---------------------------------------------------------
// 5. Update core state and emit event
// ---------------------------------------------------------
state.lastFinalizedProposalId = uint48(lastProposalId);
state.lastFinalizedTimestamp = uint48(block.timestamp);
state.lastFinalizedBlockHash = commitment.transitions[numProposals - 1].blockHash;
_coreState = state;
emit Proved(
commitment.firstProposalId,
commitment.firstProposalId + offset,
uint48(lastProposalId),
commitment.actualProver,
checkpointSynced
);
// ---------------------------------------------------------
// 6. Verify the proof
// ---------------------------------------------------------
// For multi-proposal batches (more than 1 unfinalized proposal), pass 0 to verifier.
// Single-proposal proofs pass actual age for age-based verification logic.
_proofVerifier.verifyProof(
numProposals - offset == 1 ? proposalAge : 0,
LibHashOptimized.hashCommitment(commitment),
_proof
);
}
}
/// @inheritdoc IBondManager
function deposit(uint64 _amount) external nonReentrant {
_bondStorage.deposit(_bondToken, msg.sender, msg.sender, _amount, true);
}
/// @inheritdoc IBondManager
function depositTo(address _recipient, uint64 _amount) external nonReentrant {
_bondStorage.deposit(_bondToken, msg.sender, _recipient, _amount, false);
}
/// @inheritdoc IBondManager
function withdraw(address _to, uint64 _amount) external nonReentrant {
_bondStorage.withdraw(_bondToken, msg.sender, _to, _amount, _minBond, _withdrawalDelay);
}
/// @inheritdoc IBondManager
function requestWithdrawal() external nonReentrant {
_bondStorage.requestWithdrawal(msg.sender, _withdrawalDelay);
}
/// @inheritdoc IBondManager
function cancelWithdrawal() external nonReentrant {
_bondStorage.cancelWithdrawal(msg.sender);
}
/// @inheritdoc IForcedInclusionStore
/// @dev This function will revert if called before the first non-activation proposal is
/// submitted to make sure blocks have been produced already and the derivation can use the
/// parent's block timestamp.
function saveForcedInclusion(LibBlobs.BlobReference memory _blobReference) external payable {
bytes32 proposalHash = _proposalHashes[1];
require(proposalHash != bytes32(0), IncorrectProposalCount());
uint256 refund = _forcedInclusionStorage.saveForcedInclusion(
_forcedInclusionFeeInGwei, _forcedInclusionFeeDoubleThreshold, _blobReference
);
// Refund excess payment to the sender
if (refund > 0) {
msg.sender.sendEtherAndVerify(refund);
}
}
/// @inheritdoc ICodec
function encodeProposeInput(IInbox.ProposeInput calldata _input)
external
pure
returns (bytes memory encoded_)
{
return LibCodec.encodeProposeInput(_input);
}
/// @inheritdoc ICodec
function decodeProposeInput(bytes calldata _data)
external
pure
returns (IInbox.ProposeInput memory input_)
{
return LibCodec.decodeProposeInput(_data);
}
/// @inheritdoc ICodec
function encodeProveInput(IInbox.ProveInput calldata _input)
external
pure
returns (bytes memory encoded_)
{
return LibCodec.encodeProveInput(_input);
}
/// @inheritdoc ICodec
function decodeProveInput(bytes calldata _data)
external
pure
returns (IInbox.ProveInput memory input_)
{
return LibCodec.decodeProveInput(_data);
}
/// @inheritdoc ICodec
function hashProposal(IInbox.Proposal calldata _proposal) external pure returns (bytes32) {
return LibHashOptimized.hashProposal(_proposal);
}
/// @inheritdoc ICodec
function hashCommitment(IInbox.Commitment calldata _commitment)
external
pure
returns (bytes32)
{
return LibHashOptimized.hashCommitment(_commitment);
}
// ---------------------------------------------------------------
// External and Public View Functions
// ---------------------------------------------------------------
/// @inheritdoc IBondManager
function getBond(address _address) external view returns (Bond memory bond_) {
return _bondStorage.getBond(_address);
}
/// @inheritdoc IForcedInclusionStore
function getCurrentForcedInclusionFee() external view returns (uint64 feeInGwei_) {
return _forcedInclusionStorage.getCurrentForcedInclusionFee(
_forcedInclusionFeeInGwei, _forcedInclusionFeeDoubleThreshold
);
}
/// @inheritdoc IForcedInclusionStore
function getForcedInclusions(
uint48 _start,
uint48 _maxCount
)
external
view
returns (IForcedInclusionStore.ForcedInclusion[] memory inclusions_)
{
return _forcedInclusionStorage.getForcedInclusions(_start, _maxCount);
}
/// @inheritdoc IForcedInclusionStore
function getForcedInclusionState() external view returns (uint48 head_, uint48 tail_) {
return _forcedInclusionStorage.getForcedInclusionState();
}
/// @inheritdoc IInbox
function getConfig() external view returns (Config memory config_) {
config_ = Config({
proofVerifier: address(_proofVerifier),
proposerChecker: address(_proposerChecker),
proverWhitelist: address(_proverWhitelist),
signalService: address(_signalService),
bondToken: address(_bondToken),
minBond: _minBond,
livenessBond: _livenessBond,
withdrawalDelay: _withdrawalDelay,
provingWindow: _provingWindow,
permissionlessProvingDelay: _permissionlessProvingDelay,
maxProofSubmissionDelay: _maxProofSubmissionDelay,
ringBufferSize: _ringBufferSize,
basefeeSharingPctg: _basefeeSharingPctg,
minForcedInclusionCount: _minForcedInclusionCount,
forcedInclusionDelay: _forcedInclusionDelay,
forcedInclusionFeeInGwei: _forcedInclusionFeeInGwei,
forcedInclusionFeeDoubleThreshold: _forcedInclusionFeeDoubleThreshold,
minCheckpointDelay: _minCheckpointDelay,
permissionlessInclusionMultiplier: _permissionlessInclusionMultiplier
});
}
/// @inheritdoc IInbox
function getCoreState() external view returns (CoreState memory) {
return _coreState;
}
/// @inheritdoc IInbox
/// @dev Note that due to the ring buffer nature of the `_proposalHashes` mapping proposals
/// may have been overwritten by a new one. You should verify that the hash matches the
/// expected proposal.
function getProposalHash(uint256 _proposalId) public view returns (bytes32) {
return _proposalHashes[_proposalId % _ringBufferSize];
}
// ---------------------------------------------------------------
// Private State-Changing Functions
// ---------------------------------------------------------------
/// @dev Builds proposal and derivation data.
/// This function also checks:
/// - If `msg.sender` can propose.
/// - If `msg.sender` has sufficient bond.
/// @param _input The propose input data.
/// @param _lookahead Encoded data forwarded to the proposer checker (i.e. lookahead payloads).
/// @param _nextProposalId The proposal ID to assign.
/// @param _lastProposalBlockId The last block number where a proposal was made.
/// @param _lastFinalizedProposalId The ID of the last finalized proposal.
/// @return proposal_ The proposal with final endOfSubmissionWindowTimestamp set.
function _buildProposal(
ProposeInput memory _input,
bytes calldata _lookahead,
uint48 _nextProposalId,
uint48 _lastProposalBlockId,
uint48 _lastFinalizedProposalId
)
private
returns (Proposal memory proposal_)
{
unchecked {
// Enforce one propose call per Ethereum block to prevent spam attacks that could
// deplete the ring buffer
require(block.number > _lastProposalBlockId, CannotProposeInCurrentBlock());
require(
_ringBufferSize > _nextProposalId - _lastFinalizedProposalId, NotEnoughCapacity()
);
ConsumptionResult memory result =
_consumeForcedInclusions(msg.sender, _input.numForcedInclusions);
result.sources[result.sources.length - 1] =
DerivationSource(false, LibBlobs.validateBlobReference(_input.blobReference));
// If forced inclusion is old enough, allow anyone to propose
// set endOfSubmissionWindowTimestamp = 0, and do not require a bond
// Otherwise, only the current preconfer can propose
uint48 endOfSubmissionWindowTimestamp;
if (!result.allowsPermissionless) {
endOfSubmissionWindowTimestamp =
_proposerChecker.checkProposer(msg.sender, _lookahead);
require(_bondStorage.hasSufficientBond(msg.sender, _minBond), InsufficientBond());
}
// Use previous block as the origin for the proposal to be able to call `blockhash`
uint256 parentBlockNumber = block.number - 1;
proposal_ = Proposal({
id: _nextProposalId,
timestamp: uint48(block.timestamp),
endOfSubmissionWindowTimestamp: endOfSubmissionWindowTimestamp,
proposer: msg.sender,
parentProposalHash: getProposalHash(_nextProposalId - 1),
originBlockNumber: uint48(parentBlockNumber),
originBlockHash: blockhash(parentBlockNumber),
basefeeSharingPctg: _basefeeSharingPctg,
sources: result.sources
});
}
}
/// @dev Stores a proposal hash in the ring buffer
/// Overwrites any existing hash at the calculated buffer slot
function _setProposalHash(uint48 _proposalId, bytes32 _proposalHash) private {
_proposalHashes[_proposalId % _ringBufferSize] = _proposalHash;
}
/// @dev Consumes forced inclusions from the queue and returns result with extra slot for normal
/// source
/// @param _feeRecipient Address to receive accumulated fees
/// @param _numForcedInclusionsRequested Maximum number of forced inclusions to consume
/// @return result_ ConsumptionResult with sources array (size: processed + 1, last slot empty)
/// and whether permissionless proposals are allowed
function _consumeForcedInclusions(
address _feeRecipient,
uint256 _numForcedInclusionsRequested
)
private
returns (ConsumptionResult memory result_)
{
unchecked {
LibForcedInclusion.Storage storage $ = _forcedInclusionStorage;
// Load storage once
(uint48 head, uint48 tail) = ($.head, $.tail);
uint256 available = tail - head;
uint256 toProcess = _numForcedInclusionsRequested > available
? available
: _numForcedInclusionsRequested;
result_.sources = new DerivationSource[](toProcess + 1);
uint48 oldestTimestamp;
(oldestTimestamp, head) = _dequeueAndProcessForcedInclusions(
$, _feeRecipient, result_.sources, head, toProcess
);
// We check the following conditions are met:
// 1. Proposer is willing to include at least the minimum required
// (_minForcedInclusionCount) OR
// 2. Proposer included all available inclusions that are due
if (_numForcedInclusionsRequested < _minForcedInclusionCount && available > toProcess) {
bool isOldestInclusionDue =
$.isOldestForcedInclusionDue(head, tail, _forcedInclusionDelay);
require(!isOldestInclusionDue, UnprocessedForcedInclusionIsDue());
}
uint256 permissionlessTimestamp = uint256(_forcedInclusionDelay)
* _permissionlessInclusionMultiplier + oldestTimestamp;
result_.allowsPermissionless = block.timestamp > permissionlessTimestamp;
}
}
/// @dev Dequeues and processes forced inclusions from the queue without checking if they exist
/// @param $ Storage reference
/// @param _feeRecipient Address to receive fees
/// @param _sources Array to populate with derivation sources
/// @param _head Current queue head position
/// @param _toProcess Number of inclusions to process
/// @return oldestTimestamp_ Oldest timestamp from processed inclusions.
/// `type(uint48).max` if no inclusions were processed
/// @return head_ Updated head position
function _dequeueAndProcessForcedInclusions(
LibForcedInclusion.Storage storage $,
address _feeRecipient,
DerivationSource[] memory _sources,
uint48 _head,
uint256 _toProcess
)
private
returns (uint48 oldestTimestamp_, uint48 head_)
{
unchecked {
if (_toProcess == 0) {
return (type(uint48).max, _head);
}
// Process inclusions and accumulate fees
uint256 totalFees;
for (uint256 i; i < _toProcess; ++i) {
IForcedInclusionStore.ForcedInclusion storage inclusion = $.queue[_head + i];
_sources[i] = IInbox.DerivationSource(true, inclusion.blobSlice);
totalFees += inclusion.feeInGwei;
}
// Transfer accumulated fees
_feeRecipient.sendEtherAndVerify(totalFees * 1 gwei);
// Oldest timestamp is the timestamp of the first inclusion
oldestTimestamp_ = uint48(_sources[0].blobSlice.timestamp);
// Update queue position
head_ = _head + uint48(_toProcess);
// Write to storage once
$.head = head_;
}
}
/// @dev Calculates and processes liveness bond settlement if applicable.
/// @dev Settlement rules:
/// - On-time (within provingWindow + sequential grace): No bond changes.
/// - Late: Liveness bond slash with 50% credited to the actual prover and 50% burned.
/// @param _commitment The commitment data.
/// @param _offset The offset to the first unfinalized proposal.
function _processLivenessBond(Commitment memory _commitment, uint48 _offset) private {
unchecked {
uint256 livenessWindowDeadline = (_commitment.transitions[_offset].timestamp
+ _provingWindow)
.max(_coreState.lastFinalizedTimestamp + _maxProofSubmissionDelay);
// On-time proof - no bond transfer needed.
if (block.timestamp <= livenessWindowDeadline) {
return;
}
_bondStorage.settleLivenessBond(
_commitment.transitions[_offset].proposer, _commitment.actualProver, _livenessBond
);
}
}
/// @dev Emits the Proposed event
function _emitProposedEvent(Proposal memory _proposal) private {
emit Proposed(
_proposal.id,
_proposal.proposer,
_proposal.parentProposalHash,
_proposal.endOfSubmissionWindowTimestamp,
_proposal.basefeeSharingPctg,
_proposal.sources
);
}
// ---------------------------------------------------------------
// Private View/Pure Functions
// ---------------------------------------------------------------
/// @dev Validates propose function inputs.
/// @param _input The ProposeInput to validate
function _validateProposeInput(ProposeInput memory _input) private view {
require(_input.deadline == 0 || block.timestamp <= _input.deadline, DeadlineExceeded());
}
/// @dev Checks if the caller is an authorized prover. When whitelist is enabled, proving
/// becomes permissionless once a proposal is older than the permissionless delay.
/// @param _addr The address of the caller to check.
/// @param _proposalAge The age in seconds since the proposal became available for proving.
/// @return whitelistEnabled_ True if whitelist is enabled (proverCount > 0), false otherwise.
function _checkProver(
address _addr,
uint256 _proposalAge
)
private
view
returns (bool whitelistEnabled_)
{
if (address(_proverWhitelist) == address(0)) return false;
(bool isWhitelisted, uint256 proverCount) = _proverWhitelist.isProverWhitelisted(_addr);
if (proverCount == 0) return false;
if (!isWhitelisted) {
require(_proposalAge > uint256(_permissionlessProvingDelay), ProverNotWhitelisted());
}
return true;
}
/// @dev Validates the batch bounds in the Commitment and calculates the offset
/// to the first unfinalized proposal.
/// @param _state The core state.
/// @param _commitment The commitment data.
/// @return numProposals_ The number of proposals in the batch.
/// @return lastProposalId_ The ID of the last proposal in the batch.
/// @return offset_ The offset to the first unfinalized proposal.
function _validateCommitment(
CoreState memory _state,
Commitment memory _commitment
)
private
pure
returns (uint256 numProposals_, uint256 lastProposalId_, uint48 offset_)
{
unchecked {
uint256 firstUnfinalizedId = _state.lastFinalizedProposalId + 1;
numProposals_ = _commitment.transitions.length;
require(numProposals_ > 0, EmptyBatch());
require(_commitment.firstProposalId <= firstUnfinalizedId, FirstProposalIdTooLarge());
lastProposalId_ = _commitment.firstProposalId + numProposals_ - 1;
require(lastProposalId_ < _state.nextProposalId, LastProposalIdTooLarge());
require(lastProposalId_ >= firstUnfinalizedId, LastProposalAlreadyFinalized());
// Calculate offset to first unfinalized proposal.
// Some proposals in _commitment.transitions[] may already be finalized.
// The offset points to the first proposal that will be finalized.
offset_ = uint48(firstUnfinalizedId - _commitment.firstProposalId);
}
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error ActivationRequired();
error CannotProposeInCurrentBlock();
error CheckpointDelayHasPassed();
error DeadlineExceeded();
error EmptyBatch();
error FirstProposalIdTooLarge();
error IncorrectProposalCount();
error InsufficientBond();
error LastProposalAlreadyFinalized();
error LastProposalHashMismatch();
error LastProposalIdTooLarge();
error NotEnoughCapacity();
error ParentBlockHashMismatch();
error ProverNotWhitelisted();
error UnprocessedForcedInclusionIsDue();
}
node_modules/@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.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.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @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() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @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() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @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 override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @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, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
}
contracts/layer1/core/iface/IProverWhitelist.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title IProverWhitelist
/// @notice Interface for checking if an address is authorized to prove blocks
/// @custom:security-contact security@taiko.xyz
interface IProverWhitelist {
/// @notice Checks if an address is a whitelisted prover
/// @param _prover The address to check
/// @return isWhitelisted_ True if the address is whitelisted, false otherwise
/// @return proverCount_ The total number of whitelisted provers
function isProverWhitelisted(address _prover)
external
view
returns (bool isWhitelisted_, uint256 proverCount_);
}
contracts/shared/libs/LibAddress.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @title LibAddress
/// @dev Provides utilities for address-related operations.
/// @custom:security-contact security@taiko.xyz
library LibAddress {
error ETH_TRANSFER_FAILED();
/// @dev Sends Ether to the specified address. This method will not revert even if sending ether
/// fails.
/// This function is inspired by
/// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
/// @param _to The recipient address.
/// @param _amount The amount of Ether to send in wei.
/// @param _gasLimit The max amount gas to pay for this transaction.
/// @return success_ true if the call is successful, false otherwise.
function sendEther(
address _to,
uint256 _amount,
uint256 _gasLimit,
bytes memory _calldata
)
internal
returns (bool success_)
{
// Check for zero-address transactions
require(_to != address(0), ETH_TRANSFER_FAILED());
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly ("memory-safe") {
success_ := call(
_gasLimit, // gas
_to, // recipient
_amount, // ether value
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
}
}
/// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
/// @param _to The recipient address.
/// @param _amount The amount of Ether to send in wei.
/// @param _gasLimit The max amount gas to pay for this transaction.
function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal {
if (_amount == 0) return;
require(sendEther(_to, _amount, _gasLimit, ""), ETH_TRANSFER_FAILED());
}
/// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
/// @param _to The recipient address.
/// @param _amount The amount of Ether to send in wei.
function sendEtherAndVerify(address _to, uint256 _amount) internal {
sendEtherAndVerify(_to, _amount, gasleft());
}
function supportsInterface(
address _addr,
bytes4 _interfaceId
)
internal
view
returns (bool result_)
{
(bool success, bytes memory data) =
_addr.staticcall(abi.encodeCall(IERC165.supportsInterface, (_interfaceId)));
if (success && data.length == 32) {
result_ = abi.decode(data, (bool));
}
}
}
contracts/layer1/core/libs/LibCodec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { IInbox } from "../iface/IInbox.sol";
import { LibPackUnpack as P } from "./LibPackUnpack.sol";
import { LibTransitionCodec } from "./LibTransitionCodec.sol";
/// @title LibCodec
/// @notice Compact encoder/decoder for Inbox inputs using LibPackUnpack.
/// @custom:security-contact security@taiko.xyz
library LibCodec {
// ---------------------------------------------------------------
// ProposeInputCodec Functions
// ---------------------------------------------------------------
/// @dev Encodes propose input data using compact packing.
function encodeProposeInput(IInbox.ProposeInput memory _input)
internal
pure
returns (bytes memory encoded_)
{
encoded_ = new bytes(14);
uint256 ptr = P.dataPtr(encoded_);
ptr = P.packUint48(ptr, _input.deadline);
ptr = P.packUint16(ptr, _input.blobReference.blobStartIndex);
ptr = P.packUint16(ptr, _input.blobReference.numBlobs);
ptr = P.packUint24(ptr, _input.blobReference.offset);
ptr = P.packUint8(ptr, _input.numForcedInclusions);
}
/// @dev Decodes propose input data using compact packing.
function decodeProposeInput(bytes memory _data)
internal
pure
returns (IInbox.ProposeInput memory input_)
{
uint256 ptr = P.dataPtr(_data);
(input_.deadline, ptr) = P.unpackUint48(ptr);
(input_.blobReference.blobStartIndex, ptr) = P.unpackUint16(ptr);
(input_.blobReference.numBlobs, ptr) = P.unpackUint16(ptr);
(input_.blobReference.offset, ptr) = P.unpackUint24(ptr);
(input_.numForcedInclusions,) = P.unpackUint8(ptr);
}
// ---------------------------------------------------------------
// ProveInputCodec Functions
// ---------------------------------------------------------------
/// @dev Encodes prove input data using compact packing.
function encodeProveInput(IInbox.ProveInput memory _input)
internal
pure
returns (bytes memory encoded_)
{
IInbox.Commitment memory c = _input.commitment;
uint256 bufferSize = _calculateProveInputSize(c.transitions.length);
encoded_ = new bytes(bufferSize);
uint256 ptr = P.dataPtr(encoded_);
ptr = P.packUint48(ptr, c.firstProposalId);
ptr = P.packBytes32(ptr, c.firstProposalParentBlockHash);
ptr = P.packBytes32(ptr, c.lastProposalHash);
ptr = P.packAddress(ptr, c.actualProver);
ptr = P.packUint48(ptr, c.endBlockNumber);
ptr = P.packBytes32(ptr, c.endStateRoot);
P.checkArrayLength(c.transitions.length);
ptr = P.packUint16(ptr, uint16(c.transitions.length));
for (uint256 i; i < c.transitions.length; ++i) {
ptr = LibTransitionCodec.encodeTransition(ptr, c.transitions[i]);
}
// Encode forceCheckpointSync
P.packUint8(ptr, _input.forceCheckpointSync ? 1 : 0);
}
/// @dev Decodes prove input data using compact packing.
function decodeProveInput(bytes memory _data)
internal
pure
returns (IInbox.ProveInput memory input_)
{
uint256 ptr = P.dataPtr(_data);
(input_.commitment.firstProposalId, ptr) = P.unpackUint48(ptr);
(input_.commitment.firstProposalParentBlockHash, ptr) = P.unpackBytes32(ptr);
(input_.commitment.lastProposalHash, ptr) = P.unpackBytes32(ptr);
(input_.commitment.actualProver, ptr) = P.unpackAddress(ptr);
(input_.commitment.endBlockNumber, ptr) = P.unpackUint48(ptr);
(input_.commitment.endStateRoot, ptr) = P.unpackBytes32(ptr);
uint16 transitionsLength;
(transitionsLength, ptr) = P.unpackUint16(ptr);
input_.commitment.transitions = new IInbox.Transition[](transitionsLength);
for (uint256 i; i < transitionsLength; ++i) {
(input_.commitment.transitions[i], ptr) = LibTransitionCodec.decodeTransition(ptr);
}
// Decode forceCheckpointSync
uint8 forceCheckpointSyncByte;
(forceCheckpointSyncByte,) = P.unpackUint8(ptr);
input_.forceCheckpointSync = forceCheckpointSyncByte != 0;
}
// ---------------------------------------------------------------
// Private Functions
// ---------------------------------------------------------------
/// @dev Calculates the size needed for ProveInput encoding.
/// @param _numTransitions Number of transitions in the array.
/// @return size_ Total byte size needed.
function _calculateProveInputSize(uint256 _numTransitions)
private
pure
returns (uint256 size_)
{
unchecked {
// Fixed fields:
// firstProposalId: 6 bytes
// firstProposalParentBlockHash: 32 bytes
// lastProposalHash: 32 bytes
// actualProver: 20 bytes
// endBlockNumber: 6 bytes
// endStateRoot: 32 bytes
// transitions array length: 2 bytes
// forceCheckpointSync: 1 byte
// Total fixed: 131 bytes
size_ = 131 + (_numTransitions * LibTransitionCodec.TRANSITION_SIZE);
}
}
}
contracts/layer1/core/iface/ICodec.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { IInbox } from "./IInbox.sol";
/// @title ICodec
/// @notice Interface for Inbox encoder/decoder and hashing functions
/// @dev Input validation assumptions:
/// - All decode functions may revert on malformed input data
/// - Array inputs should be bounded to prevent excessive gas usage
/// - Struct fields are not validated for business logic constraints
/// - Hash functions assume well-formed input structures
/// @dev Compatibility warning:
/// - Different codec implementations produce INCOMPATIBLE encoded outputs and hashes for the same
/// inputs
/// - Codec implementations cannot be used interchangeably
/// - System upgrades between codec types require careful migration planning
/// @custom:security-contact security@taiko.xyz
interface ICodec {
// ---------------------------------------------------------------
// ProposeInputCodec Functions
// ---------------------------------------------------------------
/// @notice Encodes propose input data
/// @param _input The ProposeInput to encode
/// @return encoded_ The encoded data
function encodeProposeInput(IInbox.ProposeInput calldata _input)
external
pure
returns (bytes memory encoded_);
/// @notice Decodes propose data
/// @param _data The encoded data
/// @return input_ The decoded ProposeInput
/// @dev Reverts on malformed or truncated input data
function decodeProposeInput(bytes calldata _data)
external
pure
returns (IInbox.ProposeInput memory input_);
// ---------------------------------------------------------------
// ProveInputCodec Functions
// ---------------------------------------------------------------
/// @notice Encodes prove input data
/// @param _input The ProveInput to encode
/// @return encoded_ The encoded data
function encodeProveInput(IInbox.ProveInput calldata _input)
external
pure
returns (bytes memory encoded_);
/// @notice Decodes prove input data
/// @param _data The encoded data
/// @return input_ The decoded ProveInput
/// @dev Reverts on malformed or truncated input data
function decodeProveInput(bytes calldata _data)
external
pure
returns (IInbox.ProveInput memory input_);
// ---------------------------------------------------------------
// Hashing Functions
// ---------------------------------------------------------------
/// @notice Hashing for Proposal structs
/// @param _proposal The proposal to hash
/// @return The hash of the proposal
function hashProposal(IInbox.Proposal calldata _proposal) external pure returns (bytes32);
/// @notice Hashing for commitment data
/// @param _commitment The commitment data to hash
/// @return The hash of the commitment
function hashCommitment(IInbox.Commitment calldata _commitment) external pure returns (bytes32);
}
node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @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 {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
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 {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {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 bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
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 {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
contracts/shared/signal/ICheckpointStore.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @title ICheckpointStore
/// @notice Interface for storing and retrieving checkpoints
/// @custom:security-contact security@taiko.xyz
interface ICheckpointStore {
// ---------------------------------------------------------------
// Structs
// ---------------------------------------------------------------
/// @notice Represents a synced checkpoint
struct Checkpoint {
/// @notice The block number associated with the checkpoint.
uint48 blockNumber;
/// @notice The block hash for the referenced block.
bytes32 blockHash;
/// @notice The state root for the referenced block.
bytes32 stateRoot;
}
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
/// @notice Emitted when a checkpoint is saved
/// @param blockNumber The block number
/// @param blockHash The block hash
/// @param stateRoot The state root
event CheckpointSaved(uint48 indexed blockNumber, bytes32 blockHash, bytes32 stateRoot);
// ---------------------------------------------------------------
// External Functions
// ---------------------------------------------------------------
/// @notice Saves a checkpoint
/// @param _checkpoint The checkpoint data to persist
function saveCheckpoint(Checkpoint calldata _checkpoint) external;
/// @notice Gets a checkpoint by its block number
/// @param _blockNumber The block number associated with the checkpoint
/// @return _ The checkpoint
function getCheckpoint(uint48 _blockNumber) external view returns (Checkpoint memory);
}
node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
contracts/layer1/core/libs/LibPackUnpack.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title LibPackUnpack
/// @notice Library providing low-level packing/unpacking functions for compact binary encoding
/// using inline assembly for maximum gas efficiency.
/// @dev This library implements a trust-the-caller pattern with no bounds checking for optimal
/// performance. Callers are responsible for:
/// - Allocating sufficient memory for pack operations
/// - Ensuring data has sufficient length for unpack operations
/// - Tracking position offsets correctly
///
/// Memory Layout:
/// - Pack functions write directly to memory at absolute positions
/// - Unpack functions read from memory at absolute positions
/// - All multi-byte integers use big-endian encoding
/// - Position tracking is left to the caller
///
/// Safety Notes:
/// - No overflow protection on position increments (caller's responsibility)
/// - No bounds checking on memory access (gas-optimized design)
/// - Suitable for controlled environments where input validation happens upstream
///
/// Usage Example:
/// ```solidity
/// bytes memory buffer = new bytes(100);
/// uint256 pos = LibPackUnpack.dataPtr(buffer);
/// pos = LibPackUnpack.packUint32(pos, 12345);
/// pos = LibPackUnpack.packAddress(pos, msg.sender);
/// ```
/// @custom:security-contact security@taiko.xyz
library LibPackUnpack {
// ---------------------------------------------------------------
// Pack Functions (write to buffer with compact encoding)
// ---------------------------------------------------------------
/// @notice Pack uint8 (1 byte) at position
/// @dev Writes a single byte to memory at the specified position.
/// @param _pos Absolute memory position to write at
/// @param _value The uint8 value to pack (0-255)
/// @return newPos_ Updated position after writing (pos + 1)
function packUint8(uint256 _pos, uint8 _value) internal pure returns (uint256 newPos_) {
assembly {
mstore8(_pos, _value)
newPos_ := add(_pos, 1)
}
}
/// @notice Pack uint16 (2 bytes) at position using big-endian encoding
/// @dev Optimized to use mstore instead of 2 individual mstore8 operations.
/// @param _pos Absolute memory position to write at
/// @param _value The uint16 value to pack (0-65535)
/// @return newPos_ Updated position after writing (pos + 2)
function packUint16(uint256 _pos, uint16 _value) internal pure returns (uint256 newPos_) {
assembly {
// Shift value left by 30 bytes (240 bits) to align at the start of a 32-byte word
let shifted := shl(240, _value)
// Store the shifted value at position
mstore(_pos, shifted)
newPos_ := add(_pos, 2)
}
}
/// @notice Pack uint24 (3 bytes) at position using big-endian encoding
/// @dev Optimized to use mstore instead of 3 individual mstore8 operations.
/// @param _pos Absolute memory position to write at
/// @param _value The uint24 value to pack (0-16777215)
/// @return newPos_ Updated position after writing (pos + 3)
function packUint24(uint256 _pos, uint24 _value) internal pure returns (uint256 newPos_) {
assembly {
// Shift value left by 29 bytes (232 bits) to align at the start of a 32-byte word
let shifted := shl(232, _value)
// Store the shifted value at position
mstore(_pos, shifted)
newPos_ := add(_pos, 3)
}
}
/// @notice Pack uint32 (4 bytes) at position using big-endian encoding
/// @dev Optimized to use mstore instead of 4 individual mstore8 operations.
/// @param _pos Absolute memory position to write at
/// @param _value The uint32 value to pack (0-4294967295)
/// @return newPos_ Updated position after writing (pos + 4)
function packUint32(uint256 _pos, uint32 _value) internal pure returns (uint256 newPos_) {
assembly {
// Shift value left by 28 bytes (224 bits) to align at the start of a 32-byte word
let shifted := shl(224, _value)
// Store the shifted value at position
mstore(_pos, shifted)
newPos_ := add(_pos, 4)
}
}
/// @notice Pack uint48 (6 bytes) at position using big-endian encoding
/// @dev Optimized to use mstore instead of 6 individual mstore8 operations.
/// Common use case: block numbers that exceed uint32 range.
/// @param _pos Absolute memory position to write at
/// @param _value The uint48 value to pack (0-281474976710655)
/// @return newPos_ Updated position after writing (pos + 6)
function packUint48(uint256 _pos, uint48 _value) internal pure returns (uint256 newPos_) {
assembly {
// Shift value left by 26 bytes (208 bits) to align at the start of a 32-byte word
let shifted := shl(208, _value)
// Store the shifted value at position
mstore(_pos, shifted)
newPos_ := add(_pos, 6)
}
}
/// @notice Pack uint256 (32 bytes) at position
/// @dev Uses single mstore for efficiency, writes full 32-byte word.
/// @param _pos Absolute memory position to write at (best if 32-byte aligned)
/// @param _value The uint256 value to pack
/// @return newPos_ Updated position after writing (pos + 32)
function packUint256(
uint256 _pos,
uint256 _value
)
internal
pure
returns (uint256 newPos_)
{
assembly {
mstore(_pos, _value)
newPos_ := add(_pos, 32)
}
}
/// @notice Pack bytes32 at position
/// @dev Direct 32-byte write, commonly used for hashes and identifiers.
/// @param _pos Absolute memory position to write at (best if 32-byte aligned)
/// @param _value The bytes32 value to pack (hash, identifier, etc.)
/// @return newPos_ Updated position after writing (pos + 32)
function packBytes32(
uint256 _pos,
bytes32 _value
)
internal
pure
returns (uint256 newPos_)
{
assembly {
mstore(_pos, _value)
newPos_ := add(_pos, 32)
}
}
/// @notice Pack address (20 bytes) at position
/// @dev Optimized to use mstore instead of 20 individual mstore8 operations.
/// Handles alignment by using a single mstore with proper shifting.
/// @param _pos Absolute memory position to write at
/// @param _value The address to pack
/// @return newPos_ Updated position after writing (pos + 20)
function packAddress(
uint256 _pos,
address _value
)
internal
pure
returns (uint256 newPos_)
{
assembly {
// Shift address left by 12 bytes (96 bits) to align it properly in a 32-byte word
// This places the 20-byte address at the start of the word with 12 bytes of padding
let shifted := shl(96, _value)
// Store the shifted address at position
// This writes 32 bytes, but we only care about the first 20
mstore(_pos, shifted)
newPos_ := add(_pos, 20)
}
}
// ---------------------------------------------------------------
// Unpack Functions (read from buffer with compact encoding)
// ---------------------------------------------------------------
/// @notice Unpack uint8 (1 byte) from position
/// @dev Optimized to use shift operation instead of byte operation.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked uint8 value
/// @return newPos_ Updated position after reading (pos + 1)
function unpackUint8(uint256 _pos) internal pure returns (uint8 value_, uint256 newPos_) {
assembly {
// Load full word and shift right by 248 bits (31 bytes) to get the 1 byte we need
value_ := shr(248, mload(_pos))
newPos_ := add(_pos, 1)
}
}
/// @notice Unpack uint16 (2 bytes) from position using big-endian encoding
/// @dev Optimized to use 1 mload operation instead of 2 byte reads.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked uint16 value
/// @return newPos_ Updated position after reading (pos + 2)
function unpackUint16(uint256 _pos) internal pure returns (uint16 value_, uint256 newPos_) {
assembly {
// Load full word and shift right by 240 bits (30 bytes) to get the 2 bytes we need
value_ := shr(240, mload(_pos))
newPos_ := add(_pos, 2)
}
}
/// @notice Unpack uint24 (3 bytes) from position using big-endian encoding
/// @dev Optimized to use 1 mload operation instead of 3 byte reads.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked uint24 value
/// @return newPos_ Updated position after reading (pos + 3)
function unpackUint24(uint256 _pos) internal pure returns (uint24 value_, uint256 newPos_) {
assembly {
// Load full word and shift right by 232 bits (29 bytes) to get the 3 bytes we need
value_ := shr(232, mload(_pos))
newPos_ := add(_pos, 3)
}
}
/// @notice Unpack uint32 (4 bytes) from position using big-endian encoding
/// @dev Optimized to use 1 mload operation instead of 4 byte reads.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked uint32 value
/// @return newPos_ Updated position after reading (pos + 4)
function unpackUint32(uint256 _pos) internal pure returns (uint32 value_, uint256 newPos_) {
assembly {
// Load full word and shift right by 224 bits (28 bytes) to get the 4 bytes we need
value_ := shr(224, mload(_pos))
newPos_ := add(_pos, 4)
}
}
/// @notice Unpack uint48 (6 bytes) from position using big-endian encoding
/// @dev Optimized to use 1 mload operation instead of 6 byte reads.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked uint48 value
/// @return newPos_ Updated position after reading (pos + 6)
function unpackUint48(uint256 _pos) internal pure returns (uint48 value_, uint256 newPos_) {
assembly {
// Load full word and shift right by 208 bits (26 bytes) to get the 6 bytes we need
value_ := shr(208, mload(_pos))
newPos_ := add(_pos, 6)
}
}
/// @notice Unpack uint256 (32 bytes) from position
/// @dev Single mload for efficiency. Reads full 32-byte word.
/// @param _pos Absolute memory position to read from (best if 32-byte aligned)
/// @return value_ The unpacked uint256 value
/// @return newPos_ Updated position after reading (pos + 32)
function unpackUint256(uint256 _pos) internal pure returns (uint256 value_, uint256 newPos_) {
assembly {
value_ := mload(_pos)
newPos_ := add(_pos, 32)
}
}
/// @notice Unpack bytes32 from position
/// @dev Direct 32-byte read for hashes and identifiers.
/// @param _pos Absolute memory position to read from (best if 32-byte aligned)
/// @return value_ The unpacked bytes32 value
/// @return newPos_ Updated position after reading (pos + 32)
function unpackBytes32(uint256 _pos) internal pure returns (bytes32 value_, uint256 newPos_) {
assembly {
value_ := mload(_pos)
newPos_ := add(_pos, 32)
}
}
/// @notice Unpack address (20 bytes) from position
/// @dev Optimized to use only 1 mload operation instead of 20 individual byte reads.
/// Reads one full word and shifts to extract the address bytes.
/// @param _pos Absolute memory position to read from
/// @return value_ The unpacked address
/// @return newPos_ Updated position after reading (pos + 20)
function unpackAddress(uint256 _pos) internal pure returns (address value_, uint256 newPos_) {
assembly {
// Load the full 32-byte word starting at _pos
let word := mload(_pos)
// Shift right by 96 bits (12 bytes) to align the 20-byte address to the right
// This removes the 12 trailing bytes and keeps the first 20 bytes
value_ := shr(96, word)
newPos_ := add(_pos, 20)
}
}
// ---------------------------------------------------------------
// Utility Functions
// ---------------------------------------------------------------
/// @notice Get the memory pointer to the data section of a bytes array
/// @dev Skips the 32-byte length prefix to point at actual data.
/// Essential for converting bytes memory to absolute position for pack/unpack operations.
/// @param _data The bytes array to get data pointer from
/// @return ptr_ The absolute memory pointer to the actual data (data location + 0x20)
function dataPtr(bytes memory _data) internal pure returns (uint256 ptr_) {
assembly {
ptr_ := add(_data, 0x20)
}
}
/// @notice Check that an array length fits within uint16 bounds
/// @dev Reverts if the length exceeds uint16 maximum value (65535).
/// Useful as a validation guard before packing array lengths.
/// @param _length The array length to validate
function checkArrayLength(uint256 _length) internal pure {
require(_length <= type(uint16).max, LengthExceedsUint16());
}
// ---------------------------------------------------------------
// Errors
// ---------------------------------------------------------------
error LengthExceedsUint16();
}
node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @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);
}
node_modules/@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
contracts/shared/common/EssentialContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "./IResolver.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
/// @title EssentialContract
/// @custom:security-contact security@taiko.xyz
abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable {
// ---------------------------------------------------------------
// Constants and Immutable Variables
// ---------------------------------------------------------------
uint8 internal constant _FALSE = 1;
uint8 internal constant _TRUE = 2;
address internal immutable __resolver;
// ---------------------------------------------------------------
// State Variables
// ---------------------------------------------------------------
uint256[50] private __gapFromOldAddressResolver;
/// @dev Slot 1.
uint8 internal __reentry;
uint8 internal __paused;
uint256[49] private __gap;
// ---------------------------------------------------------------
// Events
// ---------------------------------------------------------------
/// @notice Emitted when the contract is paused.
/// @param account The account that paused the contract.
event Paused(address account);
/// @notice Emitted when the contract is unpaused.
/// @param account The account that unpaused the contract.
event Unpaused(address account);
error INVALID_PAUSE_STATUS();
error FUNC_NOT_IMPLEMENTED();
error REENTRANT_CALL();
error ACCESS_DENIED();
error ZERO_ADDRESS();
error ZERO_VALUE();
// ---------------------------------------------------------------
// Modifiers
// ---------------------------------------------------------------
/// @dev Modifier that ensures the caller is either the owner or a specified address.
/// @param _addr The address to check against.
modifier onlyFromOwnerOr(address _addr) {
_checkOwnerOr(_addr);
_;
}
/// @dev Modifier that reverts the function call, indicating it is not implemented.
modifier notImplemented() {
revert FUNC_NOT_IMPLEMENTED();
_;
}
/// @dev Modifier that prevents reentrant calls to a function.
modifier nonReentrant() {
_checkReentrancy();
_storeReentryLock(_TRUE);
_;
_storeReentryLock(_FALSE);
}
/// @dev Modifier that allows function execution only when the contract is paused.
modifier whenPaused() {
_checkPaused();
_;
}
/// @dev Modifier that allows function execution only when the contract is not paused.
modifier whenNotPaused() {
_checkNotPaused();
_;
}
/// @dev Modifier that ensures the provided address is not the zero address.
/// @param _addr The address to check.
modifier nonZeroAddr(address _addr) {
_checkNonZeroAddr(_addr);
_;
}
/// @dev Modifier that ensures the provided value is not zero.
/// @param _value The value to check.
modifier nonZeroValue(uint256 _value) {
_checkNonZeroValue(_value);
_;
}
/// @dev Modifier that ensures the provided bytes32 value is not zero.
/// @param _value The bytes32 value to check.
modifier nonZeroBytes32(bytes32 _value) {
_checkNonZeroBytes32(_value);
_;
}
/// @dev Modifier that ensures the caller is either of the two specified addresses.
/// @param _addr1 The first address to check against.
/// @param _addr2 The second address to check against.
modifier onlyFromEither(address _addr1, address _addr2) {
_checkFromEither(_addr1, _addr2);
_;
}
/// @dev Modifier that ensures the caller is the specified address.
/// @param _addr The address to check against.
modifier onlyFrom(address _addr) {
_checkFrom(_addr);
_;
}
/// @dev Modifier that ensures the caller is the specified address.
/// @param _addr The address to check against.
modifier onlyFromOptional(address _addr) {
_checkFromOptional(_addr);
_;
}
// ---------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------
constructor() {
_disableInitializers();
}
// ---------------------------------------------------------------
// External & Public Functions
// ---------------------------------------------------------------
/// @notice Pauses the contract.
function pause() public whenNotPaused {
_pause();
emit Paused(msg.sender);
// We call the authorize function here to avoid:
// Warning (5740): Unreachable code.
_authorizePause(msg.sender, true);
}
/// @notice Unpauses the contract.
function unpause() public whenPaused {
_unpause();
emit Unpaused(msg.sender);
// We call the authorize function here to avoid:
// Warning (5740): Unreachable code.
_authorizePause(msg.sender, false);
}
function impl() public view returns (address) {
return _getImplementation();
}
/// @notice Returns true if the contract is paused, and false otherwise.
/// @return true if paused, false otherwise.
function paused() public view virtual returns (bool) {
return __paused == _TRUE;
}
function inNonReentrant() public view returns (bool) {
return _loadReentryLock() == _TRUE;
}
/// @notice Returns the address of this contract.
/// @return The address of this contract.
function resolver() public view virtual returns (address) {
return __resolver;
}
// ---------------------------------------------------------------
// Internal Functions
// ---------------------------------------------------------------
/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
function __Essential_init(address _owner) internal virtual onlyInitializing {
__Context_init();
_transferOwnership(_owner == address(0) ? msg.sender : _owner);
__paused = _FALSE;
}
function _pause() internal virtual {
__paused = _TRUE;
}
function _unpause() internal virtual {
__paused = _FALSE;
}
function _authorizeUpgrade(address) internal virtual override onlyOwner { }
function _authorizePause(address, bool) internal virtual onlyOwner { }
// Stores the reentry lock
function _storeReentryLock(uint8 _reentry) internal virtual {
__reentry = _reentry;
}
// Loads the reentry lock
function _loadReentryLock() internal view virtual returns (uint8 reentry_) {
reentry_ = __reentry;
}
// ---------------------------------------------------------------
// Private Functions
// ---------------------------------------------------------------
function _checkOwnerOr(address _addr) private view {
require(msg.sender == owner() || msg.sender == _addr, ACCESS_DENIED());
}
function _checkReentrancy() private view {
require(_loadReentryLock() != _TRUE, REENTRANT_CALL());
}
function _checkPaused() private view {
require(paused(), INVALID_PAUSE_STATUS());
}
function _checkNotPaused() private view {
require(!paused(), INVALID_PAUSE_STATUS());
}
function _checkNonZeroAddr(address _addr) private pure {
require(_addr != address(0), ZERO_ADDRESS());
}
function _checkNonZeroValue(uint256 _value) private pure {
require(_value != 0, ZERO_VALUE());
}
function _checkNonZeroBytes32(bytes32 _value) private pure {
require(_value != 0, ZERO_VALUE());
}
function _checkFromEither(address _addr1, address _addr2) private view {
require(msg.sender == _addr1 || msg.sender == _addr2, ACCESS_DENIED());
}
function _checkFrom(address _addr) private view {
require(msg.sender == _addr, ACCESS_DENIED());
}
function _checkFromOptional(address _addr) private view {
require(_addr == address(0) || msg.sender == _addr, ACCESS_DENIED());
}
}
Compiler Settings
{"viaIR":false,"remappings":["openzeppelin/=node_modules/@openzeppelin/","@openzeppelin/=node_modules/@openzeppelin/","@openzeppelin-upgrades/contracts/=node_modules/@openzeppelin/contracts-upgradeable/","@risc0/contracts/=node_modules/risc0-ethereum/contracts/src/","@solady/=node_modules/solady/","solady/src/=node_modules/solady/src/","solady/utils/=node_modules/solady/src/utils/","@optimism/=node_modules/optimism/","@sp1-contracts/=node_modules/sp1-contracts/contracts/","forge-std/=node_modules/forge-std/","@p256-verifier/contracts/=node_modules/p256-verifier/src/","@eth-fabric/urc/=node_modules/urc/src/","ds-test/=node_modules/ds-test/","src/=contracts/","test/=test/","script/=script/","optimism/=node_modules/optimism/","p256-verifier/=node_modules/p256-verifier/","risc0-ethereum/=node_modules/risc0-ethereum/","sp1-contracts/=node_modules/sp1-contracts/","urc/=node_modules/urc/"],"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"prague"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_proofVerifier","internalType":"address"},{"type":"address","name":"_proposerChecker","internalType":"address"},{"type":"address","name":"_proverWhitelist","internalType":"address"},{"type":"address","name":"_signalService","internalType":"address"},{"type":"address","name":"_bondToken","internalType":"address"},{"type":"uint64","name":"_minBond","internalType":"uint64"},{"type":"uint64","name":"_livenessBond","internalType":"uint64"},{"type":"uint48","name":"_withdrawalDelay","internalType":"uint48"}]},{"type":"error","name":"ACCESS_DENIED","inputs":[]},{"type":"error","name":"ActivationRequired","inputs":[]},{"type":"error","name":"BlobNotFound","inputs":[]},{"type":"error","name":"CannotProposeInCurrentBlock","inputs":[]},{"type":"error","name":"CheckpointDelayHasPassed","inputs":[]},{"type":"error","name":"DeadlineExceeded","inputs":[]},{"type":"error","name":"ETH_TRANSFER_FAILED","inputs":[]},{"type":"error","name":"EmptyBatch","inputs":[]},{"type":"error","name":"FUNC_NOT_IMPLEMENTED","inputs":[]},{"type":"error","name":"FirstProposalIdTooLarge","inputs":[]},{"type":"error","name":"INVALID_PAUSE_STATUS","inputs":[]},{"type":"error","name":"IncorrectProposalCount","inputs":[]},{"type":"error","name":"InsufficientBond","inputs":[]},{"type":"error","name":"InvalidAddress","inputs":[]},{"type":"error","name":"LastProposalAlreadyFinalized","inputs":[]},{"type":"error","name":"LastProposalHashMismatch","inputs":[]},{"type":"error","name":"LastProposalIdTooLarge","inputs":[]},{"type":"error","name":"LengthExceedsUint16","inputs":[]},{"type":"error","name":"MustMaintainMinBond","inputs":[]},{"type":"error","name":"NoBlobs","inputs":[]},{"type":"error","name":"NoBondToWithdraw","inputs":[]},{"type":"error","name":"NoWithdrawalRequested","inputs":[]},{"type":"error","name":"NotEnoughCapacity","inputs":[]},{"type":"error","name":"ParentBlockHashMismatch","inputs":[]},{"type":"error","name":"ProverNotWhitelisted","inputs":[]},{"type":"error","name":"REENTRANT_CALL","inputs":[]},{"type":"error","name":"UnprocessedForcedInclusionIsDue","inputs":[]},{"type":"error","name":"WithdrawalAlreadyRequested","inputs":[]},{"type":"error","name":"ZERO_ADDRESS","inputs":[]},{"type":"error","name":"ZERO_VALUE","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BondDeposited","inputs":[{"type":"address","name":"depositor","internalType":"address","indexed":true},{"type":"address","name":"recipient","internalType":"address","indexed":true},{"type":"uint64","name":"amount","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"BondWithdrawn","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint64","name":"amount","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"ForcedInclusionSaved","inputs":[{"type":"tuple","name":"forcedInclusion","internalType":"struct IForcedInclusionStore.ForcedInclusion","indexed":false,"components":[{"type":"uint64","name":"feeInGwei","internalType":"uint64"},{"type":"tuple","name":"blobSlice","internalType":"struct LibBlobs.BlobSlice","components":[{"type":"bytes32[]","name":"blobHashes","internalType":"bytes32[]"},{"type":"uint24","name":"offset","internalType":"uint24"},{"type":"uint48","name":"timestamp","internalType":"uint48"}]}]}],"anonymous":false},{"type":"event","name":"InboxActivated","inputs":[{"type":"bytes32","name":"lastPacayaBlockHash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"LivenessBondSettled","inputs":[{"type":"address","name":"payer","internalType":"address","indexed":true},{"type":"address","name":"payee","internalType":"address","indexed":true},{"type":"uint64","name":"livenessBond","internalType":"uint64","indexed":false},{"type":"uint64","name":"credited","internalType":"uint64","indexed":false},{"type":"uint64","name":"slashed","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Proposed","inputs":[{"type":"uint48","name":"id","internalType":"uint48","indexed":true},{"type":"address","name":"proposer","internalType":"address","indexed":true},{"type":"bytes32","name":"parentProposalHash","internalType":"bytes32","indexed":false},{"type":"uint48","name":"endOfSubmissionWindowTimestamp","internalType":"uint48","indexed":false},{"type":"uint8","name":"basefeeSharingPctg","internalType":"uint8","indexed":false},{"type":"tuple[]","name":"sources","internalType":"struct IInbox.DerivationSource[]","indexed":false,"components":[{"type":"bool","name":"isForcedInclusion","internalType":"bool"},{"type":"tuple","name":"blobSlice","internalType":"struct LibBlobs.BlobSlice","components":[{"type":"bytes32[]","name":"blobHashes","internalType":"bytes32[]"},{"type":"uint24","name":"offset","internalType":"uint24"},{"type":"uint48","name":"timestamp","internalType":"uint48"}]}]}],"anonymous":false},{"type":"event","name":"Proved","inputs":[{"type":"uint48","name":"firstProposalId","internalType":"uint48","indexed":false},{"type":"uint48","name":"firstNewProposalId","internalType":"uint48","indexed":false},{"type":"uint48","name":"lastProposalId","internalType":"uint48","indexed":false},{"type":"address","name":"actualProver","internalType":"address","indexed":true},{"type":"bool","name":"checkpointSynced","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"WithdrawalCancelled","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"WithdrawalRequested","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint48","name":"withdrawableAt","internalType":"uint48","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activate","inputs":[{"type":"bytes32","name":"_lastPacayaBlockHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint48","name":"","internalType":"uint48"}],"name":"activationTimestamp","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelWithdrawal","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"input_","internalType":"struct IInbox.ProposeInput","components":[{"type":"uint48","name":"deadline","internalType":"uint48"},{"type":"tuple","name":"blobReference","internalType":"struct LibBlobs.BlobReference","components":[{"type":"uint16","name":"blobStartIndex","internalType":"uint16"},{"type":"uint16","name":"numBlobs","internalType":"uint16"},{"type":"uint24","name":"offset","internalType":"uint24"}]},{"type":"uint8","name":"numForcedInclusions","internalType":"uint8"}]}],"name":"decodeProposeInput","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"input_","internalType":"struct IInbox.ProveInput","components":[{"type":"tuple","name":"commitment","internalType":"struct IInbox.Commitment","components":[{"type":"uint48","name":"firstProposalId","internalType":"uint48"},{"type":"bytes32","name":"firstProposalParentBlockHash","internalType":"bytes32"},{"type":"bytes32","name":"lastProposalHash","internalType":"bytes32"},{"type":"address","name":"actualProver","internalType":"address"},{"type":"uint48","name":"endBlockNumber","internalType":"uint48"},{"type":"bytes32","name":"endStateRoot","internalType":"bytes32"},{"type":"tuple[]","name":"transitions","internalType":"struct IInbox.Transition[]","components":[{"type":"address","name":"proposer","internalType":"address"},{"type":"uint48","name":"timestamp","internalType":"uint48"},{"type":"bytes32","name":"blockHash","internalType":"bytes32"}]}]},{"type":"bool","name":"forceCheckpointSync","internalType":"bool"}]}],"name":"decodeProveInput","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deposit","inputs":[{"type":"uint64","name":"_amount","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"depositTo","inputs":[{"type":"address","name":"_recipient","internalType":"address"},{"type":"uint64","name":"_amount","internalType":"uint64"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes","name":"encoded_","internalType":"bytes"}],"name":"encodeProposeInput","inputs":[{"type":"tuple","name":"_input","internalType":"struct IInbox.ProposeInput","components":[{"type":"uint48","name":"deadline","internalType":"uint48"},{"type":"tuple","name":"blobReference","internalType":"struct LibBlobs.BlobReference","components":[{"type":"uint16","name":"blobStartIndex","internalType":"uint16"},{"type":"uint16","name":"numBlobs","internalType":"uint16"},{"type":"uint24","name":"offset","internalType":"uint24"}]},{"type":"uint8","name":"numForcedInclusions","internalType":"uint8"}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes","name":"encoded_","internalType":"bytes"}],"name":"encodeProveInput","inputs":[{"type":"tuple","name":"_input","internalType":"struct IInbox.ProveInput","components":[{"type":"tuple","name":"commitment","internalType":"struct IInbox.Commitment","components":[{"type":"uint48","name":"firstProposalId","internalType":"uint48"},{"type":"bytes32","name":"firstProposalParentBlockHash","internalType":"bytes32"},{"type":"bytes32","name":"lastProposalHash","internalType":"bytes32"},{"type":"address","name":"actualProver","internalType":"address"},{"type":"uint48","name":"endBlockNumber","internalType":"uint48"},{"type":"bytes32","name":"endStateRoot","internalType":"bytes32"},{"type":"tuple[]","name":"transitions","internalType":"struct IInbox.Transition[]","components":[{"type":"address","name":"proposer","internalType":"address"},{"type":"uint48","name":"timestamp","internalType":"uint48"},{"type":"bytes32","name":"blockHash","internalType":"bytes32"}]}]},{"type":"bool","name":"forceCheckpointSync","internalType":"bool"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"bond_","internalType":"struct IBondManager.Bond","components":[{"type":"uint64","name":"balance","internalType":"uint64"},{"type":"uint48","name":"withdrawalRequestedAt","internalType":"uint48"}]}],"name":"getBond","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"config_","internalType":"struct IInbox.Config","components":[{"type":"address","name":"proofVerifier","internalType":"address"},{"type":"address","name":"proposerChecker","internalType":"address"},{"type":"address","name":"proverWhitelist","internalType":"address"},{"type":"address","name":"signalService","internalType":"address"},{"type":"address","name":"bondToken","internalType":"address"},{"type":"uint64","name":"minBond","internalType":"uint64"},{"type":"uint64","name":"livenessBond","internalType":"uint64"},{"type":"uint48","name":"withdrawalDelay","internalType":"uint48"},{"type":"uint48","name":"provingWindow","internalType":"uint48"},{"type":"uint48","name":"permissionlessProvingDelay","internalType":"uint48"},{"type":"uint48","name":"maxProofSubmissionDelay","internalType":"uint48"},{"type":"uint48","name":"ringBufferSize","internalType":"uint48"},{"type":"uint8","name":"basefeeSharingPctg","internalType":"uint8"},{"type":"uint256","name":"minForcedInclusionCount","internalType":"uint256"},{"type":"uint16","name":"forcedInclusionDelay","internalType":"uint16"},{"type":"uint64","name":"forcedInclusionFeeInGwei","internalType":"uint64"},{"type":"uint64","name":"forcedInclusionFeeDoubleThreshold","internalType":"uint64"},{"type":"uint16","name":"minCheckpointDelay","internalType":"uint16"},{"type":"uint8","name":"permissionlessInclusionMultiplier","internalType":"uint8"}]}],"name":"getConfig","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IInbox.CoreState","components":[{"type":"uint48","name":"nextProposalId","internalType":"uint48"},{"type":"uint48","name":"lastProposalBlockId","internalType":"uint48"},{"type":"uint48","name":"lastFinalizedProposalId","internalType":"uint48"},{"type":"uint48","name":"lastFinalizedTimestamp","internalType":"uint48"},{"type":"uint48","name":"lastCheckpointTimestamp","internalType":"uint48"},{"type":"bytes32","name":"lastFinalizedBlockHash","internalType":"bytes32"}]}],"name":"getCoreState","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"feeInGwei_","internalType":"uint64"}],"name":"getCurrentForcedInclusionFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint48","name":"head_","internalType":"uint48"},{"type":"uint48","name":"tail_","internalType":"uint48"}],"name":"getForcedInclusionState","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"inclusions_","internalType":"struct IForcedInclusionStore.ForcedInclusion[]","components":[{"type":"uint64","name":"feeInGwei","internalType":"uint64"},{"type":"tuple","name":"blobSlice","internalType":"struct LibBlobs.BlobSlice","components":[{"type":"bytes32[]","name":"blobHashes","internalType":"bytes32[]"},{"type":"uint24","name":"offset","internalType":"uint24"},{"type":"uint48","name":"timestamp","internalType":"uint48"}]}]}],"name":"getForcedInclusions","inputs":[{"type":"uint48","name":"_start","internalType":"uint48"},{"type":"uint48","name":"_maxCount","internalType":"uint48"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getProposalHash","inputs":[{"type":"uint256","name":"_proposalId","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"hashCommitment","inputs":[{"type":"tuple","name":"_commitment","internalType":"struct IInbox.Commitment","components":[{"type":"uint48","name":"firstProposalId","internalType":"uint48"},{"type":"bytes32","name":"firstProposalParentBlockHash","internalType":"bytes32"},{"type":"bytes32","name":"lastProposalHash","internalType":"bytes32"},{"type":"address","name":"actualProver","internalType":"address"},{"type":"uint48","name":"endBlockNumber","internalType":"uint48"},{"type":"bytes32","name":"endStateRoot","internalType":"bytes32"},{"type":"tuple[]","name":"transitions","internalType":"struct IInbox.Transition[]","components":[{"type":"address","name":"proposer","internalType":"address"},{"type":"uint48","name":"timestamp","internalType":"uint48"},{"type":"bytes32","name":"blockHash","internalType":"bytes32"}]}]}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"hashProposal","inputs":[{"type":"tuple","name":"_proposal","internalType":"struct IInbox.Proposal","components":[{"type":"uint48","name":"id","internalType":"uint48"},{"type":"uint48","name":"timestamp","internalType":"uint48"},{"type":"uint48","name":"endOfSubmissionWindowTimestamp","internalType":"uint48"},{"type":"address","name":"proposer","internalType":"address"},{"type":"bytes32","name":"parentProposalHash","internalType":"bytes32"},{"type":"uint48","name":"originBlockNumber","internalType":"uint48"},{"type":"bytes32","name":"originBlockHash","internalType":"bytes32"},{"type":"uint8","name":"basefeeSharingPctg","internalType":"uint8"},{"type":"tuple[]","name":"sources","internalType":"struct IInbox.DerivationSource[]","components":[{"type":"bool","name":"isForcedInclusion","internalType":"bool"},{"type":"tuple","name":"blobSlice","internalType":"struct LibBlobs.BlobSlice","components":[{"type":"bytes32[]","name":"blobHashes","internalType":"bytes32[]"},{"type":"uint24","name":"offset","internalType":"uint24"},{"type":"uint48","name":"timestamp","internalType":"uint48"}]}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"impl","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"inNonReentrant","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"propose","inputs":[{"type":"bytes","name":"_lookahead","internalType":"bytes"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"prove","inputs":[{"type":"bytes","name":"_data","internalType":"bytes"},{"type":"bytes","name":"_proof","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestWithdrawal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"resolver","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"saveForcedInclusion","inputs":[{"type":"tuple","name":"_blobReference","internalType":"struct LibBlobs.BlobReference","components":[{"type":"uint16","name":"blobStartIndex","internalType":"uint16"},{"type":"uint16","name":"numBlobs","internalType":"uint16"},{"type":"uint24","name":"offset","internalType":"uint24"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint64","name":"_amount","internalType":"uint64"}]}]
Contract Creation Code
0x61032060405230608052348015610014575f5ffd5b50604051615f01380380615f0183398101604081905261003391610351565b60408051610260810182526001600160a01b03808b168252898116602083015288811692820192909252868216606082015290851660808201526001600160401b0380851660a0830152831660c082015265ffffffffffff821660e0820152611c206101008201526201518061012082015260b46101408201526064610160820152604b6101808083019190915260016101a08301525f6101c0830152629896806101e0830152603261020083015261022082015260056102408201526100f8610264565b6040516348ed17ff60e11b815273ada98ce17b449904861791f7402b66b2fa7a7936906391da2ffe9061012f9084906004016103f1565b5f6040518083038186803b158015610145575f5ffd5b505af4158015610157573d5f5f3e3d5ffd5b505082516001600160a01b0390811660c09081526020850151821660e09081526040860151831661010090815260608701518416610120908152608088015190941661014090815260a08801516001600160401b039081166101609081529489015181166101809081529389015165ffffffffffff9081166101a0908152938a015181166101c0908152968a015181166101e0908152928a01518116610200908152958a0151166102209081529389015160ff908116610240908152938a0151610260529589015161ffff908116610280529189015181166102a052938801519093166102c052908601519091166102e0529093015190921661030052506105d998505050505050505050565b5f54610100900460ff16156102cf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161461031e575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b80516001600160a01b0381168114610336575f5ffd5b919050565b80516001600160401b0381168114610336575f5ffd5b5f5f5f5f5f5f5f5f610100898b031215610369575f5ffd5b61037289610320565b975061038060208a01610320565b965061038e60408a01610320565b955061039c60608a01610320565b94506103aa60808a01610320565b93506103b860a08a0161033b565b92506103c660c08a0161033b565b915060e089015165ffffffffffff811681146103e0575f5ffd5b809150509295985092959890939650565b81516001600160a01b031681526102608101602083015161041d60208401826001600160a01b03169052565b50604083015161043860408401826001600160a01b03169052565b50606083015161045360608401826001600160a01b03169052565b50608083015161046e60808401826001600160a01b03169052565b5060a083015161048960a08401826001600160401b03169052565b5060c08301516104a460c08401826001600160401b03169052565b5060e08301516104be60e084018265ffffffffffff169052565b506101008301516104da61010084018265ffffffffffff169052565b506101208301516104f661012084018265ffffffffffff169052565b5061014083015161051261014084018265ffffffffffff169052565b5061016083015161052e61016084018265ffffffffffff169052565b5061018083015161054561018084018260ff169052565b506101a08301516101a08301526101c08301516105696101c084018261ffff169052565b506101e08301516105866101e08401826001600160401b03169052565b506102008301516105a36102008401826001600160401b03169052565b506102208301516105bb61022084018261ffff169052565b506102408301516105d261024084018260ff169052565b5092915050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e0516103005161576461079d5f395f8181610ac7015261378801525f8181610a9d015261199b01525f8181610a6e015281816116a5015261176b01525f8181610a3f01528181611683015261174301525f8181610a150152818161373701526137ac01525f81816109ef01526136fd01525f81816109c60152612a8501525f8181610998015281816114a601528181612557015261288701525f818161096a015261313a01525f818161093c01526130e301525f818161090e015261317b01525f81816108e00152818161159801526115e201525f81816108b1015261322201525f81816108820152818161157701526129c901525f818161085301528181610cb8015281816115530152611d7d01525f818161082401526119da01525f81816107f501528181613009015261305f01525f81816107c6015261294501525f81816107970152611c7001525f61026901525f8181610e4d01528181610e8d01528181610f7f01528181610fbf015261103601526157645ff3fe60806040526004361061021d575f3560e01c80638301d56d1161011e578063d6dad060116100a8578063ea1917431161006d578063ea19174314610b8d578063edbacd4414610bac578063efba83c914610bd8578063f2fde38b14610bf7578063f954ab9214610c16575f5ffd5b8063d6dad06014610afe578063dbaf214514610b1d578063df596d9e14610b31578063e305333514610b44578063e30c397814610b70575f5ffd5b80639791e644116100ee5780639791e64414610659578063a834725a14610678578063afb63ad414610697578063b28e824e146106c3578063c3f909d4146106e2575f5ffd5b80638301d56d146105f55780638456cb59146106145780638abf6077146106285780638da5cb5b1461063c575f5ffd5b80633f4ba83a116101aa5780635c975abb1161016f5780635c975abb146104645780635ccc1718146104845780636aa6a01a146104ba578063715018a6146105cd57806379ba5097146105e1575f5ffd5b80633f4ba83a146103d057806340df9866146103e45780634f1ef2861461041057806352d1902d1461042357806359db6e8514610445575f5ffd5b806319ab453c116101f057806319ab453c1461030d578063226112801461032c5780632f1969b0146103405780633075db561461036c5780633659cfe6146103b1575f5ffd5b80630423c7de1461022157806304f3bcec1461025b5780630d8912f3146102a157806313765838146102ec575b5f5ffd5b34801561022c575f5ffd5b5060fb5461023f9065ffffffffffff1681565b60405165ffffffffffff90911681526020015b60405180910390f35b348015610266575f5ffd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610252565b3480156102ac575f5ffd5b506102c06102bb366004614139565b610c35565b6040805182516001600160401b0316815260209283015165ffffffffffff169281019290925201610252565b3480156102f7575f5ffd5b5061030b610306366004614168565b610c9e565b005b348015610318575f5ffd5b5061030b610327366004614139565b610cee565b348015610337575f5ffd5b5061030b610e00565b34801561034b575f5ffd5b5061035f61035a366004614183565b610e2a565b60405161025291906141ca565b348015610377575f5ffd5b5060027fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5c60ff16145b6040519015158152602001610252565b3480156103bc575f5ffd5b5061030b6103cb366004614139565b610e43565b3480156103db575f5ffd5b5061030b610f07565b3480156103ef575f5ffd5b506104036103fe3660046141fa565b610f60565b604051610252919061429f565b61030b61041e366004614417565b610f75565b34801561042e575f5ffd5b5061043761102a565b604051908152602001610252565b348015610450575f5ffd5b5061030b61045f3660046144bc565b6110db565b34801561046f575f5ffd5b506103a160c954610100900460ff1660021490565b34801561048f575f5ffd5b50610100546040805165ffffffffffff8084168252600160301b909304909216602083015201610252565b3480156104c5575f5ffd5b5061055a6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260fc5465ffffffffffff8082168352600160301b820481166020840152600160601b8204811693830193909352600160901b810483166060830152600160c01b9004909116608082015260fd5460a082015290565b60405161025291905f60c08201905065ffffffffffff835116825265ffffffffffff602084015116602083015265ffffffffffff604084015116604083015265ffffffffffff606084015116606083015265ffffffffffff608084015116608083015260a083015160a083015292915050565b3480156105d8575f5ffd5b5061030b611287565b3480156105ec575f5ffd5b5061030b611298565b348015610600575f5ffd5b5061035f61060f3660046144d3565b61130f565b34801561061f575f5ffd5b5061030b611322565b348015610633575f5ffd5b50610289611377565b348015610647575f5ffd5b506033546001600160a01b0316610289565b348015610664575f5ffd5b5061030b61067336600461454d565b611385565b348015610683575f5ffd5b506104376106923660046144bc565b611496565b3480156106a2575f5ffd5b506106b66106b13660046145b7565b6114e1565b60405161025291906145f5565b3480156106ce575f5ffd5b506104376106dd366004614650565b611527565b3480156106ed575f5ffd5b50610af160408051610260810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e08101829052610200810182905261022081018290526102408101919091526040518061026001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000060ff1681526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000061ffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f000000000000000000000000000000000000000000000000000000000000000061ffff1681526020017f000000000000000000000000000000000000000000000000000000000000000060ff16815250905090565b6040516102529190614687565b348015610b09575f5ffd5b5061030b610b1836600461486f565b611539565b348015610b28575f5ffd5b5061030b6115c7565b61030b610b3f366004614916565b611606565b348015610b4f575f5ffd5b50610b58611725565b6040516001600160401b039091168152602001610252565b348015610b7b575f5ffd5b506065546001600160a01b0316610289565b348015610b98575f5ffd5b5061030b610ba736600461454d565b6117f0565b348015610bb7575f5ffd5b50610bcb610bc63660046145b7565b611d1d565b6040516102529190614994565b348015610be3575f5ffd5b5061030b610bf236600461486f565b611d63565b348015610c02575f5ffd5b5061030b610c11366004614139565b611daf565b348015610c21575f5ffd5b50610437610c30366004614a26565b611e20565b6040805180820182525f80825260208083018290528351808501855282815281018290526001600160a01b03851682526101018152908390208351808501909452546001600160401b0381168452600160401b900465ffffffffffff1690830152905b92915050565b610ca6611e32565b610cb06002611e77565b610ce16101017f00000000000000000000000000000000000000000000000000000000000000003380856001611e80565b610ceb6001611e77565b50565b5f54610100900460ff1615808015610d0c57505f54600160ff909116105b80610d255750303b158015610d2557505f5460ff166001145b610d8d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015610dae575f805461ff0019166101001790555b610db782611f85565b8015610dfc575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610e08611e32565b610e126002611e77565b610e1e61010133611fe3565b610e286001611e77565b565b6060610c98610e3e36849003840184614a75565b612075565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610e8b5760405162461bcd60e51b8152600401610d8490614ac8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610ebd6120ec565b6001600160a01b031614610ee35760405162461bcd60e51b8152600401610d8490614b14565b610eec81612107565b604080515f80825260208201909252610ceb9183919061210f565b610f0f612279565b610f2360c9805461ff001916610100179055565b6040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9060200160405180910390a1610e28335f6122aa565b6060610f6e60ff84846122b2565b9392505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610fbd5760405162461bcd60e51b8152600401610d8490614ac8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610fef6120ec565b6001600160a01b0316146110155760405162461bcd60e51b8152600401610d8490614b14565b61101e82612107565b610dfc8282600161210f565b5f306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110c95760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610d84565b505f5160206156e85f395f51905f5290565b6110e36124f4565b60fb54604051633dd0723360e21b81526004810183905265ffffffffffff90911660248201525f9081908190819073ada98ce17b449904861791f7402b66b2fa7a79369063f741c8cc906044015f60405180830381865af415801561114a573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111719190810190614e0b565b60fb805465ffffffffffff191665ffffffffffff86811691909117909155835160fc805460208701516040880151606089015160808a01519587166bffffffffffffffffffffffff1990941693909317600160301b92871692909202919091176bffffffffffffffffffffffff60601b1916600160601b9186169190910265ffffffffffff60901b191617600160901b918516919091021765ffffffffffff60c01b1916600160c01b929093169190910291909117905560a083015160fd55929650909450925090506112445f8261254e565b61124d82612598565b6040518581527fe4356761c97932c05c3ee0859fb1a5e4f91f7a1d7a3752c7d5a72d5cc6ecb2d29060200160405180910390a15050505050565b61128f6124f4565b610e285f612603565b60655433906001600160a01b031681146113065760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610d84565b610ceb81612603565b6060610c9861131d8361501b565b61261c565b61132a612742565b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200160405180910390a1610e283360016122aa565b5f6113806120ec565b905090565b61138d611e32565b6113976002611e77565b5f6113d683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061277492505050565b90506113e1816127cc565b60fc5465ffffffffffff80821691600160301b8104821691600160601b90910416826114205760405163ba74d80f60e01b815260040160405180910390fd5b5f61142f858a8a878787612808565b60fc80544365ffffffffffff908116600160301b026bffffffffffffffffffffffff1990921660018901919091161717905580519091506114789061147383612abe565b61254e565b61148181612598565b50505050506114906001611e77565b50505050565b5f60fe816114cc65ffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685615084565b81526020019081526020015f20549050919050565b6114e9614080565b610f6e83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061277492505050565b5f610c9861153483615217565b612abe565b611541611e32565b61154b6002611e77565b6115bc6101017f00000000000000000000000000000000000000000000000000000000000000003385857f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612aed565b50610dfc6001611e77565b6115cf611e32565b6115d96002611e77565b610e1e610101337f0000000000000000000000000000000000000000000000000000000000000000612c95565b60015f5260fe6020527f457c8a48b4735f56b938837eb0a8a5f9c55f23c1a85767ce3b65c3e59d3d32b7548061164f5760405163f37a8b1360e01b815260040160405180910390fd5b6040516312b2aa9160e31b81525f90735912bae0b1f53f15c2cba5f9ab3718ddda2a6046906395955488906116cf9060ff907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009089906004016152c9565b602060405180830381865af41580156116ea573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061170e9190615318565b90508015611720576117203382612dd1565b505050565b6040516343c3d71960e01b815260ff60048201526001600160401b037f0000000000000000000000000000000000000000000000000000000000000000811660248301527f00000000000000000000000000000000000000000000000000000000000000001660448201525f90735912bae0b1f53f15c2cba5f9ab3718ddda2a6046906343c3d71990606401602060405180830381865af41580156117cc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611380919061532f565b6040805160c08101825260fc5465ffffffffffff8082168352600160301b82048116602080850191909152600160601b8304821684860152600160901b830482166060850152600160c01b90920416608083015260fd5460a08301528251601f870182900482028101820190935285835290915f91611889919088908890819084018382808284375f92019190915250612ddc92505050565b80519091505f808061189b8685612f35565b9250925092505f8460c001518265ffffffffffff16815181106118c0576118c061534a565b60200260200101516020015165ffffffffffff16420390505f6118e33383613006565b90505f65ffffffffffff841615611926578660c001516001850365ffffffffffff16815181106119155761191561534a565b60200260200101516040015161192c565b86602001515b9050808960a00151146119525760405163198070b360e01b815260040160405180910390fd5b61195b85611496565b87604001511461197e5760405163f904c2fd60e01b815260040160405180910390fd5b8161198d5761198d8785613134565b5f8860200151806119d057507f000000000000000000000000000000000000000000000000000000000000000061ffff168a608001510165ffffffffffff164210155b90508015611ad2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c9a0b8c860405180606001604052808b6080015165ffffffffffff1681526020018b60c0015160018c0381518110611a3d57611a3d61534a565b60200260200101516040015181526020018b60a001518152506040518263ffffffff1660e01b8152600401611a969190815165ffffffffffff168152602080830151908201526040918201519181019190915260600190565b5f604051808303815f87803b158015611aad575f5ffd5b505af1158015611abf573d5f5f3e3d5ffd5b50505065ffffffffffff421660808c0152505b65ffffffffffff80871660408c0152421660608b015260c088015180515f198901908110611b0257611b0261534a565b6020026020010151604001518a60a00181815250508960fc5f820151815f015f6101000a81548165ffffffffffff021916908365ffffffffffff1602179055506020820151815f0160066101000a81548165ffffffffffff021916908365ffffffffffff1602179055506040820151815f01600c6101000a81548165ffffffffffff021916908365ffffffffffff1602179055506060820151815f0160126101000a81548165ffffffffffff021916908365ffffffffffff1602179055506080820151815f0160186101000a81548165ffffffffffff021916908365ffffffffffff16021790555060a0820151816001015590505087606001516001600160a01b03167f7ca0f1e30099488c4ee24e86a6b2c6802e9add6d530919af7aa17db3bcc1cff1895f0151878b5f0151018985604051611c66949392919065ffffffffffff9485168152928416602084015292166040820152901515606082015260800190565b60405180910390a27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166314bcf3dd8665ffffffffffff168903600114611cb5575f611cb7565b855b611cc08b613246565b8f8f6040518563ffffffff1660e01b8152600401611ce19493929190615386565b5f6040518083038186803b158015611cf7575f5ffd5b505afa158015611d09573d5f5f3e3d5ffd5b505050505050505050505050505050505050565b611d256140b7565b610f6e83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ddc92505050565b611d6b611e32565b611d756002611e77565b611da56101017f00000000000000000000000000000000000000000000000000000000000000003385855f611e80565b610dfc6001611e77565b611db76124f4565b606580546001600160a01b0383166001600160a01b03199091168117909155611de86033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f610c98611e2d836153a5565b613246565b60027fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5c60ff1603610e285760405163dfc60d8560e01b815260040160405180910390fd5b610ceb81613385565b6001600160a01b038316611ea75760405163e6c4247b60e01b815260040160405180910390fd5b611eb28684846133ab565b808015611ee457506001600160a01b0383165f90815260208790526040902054600160401b900465ffffffffffff1615155b15611f11576001600160a01b0383165f908152602087905260409020805465ffffffffffff60401b191690555b611f318430611f1f856133f9565b6001600160a01b038916929190613411565b6040516001600160401b03831681526001600160a01b0380851691908616907fe5e95641fa87bdfef3ce0d39f0c9a37c200f3bf59f53623b3de21e03ed33e3d29060200160405180910390a3505050505050565b5f54610100900460ff16611fab5760405162461bcd60e51b8152600401610d84906153b0565b611fb361347c565b611fd16001600160a01b03821615611fcb5781612603565b33612603565b5060c9805461ff001916610100179055565b6001600160a01b0381165f90815260208390526040812080549091600160401b90910465ffffffffffff16900361202d576040516387bdc6a960e01b815260040160405180910390fd5b805465ffffffffffff60401b191681556040516001600160a01b038316907fc51fdb96728de385ec7859819e3997bc618362ef0dbca0ad051d856866cda3db905f90a2505050565b60408051600e8082528183019092526060916020820181803683375050835160d01b60208084019190915284810180515160f090811b602686015281519092015190911b60288401525160409081015160e81b602a84015284015191925050602d8201906120e49082906134a2565b905050919050565b5f5160206156e85f395f51905f52546001600160a01b031690565b610ceb6124f4565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561214257611720836134ae565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561219c575060408051601f3d908101601f1916820190925261219991810190615318565b60015b6121ff5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d84565b5f5160206156e85f395f51905f52811461226d5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d84565b50611720838383613549565b61228d60c954610100900460ff1660021490565b610e285760405163bae6e2a960e01b815260040160405180910390fd5b610dfc6124f4565b600183015460609065ffffffffffff80821691600160301b900481169085168211806122ee57508065ffffffffffff168565ffffffffffff1610155b806122ff575065ffffffffffff8416155b1561236857604080515f808252602082019092529061235e565b61234b6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b8152602001906001900390816123195790505b5092505050610f6e565b5f61238065ffffffffffff878403811690871661356d565b9050806001600160401b0381111561239a5761239a614322565b6040519080825280602002602001820160405280156123fd57816020015b6123ea6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b8152602001906001900390816123b85790505b5093505f5b818110156124e95765ffffffffffff871681015f90815260208981526040918290208251808401845281546001600160401b031681528351600183018054608081870284018101909752606083018181529396949587019492939192849291849184018282801561249057602002820191905f5260205f20905b81548152602001906001019080831161247c575b50505091835250506001919091015462ffffff811660208301526301000000900465ffffffffffff1660409091015290525085518690839081106124d6576124d661534a565b6020908102919091010152600101612402565b505050509392505050565b6033546001600160a01b03163314610e285760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610d84565b8060fe5f61257c7f0000000000000000000000000000000000000000000000000000000000000000866153fb565b65ffffffffffff16815260208101919091526040015f20555050565b80606001516001600160a01b0316815f015165ffffffffffff167f7c4c4523e17533e451df15762a093e0693a2cd8b279fe54c6cd3777ed5771213836080015184604001518560e001518661010001516040516125f89493929190615499565b60405180910390a350565b606580546001600160a01b0319169055610ceb81613581565b805160c08101515160609190603a02608301806001600160401b0381111561264657612646614322565b6040519080825280601f01601f191660200182016040528015612670576020820181803683370190505b50825160d090811b602083810191909152840151602683015260408401516046830152606080850151901b606683015260808085015190911b607a83015260a0808501519183019190915260c0840151519194508401906126d0906135d2565b60c08301515160f01b81526002015f5b8360c001515181101561271e57612714828560c0015183815181106127075761270761534a565b60200260200101516135f5565b91506001016126e0565b50612739818660200151612732575f6134a2565b60016134a2565b50505050919050565b61275660c954610100900460ff1660021490565b15610e285760405163bae6e2a960e01b815260040160405180910390fd5b61277c614080565b60208281015160d01c82526026830151828201805160f092831c905260288501518151921c9190920152602a830151905160e89190911c604091820152602d9092015160f81c9181019190915290565b805165ffffffffffff1615806127eb5750805165ffffffffffff164211155b610ceb5760405163559895a360e01b815260040160405180910390fd5b60408051610120810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201929092526101008101919091528265ffffffffffff16431161287a576040516349517a1d60e11b815260040160405180910390fd5b81840365ffffffffffff167f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff16116128cc5760405163eaabac9b60e01b815260040160405180910390fd5b5f6128de33896040015160ff1661361e565b905060405180604001604052805f151581526020016129008a602001516137e4565b9052815180515f1981019081106129195761291961534a565b60200260200101819052505f8160200151612a0a57604051635600026d60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ac0004da9061297e9033908c908c906004016154c8565b6020604051808303815f875af115801561299a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129be91906154ec565b90506129ed610101337f0000000000000000000000000000000000000000000000000000000000000000613925565b612a0a5760405163e92c469f60e01b815260040160405180910390fd5b5f6001430390506040518061012001604052808865ffffffffffff1681526020014265ffffffffffff1681526020018365ffffffffffff168152602001336001600160a01b03168152602001612a6a60018a0365ffffffffffff16611496565b815265ffffffffffff831660208201529140604083015260ff7f0000000000000000000000000000000000000000000000000000000000000000166060830152925160809091015250979650505050505050565b5f81604051602001612ad09190615507565b604051602081830303815290604052805190602001209050919050565b5f6001600160a01b038516612b155760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0386165f908152602089905260408120805490916001600160401b039182169187168210612b4a5786612b4c565b815b8354909150600160401b900465ffffffffffff161580612b8e57508254612b83908690600160401b900465ffffffffffff166155d7565b65ffffffffffff1642105b15612bcf576001600160401b038616612ba782846155f5565b6001600160401b03161015612bcf576040516321f68cc160e21b815260040160405180910390fd5b612bda8b8a83613970565b9350816001600160401b0316846001600160401b0316148015612c0c57508254600160401b900465ffffffffffff1615155b15612c2257825465ffffffffffff60401b191683555b612c4088612c2f866133f9565b6001600160a01b038d1691906139f9565b6040516001600160401b03851681526001600160a01b038a16907f3362c96009316515fccd3dd29c7036c305ad9e892d83dd5681845ac9edb0c9a89060200160405180910390a2505050979650505050505050565b6001600160a01b0382165f908152602084815260408083208151808301909252546001600160401b038116808352600160401b90910465ffffffffffff16928201929092529103612cf957604051634555262b60e01b815260040160405180910390fd5b602081015165ffffffffffff1615612d245760405163fb52063b60e01b815260040160405180910390fd5b65ffffffffffff4281811660208085019182526001600160a01b0387165f8181529189905260409091208551815493518616600160401b026dffffffffffffffffffffffffffff199094166001600160401b039091161792909217909155917f3bbe41cfdd142e0f9b2224dac18c6efd2a6966e35a9ec23ab57ce63a60b3360491612db191861690615614565b60405165ffffffffffff909116815260200160405180910390a250505050565b610dfc82825a613a29565b612de46140b7565b602082810151825160d091821c90526026840151835190920191909152604683015182516040015260668301518251606091821c910152607a8301518251911c608091820152820151815160a09081019190915282015160a283019060f01c806001600160401b03811115612e5b57612e5b614322565b604051908082528060200260200182016040528015612ea457816020015b604080516060810182525f80825260208083018290529282015282525f19909201910181612e795790505b50835160c001525f5b8161ffff16811015612f235760408051606080820183525f80835260208301818152938301908152865190911c8252601486015160d01c909252601a850151909152603a8401855160c00151805184908110612f0b57612f0b61534a565b60209081029190910101919091529250600101612ead565b50505160f81c15156020820152919050565b604082015160c082015151905f90819060010165ffffffffffff1683612f6e5760405163c2e5347d60e01b815260040160405180910390fd5b845165ffffffffffff16811015612f98576040516363db3a4160e01b815260040160405180910390fd5b845186515f1965ffffffffffff9283168701019450168310612fcd5760405163677c56f160e01b815260040160405180910390fd5b80831015612fee5760405163181432e760e11b815260040160405180910390fd5b845f015165ffffffffffff1681039150509250925092565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661303c57505f610c98565b604051633326844b60e11b81526001600160a01b0384811660048301525f9182917f0000000000000000000000000000000000000000000000000000000000000000169063664d0896906024016040805180830381865afa1580156130a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130c79190615627565b91509150805f036130dc575f92505050610c98565b81613129577f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1684116131295760405163c1a58f1960e01b815260040160405180910390fd5b506001949350505050565b5f6131db7f000000000000000000000000000000000000000000000000000000000000000060fc5f0160129054906101000a900465ffffffffffff160165ffffffffffff167f00000000000000000000000000000000000000000000000000000000000000008560c001518565ffffffffffff16815181106131b8576131b861534a565b6020026020010151602001510165ffffffffffff16613a6c90919063ffffffff16565b90508042116131e957505050565b6117208360c001518365ffffffffffff168151811061320a5761320a61534a565b602090810291909101015151606085015161010191907f0000000000000000000000000000000000000000000000000000000000000000613a81565b60c081015180515f919060096003820201836132728260408051828152600190920160051b8201905290565b6020808201529050855165ffffffffffff166040820152602086015160608201526040860151608082015260608601516001600160a01b031660a0820152608086015165ffffffffffff1660c082015260a086015160e082015260e0610100820152610120810183905260095f5b84811015613353575f8682815181106132fb576132fb61534a565b602090810291909101015180516001600160a01b03166001850160051b8601529050602081015165ffffffffffff166002840160051b85015260408101516003840160051b85015250600391909101906001016132e0565b50815160051b602083012061337a8380516040516001820160051b83011490151060061b52565b979650505050505050565b807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5d50565b6001600160a01b0382165f90815260208490526040902080546133d89083906001600160401b0316615653565b815467ffffffffffffffff19166001600160401b0391909116179055505050565b5f610c98633b9aca006001600160401b038416615672565b6040516001600160a01b03808516602483015283166044820152606481018290526114909085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613b3e565b5f54610100900460ff16610e285760405162461bcd60e51b8152600401610d84906153b0565b5f818353505060010190565b6001600160a01b0381163b61351b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d84565b5f5160206156e85f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b61355283613c11565b5f8251118061355e5750805b15611720576114908383613c50565b5f81831161357b5782610f6e565b50919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61ffff811115610ceb5760405163161e7a6b60e11b815260040160405180910390fd5b805160601b8252602081015160d01b60148301526040810151601a8301908152603a8301610f6e565b60408051808201909152606081525f60208201526101005460ff9065ffffffffffff80821691600160301b9004811690828203165f8187116136605786613662565b815b9050806001016001600160401b0381111561367f5761367f614322565b6040519080825280602002602001820160405280156136e257816020015b6136cf6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b81526020019060019003908161369d5790505b508087525f906136f79087908b908886613c75565b955090507f00000000000000000000000000000000000000000000000000000000000000008810801561372957508183115b1561377e575f61375b8787877f0000000000000000000000000000000000000000000000000000000000000000613df3565b9050801561377c5760405163014b3fdb60e11b815260040160405180910390fd5b505b65ffffffffffff167f000000000000000000000000000000000000000000000000000000000000000060ff167f000000000000000000000000000000000000000000000000000000000000000061ffff1602014211602087015250939695505050505050565b604080516060808201835281525f6020808301829052928201529082015161ffff166138235760405163fdac229f60e01b815260040160405180910390fd5b5f826020015161ffff166001600160401b0381111561384457613844614322565b60405190808252806020026020018201604052801561386d578160200160208202803683370190505b5090505f5b836020015161ffff168110156138f557835161389390829061ffff16615614565b498282815181106138a6576138a661534a565b6020026020010181815250508181815181106138c4576138c461534a565b60200260200101515f5f1b036138ed57604051637bb2fa2f60e11b815260040160405180910390fd5b600101613872565b50604080516060810182529182529283015162ffffff16602082015265ffffffffffff4216928101929092525090565b6001600160a01b0382165f90815260208490526040812080546001600160401b0380851691161080159061396757508054600160401b900465ffffffffffff16155b95945050505050565b6001600160a01b0382165f90815260208490526040812080546001600160401b038085169116116139bb57805467ffffffffffffffff19811682556001600160401b031691506139f1565b80548392506139d49083906001600160401b03166155f5565b815467ffffffffffffffff19166001600160401b03919091161781555b509392505050565b6040516001600160a01b03831660248201526044810182905261172090849063a9059cbb60e01b90606401613445565b815f03613a3557505050565b613a4f83838360405180602001604052805f815250613e5c565b61172057604051634c67134d60e11b815260040160405180910390fd5b5f818311613a7a5781610f6e565b5090919050565b5f613a8d858584613970565b9050806001600160401b03165f03613aa55750611490565b5f613ab1600283615689565b90505f613abe82846155f5565b90506001600160401b03821615613ada57613ada8786846133ab565b604080516001600160401b038681168252848116602083015283168183015290516001600160a01b0387811692908916917faa22f5157944b5fa6846460e159d57ea9c3878e71fda274af372fa2ccf285aa09181900360600190a350505050505050565b5f613b92826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e999092919063ffffffff16565b905080515f1480613bb2575080806020019051810190613bb291906156b6565b6117205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d84565b613c1a816134ae565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610f6e838360405180606001604052806027815260200161570860279139613ea7565b5f5f825f03613c8e575065ffffffffffff905082613de9565b5f5f5b84811015613d7e5765ffffffffffff861681015f90815260208a815260409182902082518084018452600180825284519083018054608081870284018101909752606083018181529496939586019492939192849290918491840182828015613d1757602002820191905f5260205f20905b815481526020019060010190808311613d03575b50505091835250506001919091015462ffffff811660208301526301000000900465ffffffffffff1660409091015290528851899084908110613d5c57613d5c61534a565b6020908102919091010152546001600160401b03169190910190600101613c91565b50613d986001600160a01b038816633b9aca008302612dd1565b855f81518110613daa57613daa61534a565b602002602001015160200151604001519250838501915081886001015f6101000a81548165ffffffffffff021916908365ffffffffffff160217905550505b9550959350505050565b5f8265ffffffffffff168465ffffffffffff1603613e1257505f613e54565b65ffffffffffff8085165f908152602087905260408120600201546301000000900490911690819003613e48575f915050613e54565b61ffff83160142101590505b949350505050565b5f6001600160a01b038516613e8457604051634c67134d60e11b815260040160405180910390fd5b5f5f835160208501878988f195945050505050565b6060613e5484845f85613f1b565b60605f5f856001600160a01b031685604051613ec391906156d1565b5f60405180830381855af49150503d805f8114613efb576040519150601f19603f3d011682016040523d82523d5f602084013e613f00565b606091505b5091509150613f1186838387613fe3565b9695505050505050565b606082471015613f7c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d84565b5f5f866001600160a01b03168587604051613f9791906156d1565b5f6040518083038185875af1925050503d805f8114613fd1576040519150601f19603f3d011682016040523d82523d5f602084013e613fd6565b606091505b509150915061337a878383875b606083156140515782515f0361404a576001600160a01b0385163b61404a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d84565b5081613e54565b613e5483838151156140665781518083602001fd5b8060405162461bcd60e51b8152600401610d8491906141ca565b60408051606080820183525f8083528351918201845280825260208281018290529382015290918201905b81525f60209091015290565b60405180604001604052806140ab6040518060e001604052805f65ffffffffffff1681526020015f81526020015f81526020015f6001600160a01b031681526020015f65ffffffffffff1681526020015f8152602001606081525090565b6001600160a01b0381168114610ceb575f5ffd5b803561413481614115565b919050565b5f60208284031215614149575f5ffd5b8135610f6e81614115565b6001600160401b0381168114610ceb575f5ffd5b5f60208284031215614178575f5ffd5b8135610f6e81614154565b5f60a0828403128015614194575f5ffd5b509092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610f6e602083018461419c565b65ffffffffffff81168114610ceb575f5ffd5b8035614134816141dc565b5f5f6040838503121561420b575f5ffd5b8235614216816141dc565b91506020830135614226816141dc565b809150509250929050565b8051606080845281519084018190525f9160200190829060808601905b80831015614271578351825260208201915060208401935060018301925061424e565b5062ffffff602086015116602087015265ffffffffffff604086015116604087015280935050505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561431657603f1987860301845281516001600160401b03815116865260208101519050604060208701526143006040870182614231565b95505060209384019391909101906001016142c5565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051606081016001600160401b038111828210171561435857614358614322565b60405290565b604080519081016001600160401b038111828210171561435857614358614322565b60405161012081016001600160401b038111828210171561435857614358614322565b60405160c081016001600160401b038111828210171561435857614358614322565b60405160e081016001600160401b038111828210171561435857614358614322565b604051601f8201601f191681016001600160401b038111828210171561440f5761440f614322565b604052919050565b5f5f60408385031215614428575f5ffd5b823561443381614115565b915060208301356001600160401b0381111561444d575f5ffd5b8301601f8101851361445d575f5ffd5b80356001600160401b0381111561447657614476614322565b614489601f8201601f19166020016143e7565b81815286602083850101111561449d575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f602082840312156144cc575f5ffd5b5035919050565b5f602082840312156144e3575f5ffd5b81356001600160401b038111156144f8575f5ffd5b820160408185031215610f6e575f5ffd5b5f5f83601f840112614519575f5ffd5b5081356001600160401b0381111561452f575f5ffd5b602083019150836020828501011115614546575f5ffd5b9250929050565b5f5f5f5f60408587031215614560575f5ffd5b84356001600160401b03811115614575575f5ffd5b61458187828801614509565b90955093505060208501356001600160401b0381111561459f575f5ffd5b6145ab87828801614509565b95989497509550505050565b5f5f602083850312156145c8575f5ffd5b82356001600160401b038111156145dd575f5ffd5b6145e985828601614509565b90969095509350505050565b815165ffffffffffff16815260208083015160a083019161463c9084018261ffff815116825261ffff602082015116602083015262ffffff60408201511660408301525050565b5060ff604084015116608083015292915050565b5f60208284031215614660575f5ffd5b81356001600160401b03811115614675575f5ffd5b82016101208185031215610f6e575f5ffd5b81516001600160a01b03168152610260810160208301516146b360208401826001600160a01b03169052565b5060408301516146ce60408401826001600160a01b03169052565b5060608301516146e960608401826001600160a01b03169052565b50608083015161470460808401826001600160a01b03169052565b5060a083015161471f60a08401826001600160401b03169052565b5060c083015161473a60c08401826001600160401b03169052565b5060e083015161475460e084018265ffffffffffff169052565b5061010083015161477061010084018265ffffffffffff169052565b5061012083015161478c61012084018265ffffffffffff169052565b506101408301516147a861014084018265ffffffffffff169052565b506101608301516147c461016084018265ffffffffffff169052565b506101808301516147db61018084018260ff169052565b506101a08301516101a08301526101c08301516147ff6101c084018261ffff169052565b506101e083015161481c6101e08401826001600160401b03169052565b506102008301516148396102008401826001600160401b03169052565b5061022083015161485161022084018261ffff169052565b5061024083015161486861024084018260ff169052565b5092915050565b5f5f60408385031215614880575f5ffd5b823561488b81614115565b9150602083013561422681614154565b803561ffff81168114614134575f5ffd5b62ffffff81168114610ceb575f5ffd5b8035614134816148ac565b5f606082840312156148d7575f5ffd5b6148df614336565b90506148ea8261489b565b81526148f86020830161489b565b6020820152604082013561490b816148ac565b604082015292915050565b5f60608284031215614926575f5ffd5b610f6e83836148c7565b5f8151808452602084019350602083015f5b8281101561498a57815180516001600160a01b0316875260208082015165ffffffffffff16818901526040918201519188019190915260609096019590910190600101614942565b5093949350505050565b602081525f82516040602084015265ffffffffffff815116606084015260208101516080840152604081015160a084015260018060a01b0360608201511660c084015265ffffffffffff60808201511660e084015260a081015161010084015260c0810151905060e0610120840152614a11610140840182614930565b905060208401516139f1604085018215159052565b5f60208284031215614a36575f5ffd5b81356001600160401b03811115614a4b575f5ffd5b820160e08185031215610f6e575f5ffd5b60ff81168114610ceb575f5ffd5b803561413481614a5c565b5f60a0828403128015614a86575f5ffd5b50614a8f614336565b8235614a9a816141dc565b8152614aa984602085016148c7565b60208201526080830135614abc81614a5c565b60408201529392505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b8051614134816141dc565b805161413481614115565b805161413481614a5c565b5f6001600160401b03821115614b9957614b99614322565b5060051b60200190565b8015158114610ceb575f5ffd5b8051614134816148ac565b5f82601f830112614bca575f5ffd5b8151614bdd614bd882614b81565b6143e7565b8082825260208201915060208360051b860101925085831115614bfe575f5ffd5b602085015b83811015614d405780516001600160401b03811115614c20575f5ffd5b86016040818903601f19011215614c35575f5ffd5b614c3d61435e565b6020820151614c4b81614ba3565b815260408201516001600160401b03811115614c65575f5ffd5b6020818401019250506060828a031215614c7d575f5ffd5b614c85614336565b82516001600160401b03811115614c9a575f5ffd5b8301601f81018b13614caa575f5ffd5b8051614cb8614bd882614b81565b8082825260208201915060208360051b85010192508d831115614cd9575f5ffd5b6020840193505b82841015614cfb578351825260209384019390910190614ce0565b845250614d0d91505060208401614bb0565b6020820152614d1e60408401614b60565b6040820152806020830152508085525050602083019250602081019050614c03565b5095945050505050565b5f6101208284031215614d5b575f5ffd5b614d63614380565b9050614d6e82614b60565b8152614d7c60208301614b60565b6020820152614d8d60408301614b60565b6040820152614d9e60608301614b6b565b606082015260808281015190820152614db960a08301614b60565b60a082015260c08281015190820152614dd460e08301614b76565b60e08201526101008201516001600160401b03811115614df2575f5ffd5b614dfe84828501614bbb565b6101008301525092915050565b5f5f5f5f848603610120811215614e20575f5ffd5b8551614e2b816141dc565b945060c0601f1982011215614e3e575f5ffd5b50614e476143a3565b6020860151614e55816141dc565b81526040860151614e65816141dc565b60208201526060860151614e78816141dc565b60408201526080860151614e8b816141dc565b606082015260a0860151614e9e816141dc565b608082015260c086015160a082015260e08601519093506001600160401b03811115614ec8575f5ffd5b614ed487828801614d4a565b61010096909601519497939650505050565b5f82601f830112614ef5575f5ffd5b8135614f03614bd882614b81565b80828252602082019150602060608402860101925085831115614f24575f5ffd5b602085015b83811015614d405760608188031215614f40575f5ffd5b614f48614336565b8135614f5381614115565b81526020820135614f63816141dc565b602082810191909152604083810135908301529084529290920191606001614f29565b5f60e08284031215614f96575f5ffd5b614f9e6143c5565b9050614fa9826141ef565b81526020828101359082015260408083013590820152614fcb60608301614129565b6060820152614fdc608083016141ef565b608082015260a0828101359082015260c08201356001600160401b03811115615003575f5ffd5b61500f84828501614ee6565b60c08301525092915050565b5f6040823603121561502b575f5ffd5b61503361435e565b82356001600160401b03811115615048575f5ffd5b61505436828601614f86565b825250602083013561506581614ba3565b602082015292915050565b634e487b7160e01b5f52601260045260245ffd5b5f8261509257615092615070565b500690565b5f82601f8301126150a6575f5ffd5b81356150b4614bd882614b81565b8082825260208201915060208360051b8601019250858311156150d5575f5ffd5b602085015b83811015614d405780356001600160401b038111156150f7575f5ffd5b86016040818903601f1901121561510c575f5ffd5b61511461435e565b602082013561512281614ba3565b815260408201356001600160401b0381111561513c575f5ffd5b6020818401019250506060828a031215615154575f5ffd5b61515c614336565b82356001600160401b03811115615171575f5ffd5b8301601f81018b13615181575f5ffd5b803561518f614bd882614b81565b8082825260208201915060208360051b85010192508d8311156151b0575f5ffd5b6020840193505b828410156151d25783358252602093840193909101906151b7565b8452506151e4915050602084016148bc565b60208201526151f5604084016141ef565b60408201528060208301525080855250506020830192506020810190506150da565b5f6101208236031215615228575f5ffd5b615230614380565b615239836141ef565b8152615247602084016141ef565b6020820152615258604084016141ef565b604082015261526960608401614129565b60608201526080838101359082015261528460a084016141ef565b60a082015260c0838101359082015261529f60e08401614a6a565b60e08201526101008301356001600160401b038111156152bd575f5ffd5b614dfe36828601615097565b8481526001600160401b0384811660208301528316604082015260c08101613967606083018461ffff815116825261ffff602082015116602083015262ffffff60408201511660408301525050565b5f60208284031215615328575f5ffd5b5051919050565b5f6020828403121561533f575f5ffd5b8151610f6e81614154565b634e487b7160e01b5f52603260045260245ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201525f613f1160608301848661535e565b5f610c983683614f86565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f65ffffffffffff83168061541257615412615070565b8065ffffffffffff84160691505092915050565b5f82825180855260208501945060208160051b830101602085015f5b8381101561548d57601f19858403018852815180511515845260208101519050604060208501526154766040850182614231565b6020998a0199909450929092019150600101615442565b50909695505050505050565b84815265ffffffffffff8416602082015260ff83166040820152608060608201525f613f116080830184615426565b6001600160a01b03841681526040602082018190525f90613967908301848661535e565b5f602082840312156154fc575f5ffd5b8151610f6e816141dc565b6020815261552060208201835165ffffffffffff169052565b5f602083015161553a604084018265ffffffffffff169052565b50604083015165ffffffffffff811660608401525060608301516001600160a01b038116608084015250608083015160a083015260a083015161558760c084018265ffffffffffff169052565b5060c083015160e083015260e08301516155a761010084018260ff169052565b5061010083015161012080840152613e54610140840182615426565b634e487b7160e01b5f52601160045260245ffd5b65ffffffffffff8181168382160190811115610c9857610c986155c3565b6001600160401b038281168282160390811115610c9857610c986155c3565b80820180821115610c9857610c986155c3565b5f5f60408385031215615638575f5ffd5b825161564381614ba3565b6020939093015192949293505050565b6001600160401b038181168382160190811115610c9857610c986155c3565b8082028115828204841417610c9857610c986155c3565b5f6001600160401b038316806156a1576156a1615070565b806001600160401b0384160491505092915050565b5f602082840312156156c6575f5ffd5b8151610f6e81614ba3565b5f82518060208501845e5f92019182525091905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220528534fe7195b2d7ae117d69a1bf4b3ca9026c4dcf967e9bd391ad01e0bfe22664736f6c634300081e0033000000000000000000000000121b61af720bf2f147893d4b27a6ac93709373e8000000000000000000000000cfb57e95cbab87bfd167b3eddd5c11e2d1613b2200000000000000000000000053789e39e3310737e8c8ced483032aac25b39ded000000000000000000000000cbf1639b8809adff74bd59ec292e436107852cc9000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c58000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x60806040526004361061021d575f3560e01c80638301d56d1161011e578063d6dad060116100a8578063ea1917431161006d578063ea19174314610b8d578063edbacd4414610bac578063efba83c914610bd8578063f2fde38b14610bf7578063f954ab9214610c16575f5ffd5b8063d6dad06014610afe578063dbaf214514610b1d578063df596d9e14610b31578063e305333514610b44578063e30c397814610b70575f5ffd5b80639791e644116100ee5780639791e64414610659578063a834725a14610678578063afb63ad414610697578063b28e824e146106c3578063c3f909d4146106e2575f5ffd5b80638301d56d146105f55780638456cb59146106145780638abf6077146106285780638da5cb5b1461063c575f5ffd5b80633f4ba83a116101aa5780635c975abb1161016f5780635c975abb146104645780635ccc1718146104845780636aa6a01a146104ba578063715018a6146105cd57806379ba5097146105e1575f5ffd5b80633f4ba83a146103d057806340df9866146103e45780634f1ef2861461041057806352d1902d1461042357806359db6e8514610445575f5ffd5b806319ab453c116101f057806319ab453c1461030d578063226112801461032c5780632f1969b0146103405780633075db561461036c5780633659cfe6146103b1575f5ffd5b80630423c7de1461022157806304f3bcec1461025b5780630d8912f3146102a157806313765838146102ec575b5f5ffd5b34801561022c575f5ffd5b5060fb5461023f9065ffffffffffff1681565b60405165ffffffffffff90911681526020015b60405180910390f35b348015610266575f5ffd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610252565b3480156102ac575f5ffd5b506102c06102bb366004614139565b610c35565b6040805182516001600160401b0316815260209283015165ffffffffffff169281019290925201610252565b3480156102f7575f5ffd5b5061030b610306366004614168565b610c9e565b005b348015610318575f5ffd5b5061030b610327366004614139565b610cee565b348015610337575f5ffd5b5061030b610e00565b34801561034b575f5ffd5b5061035f61035a366004614183565b610e2a565b60405161025291906141ca565b348015610377575f5ffd5b5060027fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5c60ff16145b6040519015158152602001610252565b3480156103bc575f5ffd5b5061030b6103cb366004614139565b610e43565b3480156103db575f5ffd5b5061030b610f07565b3480156103ef575f5ffd5b506104036103fe3660046141fa565b610f60565b604051610252919061429f565b61030b61041e366004614417565b610f75565b34801561042e575f5ffd5b5061043761102a565b604051908152602001610252565b348015610450575f5ffd5b5061030b61045f3660046144bc565b6110db565b34801561046f575f5ffd5b506103a160c954610100900460ff1660021490565b34801561048f575f5ffd5b50610100546040805165ffffffffffff8084168252600160301b909304909216602083015201610252565b3480156104c5575f5ffd5b5061055a6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260fc5465ffffffffffff8082168352600160301b820481166020840152600160601b8204811693830193909352600160901b810483166060830152600160c01b9004909116608082015260fd5460a082015290565b60405161025291905f60c08201905065ffffffffffff835116825265ffffffffffff602084015116602083015265ffffffffffff604084015116604083015265ffffffffffff606084015116606083015265ffffffffffff608084015116608083015260a083015160a083015292915050565b3480156105d8575f5ffd5b5061030b611287565b3480156105ec575f5ffd5b5061030b611298565b348015610600575f5ffd5b5061035f61060f3660046144d3565b61130f565b34801561061f575f5ffd5b5061030b611322565b348015610633575f5ffd5b50610289611377565b348015610647575f5ffd5b506033546001600160a01b0316610289565b348015610664575f5ffd5b5061030b61067336600461454d565b611385565b348015610683575f5ffd5b506104376106923660046144bc565b611496565b3480156106a2575f5ffd5b506106b66106b13660046145b7565b6114e1565b60405161025291906145f5565b3480156106ce575f5ffd5b506104376106dd366004614650565b611527565b3480156106ed575f5ffd5b50610af160408051610260810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e08101829052610200810182905261022081018290526102408101919091526040518061026001604052807f000000000000000000000000121b61af720bf2f147893d4b27a6ac93709373e86001600160a01b031681526020017f000000000000000000000000cfb57e95cbab87bfd167b3eddd5c11e2d1613b226001600160a01b031681526020017f00000000000000000000000053789e39e3310737e8c8ced483032aac25b39ded6001600160a01b031681526020017f000000000000000000000000cbf1639b8809adff74bd59ec292e436107852cc96001600160a01b031681526020017f000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c586001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160401b031681526020017f000000000000000000000000000000000000000000000000000000000000000065ffffffffffff1681526020017f0000000000000000000000000000000000000000000000000000000000001c2065ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000001518065ffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000b465ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000006465ffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000004b60ff1681526020017f000000000000000000000000000000000000000000000000000000000000000181526020017f000000000000000000000000000000000000000000000000000000000000000061ffff1681526020017f00000000000000000000000000000000000000000000000000000000009896806001600160401b031681526020017f00000000000000000000000000000000000000000000000000000000000000326001600160401b031681526020017f000000000000000000000000000000000000000000000000000000000000018061ffff1681526020017f000000000000000000000000000000000000000000000000000000000000000560ff16815250905090565b6040516102529190614687565b348015610b09575f5ffd5b5061030b610b1836600461486f565b611539565b348015610b28575f5ffd5b5061030b6115c7565b61030b610b3f366004614916565b611606565b348015610b4f575f5ffd5b50610b58611725565b6040516001600160401b039091168152602001610252565b348015610b7b575f5ffd5b506065546001600160a01b0316610289565b348015610b98575f5ffd5b5061030b610ba736600461454d565b6117f0565b348015610bb7575f5ffd5b50610bcb610bc63660046145b7565b611d1d565b6040516102529190614994565b348015610be3575f5ffd5b5061030b610bf236600461486f565b611d63565b348015610c02575f5ffd5b5061030b610c11366004614139565b611daf565b348015610c21575f5ffd5b50610437610c30366004614a26565b611e20565b6040805180820182525f80825260208083018290528351808501855282815281018290526001600160a01b03851682526101018152908390208351808501909452546001600160401b0381168452600160401b900465ffffffffffff1690830152905b92915050565b610ca6611e32565b610cb06002611e77565b610ce16101017f000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c583380856001611e80565b610ceb6001611e77565b50565b5f54610100900460ff1615808015610d0c57505f54600160ff909116105b80610d255750303b158015610d2557505f5460ff166001145b610d8d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015610dae575f805461ff0019166101001790555b610db782611f85565b8015610dfc575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610e08611e32565b610e126002611e77565b610e1e61010133611fe3565b610e286001611e77565b565b6060610c98610e3e36849003840184614a75565b612075565b6001600160a01b037f000000000000000000000000d251b61ccff0e6632757e619bc4f3eddbf621d5b163003610e8b5760405162461bcd60e51b8152600401610d8490614ac8565b7f000000000000000000000000d251b61ccff0e6632757e619bc4f3eddbf621d5b6001600160a01b0316610ebd6120ec565b6001600160a01b031614610ee35760405162461bcd60e51b8152600401610d8490614b14565b610eec81612107565b604080515f80825260208201909252610ceb9183919061210f565b610f0f612279565b610f2360c9805461ff001916610100179055565b6040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9060200160405180910390a1610e28335f6122aa565b6060610f6e60ff84846122b2565b9392505050565b6001600160a01b037f000000000000000000000000d251b61ccff0e6632757e619bc4f3eddbf621d5b163003610fbd5760405162461bcd60e51b8152600401610d8490614ac8565b7f000000000000000000000000d251b61ccff0e6632757e619bc4f3eddbf621d5b6001600160a01b0316610fef6120ec565b6001600160a01b0316146110155760405162461bcd60e51b8152600401610d8490614b14565b61101e82612107565b610dfc8282600161210f565b5f306001600160a01b037f000000000000000000000000d251b61ccff0e6632757e619bc4f3eddbf621d5b16146110c95760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610d84565b505f5160206156e85f395f51905f5290565b6110e36124f4565b60fb54604051633dd0723360e21b81526004810183905265ffffffffffff90911660248201525f9081908190819073ada98ce17b449904861791f7402b66b2fa7a79369063f741c8cc906044015f60405180830381865af415801561114a573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111719190810190614e0b565b60fb805465ffffffffffff191665ffffffffffff86811691909117909155835160fc805460208701516040880151606089015160808a01519587166bffffffffffffffffffffffff1990941693909317600160301b92871692909202919091176bffffffffffffffffffffffff60601b1916600160601b9186169190910265ffffffffffff60901b191617600160901b918516919091021765ffffffffffff60c01b1916600160c01b929093169190910291909117905560a083015160fd55929650909450925090506112445f8261254e565b61124d82612598565b6040518581527fe4356761c97932c05c3ee0859fb1a5e4f91f7a1d7a3752c7d5a72d5cc6ecb2d29060200160405180910390a15050505050565b61128f6124f4565b610e285f612603565b60655433906001600160a01b031681146113065760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610d84565b610ceb81612603565b6060610c9861131d8361501b565b61261c565b61132a612742565b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200160405180910390a1610e283360016122aa565b5f6113806120ec565b905090565b61138d611e32565b6113976002611e77565b5f6113d683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061277492505050565b90506113e1816127cc565b60fc5465ffffffffffff80821691600160301b8104821691600160601b90910416826114205760405163ba74d80f60e01b815260040160405180910390fd5b5f61142f858a8a878787612808565b60fc80544365ffffffffffff908116600160301b026bffffffffffffffffffffffff1990921660018901919091161717905580519091506114789061147383612abe565b61254e565b61148181612598565b50505050506114906001611e77565b50505050565b5f60fe816114cc65ffffffffffff7f00000000000000000000000000000000000000000000000000000000000000641685615084565b81526020019081526020015f20549050919050565b6114e9614080565b610f6e83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061277492505050565b5f610c9861153483615217565b612abe565b611541611e32565b61154b6002611e77565b6115bc6101017f000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c583385857f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612aed565b50610dfc6001611e77565b6115cf611e32565b6115d96002611e77565b610e1e610101337f0000000000000000000000000000000000000000000000000000000000000000612c95565b60015f5260fe6020527f457c8a48b4735f56b938837eb0a8a5f9c55f23c1a85767ce3b65c3e59d3d32b7548061164f5760405163f37a8b1360e01b815260040160405180910390fd5b6040516312b2aa9160e31b81525f90735912bae0b1f53f15c2cba5f9ab3718ddda2a6046906395955488906116cf9060ff907f0000000000000000000000000000000000000000000000000000000000989680907f00000000000000000000000000000000000000000000000000000000000000329089906004016152c9565b602060405180830381865af41580156116ea573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061170e9190615318565b90508015611720576117203382612dd1565b505050565b6040516343c3d71960e01b815260ff60048201526001600160401b037f0000000000000000000000000000000000000000000000000000000000989680811660248301527f00000000000000000000000000000000000000000000000000000000000000321660448201525f90735912bae0b1f53f15c2cba5f9ab3718ddda2a6046906343c3d71990606401602060405180830381865af41580156117cc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611380919061532f565b6040805160c08101825260fc5465ffffffffffff8082168352600160301b82048116602080850191909152600160601b8304821684860152600160901b830482166060850152600160c01b90920416608083015260fd5460a08301528251601f870182900482028101820190935285835290915f91611889919088908890819084018382808284375f92019190915250612ddc92505050565b80519091505f808061189b8685612f35565b9250925092505f8460c001518265ffffffffffff16815181106118c0576118c061534a565b60200260200101516020015165ffffffffffff16420390505f6118e33383613006565b90505f65ffffffffffff841615611926578660c001516001850365ffffffffffff16815181106119155761191561534a565b60200260200101516040015161192c565b86602001515b9050808960a00151146119525760405163198070b360e01b815260040160405180910390fd5b61195b85611496565b87604001511461197e5760405163f904c2fd60e01b815260040160405180910390fd5b8161198d5761198d8785613134565b5f8860200151806119d057507f000000000000000000000000000000000000000000000000000000000000018061ffff168a608001510165ffffffffffff164210155b90508015611ad2577f000000000000000000000000cbf1639b8809adff74bd59ec292e436107852cc96001600160a01b031663c9a0b8c860405180606001604052808b6080015165ffffffffffff1681526020018b60c0015160018c0381518110611a3d57611a3d61534a565b60200260200101516040015181526020018b60a001518152506040518263ffffffff1660e01b8152600401611a969190815165ffffffffffff168152602080830151908201526040918201519181019190915260600190565b5f604051808303815f87803b158015611aad575f5ffd5b505af1158015611abf573d5f5f3e3d5ffd5b50505065ffffffffffff421660808c0152505b65ffffffffffff80871660408c0152421660608b015260c088015180515f198901908110611b0257611b0261534a565b6020026020010151604001518a60a00181815250508960fc5f820151815f015f6101000a81548165ffffffffffff021916908365ffffffffffff1602179055506020820151815f0160066101000a81548165ffffffffffff021916908365ffffffffffff1602179055506040820151815f01600c6101000a81548165ffffffffffff021916908365ffffffffffff1602179055506060820151815f0160126101000a81548165ffffffffffff021916908365ffffffffffff1602179055506080820151815f0160186101000a81548165ffffffffffff021916908365ffffffffffff16021790555060a0820151816001015590505087606001516001600160a01b03167f7ca0f1e30099488c4ee24e86a6b2c6802e9add6d530919af7aa17db3bcc1cff1895f0151878b5f0151018985604051611c66949392919065ffffffffffff9485168152928416602084015292166040820152901515606082015260800190565b60405180910390a27f000000000000000000000000121b61af720bf2f147893d4b27a6ac93709373e86001600160a01b03166314bcf3dd8665ffffffffffff168903600114611cb5575f611cb7565b855b611cc08b613246565b8f8f6040518563ffffffff1660e01b8152600401611ce19493929190615386565b5f6040518083038186803b158015611cf7575f5ffd5b505afa158015611d09573d5f5f3e3d5ffd5b505050505050505050505050505050505050565b611d256140b7565b610f6e83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ddc92505050565b611d6b611e32565b611d756002611e77565b611da56101017f000000000000000000000000a20182131658295f37c1a1efdbdc89eff97d9c583385855f611e80565b610dfc6001611e77565b611db76124f4565b606580546001600160a01b0383166001600160a01b03199091168117909155611de86033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f610c98611e2d836153a5565b613246565b60027fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5c60ff1603610e285760405163dfc60d8560e01b815260040160405180910390fd5b610ceb81613385565b6001600160a01b038316611ea75760405163e6c4247b60e01b815260040160405180910390fd5b611eb28684846133ab565b808015611ee457506001600160a01b0383165f90815260208790526040902054600160401b900465ffffffffffff1615155b15611f11576001600160a01b0383165f908152602087905260409020805465ffffffffffff60401b191690555b611f318430611f1f856133f9565b6001600160a01b038916929190613411565b6040516001600160401b03831681526001600160a01b0380851691908616907fe5e95641fa87bdfef3ce0d39f0c9a37c200f3bf59f53623b3de21e03ed33e3d29060200160405180910390a3505050505050565b5f54610100900460ff16611fab5760405162461bcd60e51b8152600401610d84906153b0565b611fb361347c565b611fd16001600160a01b03821615611fcb5781612603565b33612603565b5060c9805461ff001916610100179055565b6001600160a01b0381165f90815260208390526040812080549091600160401b90910465ffffffffffff16900361202d576040516387bdc6a960e01b815260040160405180910390fd5b805465ffffffffffff60401b191681556040516001600160a01b038316907fc51fdb96728de385ec7859819e3997bc618362ef0dbca0ad051d856866cda3db905f90a2505050565b60408051600e8082528183019092526060916020820181803683375050835160d01b60208084019190915284810180515160f090811b602686015281519092015190911b60288401525160409081015160e81b602a84015284015191925050602d8201906120e49082906134a2565b905050919050565b5f5160206156e85f395f51905f52546001600160a01b031690565b610ceb6124f4565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561214257611720836134ae565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561219c575060408051601f3d908101601f1916820190925261219991810190615318565b60015b6121ff5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d84565b5f5160206156e85f395f51905f52811461226d5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d84565b50611720838383613549565b61228d60c954610100900460ff1660021490565b610e285760405163bae6e2a960e01b815260040160405180910390fd5b610dfc6124f4565b600183015460609065ffffffffffff80821691600160301b900481169085168211806122ee57508065ffffffffffff168565ffffffffffff1610155b806122ff575065ffffffffffff8416155b1561236857604080515f808252602082019092529061235e565b61234b6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b8152602001906001900390816123195790505b5092505050610f6e565b5f61238065ffffffffffff878403811690871661356d565b9050806001600160401b0381111561239a5761239a614322565b6040519080825280602002602001820160405280156123fd57816020015b6123ea6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b8152602001906001900390816123b85790505b5093505f5b818110156124e95765ffffffffffff871681015f90815260208981526040918290208251808401845281546001600160401b031681528351600183018054608081870284018101909752606083018181529396949587019492939192849291849184018282801561249057602002820191905f5260205f20905b81548152602001906001019080831161247c575b50505091835250506001919091015462ffffff811660208301526301000000900465ffffffffffff1660409091015290525085518690839081106124d6576124d661534a565b6020908102919091010152600101612402565b505050509392505050565b6033546001600160a01b03163314610e285760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610d84565b8060fe5f61257c7f0000000000000000000000000000000000000000000000000000000000000064866153fb565b65ffffffffffff16815260208101919091526040015f20555050565b80606001516001600160a01b0316815f015165ffffffffffff167f7c4c4523e17533e451df15762a093e0693a2cd8b279fe54c6cd3777ed5771213836080015184604001518560e001518661010001516040516125f89493929190615499565b60405180910390a350565b606580546001600160a01b0319169055610ceb81613581565b805160c08101515160609190603a02608301806001600160401b0381111561264657612646614322565b6040519080825280601f01601f191660200182016040528015612670576020820181803683370190505b50825160d090811b602083810191909152840151602683015260408401516046830152606080850151901b606683015260808085015190911b607a83015260a0808501519183019190915260c0840151519194508401906126d0906135d2565b60c08301515160f01b81526002015f5b8360c001515181101561271e57612714828560c0015183815181106127075761270761534a565b60200260200101516135f5565b91506001016126e0565b50612739818660200151612732575f6134a2565b60016134a2565b50505050919050565b61275660c954610100900460ff1660021490565b15610e285760405163bae6e2a960e01b815260040160405180910390fd5b61277c614080565b60208281015160d01c82526026830151828201805160f092831c905260288501518151921c9190920152602a830151905160e89190911c604091820152602d9092015160f81c9181019190915290565b805165ffffffffffff1615806127eb5750805165ffffffffffff164211155b610ceb5760405163559895a360e01b815260040160405180910390fd5b60408051610120810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201929092526101008101919091528265ffffffffffff16431161287a576040516349517a1d60e11b815260040160405180910390fd5b81840365ffffffffffff167f000000000000000000000000000000000000000000000000000000000000006465ffffffffffff16116128cc5760405163eaabac9b60e01b815260040160405180910390fd5b5f6128de33896040015160ff1661361e565b905060405180604001604052805f151581526020016129008a602001516137e4565b9052815180515f1981019081106129195761291961534a565b60200260200101819052505f8160200151612a0a57604051635600026d60e11b81526001600160a01b037f000000000000000000000000cfb57e95cbab87bfd167b3eddd5c11e2d1613b22169063ac0004da9061297e9033908c908c906004016154c8565b6020604051808303815f875af115801561299a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129be91906154ec565b90506129ed610101337f0000000000000000000000000000000000000000000000000000000000000000613925565b612a0a5760405163e92c469f60e01b815260040160405180910390fd5b5f6001430390506040518061012001604052808865ffffffffffff1681526020014265ffffffffffff1681526020018365ffffffffffff168152602001336001600160a01b03168152602001612a6a60018a0365ffffffffffff16611496565b815265ffffffffffff831660208201529140604083015260ff7f000000000000000000000000000000000000000000000000000000000000004b166060830152925160809091015250979650505050505050565b5f81604051602001612ad09190615507565b604051602081830303815290604052805190602001209050919050565b5f6001600160a01b038516612b155760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0386165f908152602089905260408120805490916001600160401b039182169187168210612b4a5786612b4c565b815b8354909150600160401b900465ffffffffffff161580612b8e57508254612b83908690600160401b900465ffffffffffff166155d7565b65ffffffffffff1642105b15612bcf576001600160401b038616612ba782846155f5565b6001600160401b03161015612bcf576040516321f68cc160e21b815260040160405180910390fd5b612bda8b8a83613970565b9350816001600160401b0316846001600160401b0316148015612c0c57508254600160401b900465ffffffffffff1615155b15612c2257825465ffffffffffff60401b191683555b612c4088612c2f866133f9565b6001600160a01b038d1691906139f9565b6040516001600160401b03851681526001600160a01b038a16907f3362c96009316515fccd3dd29c7036c305ad9e892d83dd5681845ac9edb0c9a89060200160405180910390a2505050979650505050505050565b6001600160a01b0382165f908152602084815260408083208151808301909252546001600160401b038116808352600160401b90910465ffffffffffff16928201929092529103612cf957604051634555262b60e01b815260040160405180910390fd5b602081015165ffffffffffff1615612d245760405163fb52063b60e01b815260040160405180910390fd5b65ffffffffffff4281811660208085019182526001600160a01b0387165f8181529189905260409091208551815493518616600160401b026dffffffffffffffffffffffffffff199094166001600160401b039091161792909217909155917f3bbe41cfdd142e0f9b2224dac18c6efd2a6966e35a9ec23ab57ce63a60b3360491612db191861690615614565b60405165ffffffffffff909116815260200160405180910390a250505050565b610dfc82825a613a29565b612de46140b7565b602082810151825160d091821c90526026840151835190920191909152604683015182516040015260668301518251606091821c910152607a8301518251911c608091820152820151815160a09081019190915282015160a283019060f01c806001600160401b03811115612e5b57612e5b614322565b604051908082528060200260200182016040528015612ea457816020015b604080516060810182525f80825260208083018290529282015282525f19909201910181612e795790505b50835160c001525f5b8161ffff16811015612f235760408051606080820183525f80835260208301818152938301908152865190911c8252601486015160d01c909252601a850151909152603a8401855160c00151805184908110612f0b57612f0b61534a565b60209081029190910101919091529250600101612ead565b50505160f81c15156020820152919050565b604082015160c082015151905f90819060010165ffffffffffff1683612f6e5760405163c2e5347d60e01b815260040160405180910390fd5b845165ffffffffffff16811015612f98576040516363db3a4160e01b815260040160405180910390fd5b845186515f1965ffffffffffff9283168701019450168310612fcd5760405163677c56f160e01b815260040160405180910390fd5b80831015612fee5760405163181432e760e11b815260040160405180910390fd5b845f015165ffffffffffff1681039150509250925092565b5f7f00000000000000000000000053789e39e3310737e8c8ced483032aac25b39ded6001600160a01b031661303c57505f610c98565b604051633326844b60e11b81526001600160a01b0384811660048301525f9182917f00000000000000000000000053789e39e3310737e8c8ced483032aac25b39ded169063664d0896906024016040805180830381865afa1580156130a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130c79190615627565b91509150805f036130dc575f92505050610c98565b81613129577f000000000000000000000000000000000000000000000000000000000001518065ffffffffffff1684116131295760405163c1a58f1960e01b815260040160405180910390fd5b506001949350505050565b5f6131db7f00000000000000000000000000000000000000000000000000000000000000b460fc5f0160129054906101000a900465ffffffffffff160165ffffffffffff167f0000000000000000000000000000000000000000000000000000000000001c208560c001518565ffffffffffff16815181106131b8576131b861534a565b6020026020010151602001510165ffffffffffff16613a6c90919063ffffffff16565b90508042116131e957505050565b6117208360c001518365ffffffffffff168151811061320a5761320a61534a565b602090810291909101015151606085015161010191907f0000000000000000000000000000000000000000000000000000000000000000613a81565b60c081015180515f919060096003820201836132728260408051828152600190920160051b8201905290565b6020808201529050855165ffffffffffff166040820152602086015160608201526040860151608082015260608601516001600160a01b031660a0820152608086015165ffffffffffff1660c082015260a086015160e082015260e0610100820152610120810183905260095f5b84811015613353575f8682815181106132fb576132fb61534a565b602090810291909101015180516001600160a01b03166001850160051b8601529050602081015165ffffffffffff166002840160051b85015260408101516003840160051b85015250600391909101906001016132e0565b50815160051b602083012061337a8380516040516001820160051b83011490151060061b52565b979650505050505050565b807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b5d50565b6001600160a01b0382165f90815260208490526040902080546133d89083906001600160401b0316615653565b815467ffffffffffffffff19166001600160401b0391909116179055505050565b5f610c98633b9aca006001600160401b038416615672565b6040516001600160a01b03808516602483015283166044820152606481018290526114909085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613b3e565b5f54610100900460ff16610e285760405162461bcd60e51b8152600401610d84906153b0565b5f818353505060010190565b6001600160a01b0381163b61351b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d84565b5f5160206156e85f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b61355283613c11565b5f8251118061355e5750805b15611720576114908383613c50565b5f81831161357b5782610f6e565b50919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61ffff811115610ceb5760405163161e7a6b60e11b815260040160405180910390fd5b805160601b8252602081015160d01b60148301526040810151601a8301908152603a8301610f6e565b60408051808201909152606081525f60208201526101005460ff9065ffffffffffff80821691600160301b9004811690828203165f8187116136605786613662565b815b9050806001016001600160401b0381111561367f5761367f614322565b6040519080825280602002602001820160405280156136e257816020015b6136cf6040805180820182525f8082528251606080820185528152602081810183905293810191909152909182015290565b81526020019060019003908161369d5790505b508087525f906136f79087908b908886613c75565b955090507f00000000000000000000000000000000000000000000000000000000000000018810801561372957508183115b1561377e575f61375b8787877f0000000000000000000000000000000000000000000000000000000000000000613df3565b9050801561377c5760405163014b3fdb60e11b815260040160405180910390fd5b505b65ffffffffffff167f000000000000000000000000000000000000000000000000000000000000000560ff167f000000000000000000000000000000000000000000000000000000000000000061ffff1602014211602087015250939695505050505050565b604080516060808201835281525f6020808301829052928201529082015161ffff166138235760405163fdac229f60e01b815260040160405180910390fd5b5f826020015161ffff166001600160401b0381111561384457613844614322565b60405190808252806020026020018201604052801561386d578160200160208202803683370190505b5090505f5b836020015161ffff168110156138f557835161389390829061ffff16615614565b498282815181106138a6576138a661534a565b6020026020010181815250508181815181106138c4576138c461534a565b60200260200101515f5f1b036138ed57604051637bb2fa2f60e11b815260040160405180910390fd5b600101613872565b50604080516060810182529182529283015162ffffff16602082015265ffffffffffff4216928101929092525090565b6001600160a01b0382165f90815260208490526040812080546001600160401b0380851691161080159061396757508054600160401b900465ffffffffffff16155b95945050505050565b6001600160a01b0382165f90815260208490526040812080546001600160401b038085169116116139bb57805467ffffffffffffffff19811682556001600160401b031691506139f1565b80548392506139d49083906001600160401b03166155f5565b815467ffffffffffffffff19166001600160401b03919091161781555b509392505050565b6040516001600160a01b03831660248201526044810182905261172090849063a9059cbb60e01b90606401613445565b815f03613a3557505050565b613a4f83838360405180602001604052805f815250613e5c565b61172057604051634c67134d60e11b815260040160405180910390fd5b5f818311613a7a5781610f6e565b5090919050565b5f613a8d858584613970565b9050806001600160401b03165f03613aa55750611490565b5f613ab1600283615689565b90505f613abe82846155f5565b90506001600160401b03821615613ada57613ada8786846133ab565b604080516001600160401b038681168252848116602083015283168183015290516001600160a01b0387811692908916917faa22f5157944b5fa6846460e159d57ea9c3878e71fda274af372fa2ccf285aa09181900360600190a350505050505050565b5f613b92826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e999092919063ffffffff16565b905080515f1480613bb2575080806020019051810190613bb291906156b6565b6117205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d84565b613c1a816134ae565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610f6e838360405180606001604052806027815260200161570860279139613ea7565b5f5f825f03613c8e575065ffffffffffff905082613de9565b5f5f5b84811015613d7e5765ffffffffffff861681015f90815260208a815260409182902082518084018452600180825284519083018054608081870284018101909752606083018181529496939586019492939192849290918491840182828015613d1757602002820191905f5260205f20905b815481526020019060010190808311613d03575b50505091835250506001919091015462ffffff811660208301526301000000900465ffffffffffff1660409091015290528851899084908110613d5c57613d5c61534a565b6020908102919091010152546001600160401b03169190910190600101613c91565b50613d986001600160a01b038816633b9aca008302612dd1565b855f81518110613daa57613daa61534a565b602002602001015160200151604001519250838501915081886001015f6101000a81548165ffffffffffff021916908365ffffffffffff160217905550505b9550959350505050565b5f8265ffffffffffff168465ffffffffffff1603613e1257505f613e54565b65ffffffffffff8085165f908152602087905260408120600201546301000000900490911690819003613e48575f915050613e54565b61ffff83160142101590505b949350505050565b5f6001600160a01b038516613e8457604051634c67134d60e11b815260040160405180910390fd5b5f5f835160208501878988f195945050505050565b6060613e5484845f85613f1b565b60605f5f856001600160a01b031685604051613ec391906156d1565b5f60405180830381855af49150503d805f8114613efb576040519150601f19603f3d011682016040523d82523d5f602084013e613f00565b606091505b5091509150613f1186838387613fe3565b9695505050505050565b606082471015613f7c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d84565b5f5f866001600160a01b03168587604051613f9791906156d1565b5f6040518083038185875af1925050503d805f8114613fd1576040519150601f19603f3d011682016040523d82523d5f602084013e613fd6565b606091505b509150915061337a878383875b606083156140515782515f0361404a576001600160a01b0385163b61404a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d84565b5081613e54565b613e5483838151156140665781518083602001fd5b8060405162461bcd60e51b8152600401610d8491906141ca565b60408051606080820183525f8083528351918201845280825260208281018290529382015290918201905b81525f60209091015290565b60405180604001604052806140ab6040518060e001604052805f65ffffffffffff1681526020015f81526020015f81526020015f6001600160a01b031681526020015f65ffffffffffff1681526020015f8152602001606081525090565b6001600160a01b0381168114610ceb575f5ffd5b803561413481614115565b919050565b5f60208284031215614149575f5ffd5b8135610f6e81614115565b6001600160401b0381168114610ceb575f5ffd5b5f60208284031215614178575f5ffd5b8135610f6e81614154565b5f60a0828403128015614194575f5ffd5b509092915050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610f6e602083018461419c565b65ffffffffffff81168114610ceb575f5ffd5b8035614134816141dc565b5f5f6040838503121561420b575f5ffd5b8235614216816141dc565b91506020830135614226816141dc565b809150509250929050565b8051606080845281519084018190525f9160200190829060808601905b80831015614271578351825260208201915060208401935060018301925061424e565b5062ffffff602086015116602087015265ffffffffffff604086015116604087015280935050505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561431657603f1987860301845281516001600160401b03815116865260208101519050604060208701526143006040870182614231565b95505060209384019391909101906001016142c5565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051606081016001600160401b038111828210171561435857614358614322565b60405290565b604080519081016001600160401b038111828210171561435857614358614322565b60405161012081016001600160401b038111828210171561435857614358614322565b60405160c081016001600160401b038111828210171561435857614358614322565b60405160e081016001600160401b038111828210171561435857614358614322565b604051601f8201601f191681016001600160401b038111828210171561440f5761440f614322565b604052919050565b5f5f60408385031215614428575f5ffd5b823561443381614115565b915060208301356001600160401b0381111561444d575f5ffd5b8301601f8101851361445d575f5ffd5b80356001600160401b0381111561447657614476614322565b614489601f8201601f19166020016143e7565b81815286602083850101111561449d575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f602082840312156144cc575f5ffd5b5035919050565b5f602082840312156144e3575f5ffd5b81356001600160401b038111156144f8575f5ffd5b820160408185031215610f6e575f5ffd5b5f5f83601f840112614519575f5ffd5b5081356001600160401b0381111561452f575f5ffd5b602083019150836020828501011115614546575f5ffd5b9250929050565b5f5f5f5f60408587031215614560575f5ffd5b84356001600160401b03811115614575575f5ffd5b61458187828801614509565b90955093505060208501356001600160401b0381111561459f575f5ffd5b6145ab87828801614509565b95989497509550505050565b5f5f602083850312156145c8575f5ffd5b82356001600160401b038111156145dd575f5ffd5b6145e985828601614509565b90969095509350505050565b815165ffffffffffff16815260208083015160a083019161463c9084018261ffff815116825261ffff602082015116602083015262ffffff60408201511660408301525050565b5060ff604084015116608083015292915050565b5f60208284031215614660575f5ffd5b81356001600160401b03811115614675575f5ffd5b82016101208185031215610f6e575f5ffd5b81516001600160a01b03168152610260810160208301516146b360208401826001600160a01b03169052565b5060408301516146ce60408401826001600160a01b03169052565b5060608301516146e960608401826001600160a01b03169052565b50608083015161470460808401826001600160a01b03169052565b5060a083015161471f60a08401826001600160401b03169052565b5060c083015161473a60c08401826001600160401b03169052565b5060e083015161475460e084018265ffffffffffff169052565b5061010083015161477061010084018265ffffffffffff169052565b5061012083015161478c61012084018265ffffffffffff169052565b506101408301516147a861014084018265ffffffffffff169052565b506101608301516147c461016084018265ffffffffffff169052565b506101808301516147db61018084018260ff169052565b506101a08301516101a08301526101c08301516147ff6101c084018261ffff169052565b506101e083015161481c6101e08401826001600160401b03169052565b506102008301516148396102008401826001600160401b03169052565b5061022083015161485161022084018261ffff169052565b5061024083015161486861024084018260ff169052565b5092915050565b5f5f60408385031215614880575f5ffd5b823561488b81614115565b9150602083013561422681614154565b803561ffff81168114614134575f5ffd5b62ffffff81168114610ceb575f5ffd5b8035614134816148ac565b5f606082840312156148d7575f5ffd5b6148df614336565b90506148ea8261489b565b81526148f86020830161489b565b6020820152604082013561490b816148ac565b604082015292915050565b5f60608284031215614926575f5ffd5b610f6e83836148c7565b5f8151808452602084019350602083015f5b8281101561498a57815180516001600160a01b0316875260208082015165ffffffffffff16818901526040918201519188019190915260609096019590910190600101614942565b5093949350505050565b602081525f82516040602084015265ffffffffffff815116606084015260208101516080840152604081015160a084015260018060a01b0360608201511660c084015265ffffffffffff60808201511660e084015260a081015161010084015260c0810151905060e0610120840152614a11610140840182614930565b905060208401516139f1604085018215159052565b5f60208284031215614a36575f5ffd5b81356001600160401b03811115614a4b575f5ffd5b820160e08185031215610f6e575f5ffd5b60ff81168114610ceb575f5ffd5b803561413481614a5c565b5f60a0828403128015614a86575f5ffd5b50614a8f614336565b8235614a9a816141dc565b8152614aa984602085016148c7565b60208201526080830135614abc81614a5c565b60408201529392505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b8051614134816141dc565b805161413481614115565b805161413481614a5c565b5f6001600160401b03821115614b9957614b99614322565b5060051b60200190565b8015158114610ceb575f5ffd5b8051614134816148ac565b5f82601f830112614bca575f5ffd5b8151614bdd614bd882614b81565b6143e7565b8082825260208201915060208360051b860101925085831115614bfe575f5ffd5b602085015b83811015614d405780516001600160401b03811115614c20575f5ffd5b86016040818903601f19011215614c35575f5ffd5b614c3d61435e565b6020820151614c4b81614ba3565b815260408201516001600160401b03811115614c65575f5ffd5b6020818401019250506060828a031215614c7d575f5ffd5b614c85614336565b82516001600160401b03811115614c9a575f5ffd5b8301601f81018b13614caa575f5ffd5b8051614cb8614bd882614b81565b8082825260208201915060208360051b85010192508d831115614cd9575f5ffd5b6020840193505b82841015614cfb578351825260209384019390910190614ce0565b845250614d0d91505060208401614bb0565b6020820152614d1e60408401614b60565b6040820152806020830152508085525050602083019250602081019050614c03565b5095945050505050565b5f6101208284031215614d5b575f5ffd5b614d63614380565b9050614d6e82614b60565b8152614d7c60208301614b60565b6020820152614d8d60408301614b60565b6040820152614d9e60608301614b6b565b606082015260808281015190820152614db960a08301614b60565b60a082015260c08281015190820152614dd460e08301614b76565b60e08201526101008201516001600160401b03811115614df2575f5ffd5b614dfe84828501614bbb565b6101008301525092915050565b5f5f5f5f848603610120811215614e20575f5ffd5b8551614e2b816141dc565b945060c0601f1982011215614e3e575f5ffd5b50614e476143a3565b6020860151614e55816141dc565b81526040860151614e65816141dc565b60208201526060860151614e78816141dc565b60408201526080860151614e8b816141dc565b606082015260a0860151614e9e816141dc565b608082015260c086015160a082015260e08601519093506001600160401b03811115614ec8575f5ffd5b614ed487828801614d4a565b61010096909601519497939650505050565b5f82601f830112614ef5575f5ffd5b8135614f03614bd882614b81565b80828252602082019150602060608402860101925085831115614f24575f5ffd5b602085015b83811015614d405760608188031215614f40575f5ffd5b614f48614336565b8135614f5381614115565b81526020820135614f63816141dc565b602082810191909152604083810135908301529084529290920191606001614f29565b5f60e08284031215614f96575f5ffd5b614f9e6143c5565b9050614fa9826141ef565b81526020828101359082015260408083013590820152614fcb60608301614129565b6060820152614fdc608083016141ef565b608082015260a0828101359082015260c08201356001600160401b03811115615003575f5ffd5b61500f84828501614ee6565b60c08301525092915050565b5f6040823603121561502b575f5ffd5b61503361435e565b82356001600160401b03811115615048575f5ffd5b61505436828601614f86565b825250602083013561506581614ba3565b602082015292915050565b634e487b7160e01b5f52601260045260245ffd5b5f8261509257615092615070565b500690565b5f82601f8301126150a6575f5ffd5b81356150b4614bd882614b81565b8082825260208201915060208360051b8601019250858311156150d5575f5ffd5b602085015b83811015614d405780356001600160401b038111156150f7575f5ffd5b86016040818903601f1901121561510c575f5ffd5b61511461435e565b602082013561512281614ba3565b815260408201356001600160401b0381111561513c575f5ffd5b6020818401019250506060828a031215615154575f5ffd5b61515c614336565b82356001600160401b03811115615171575f5ffd5b8301601f81018b13615181575f5ffd5b803561518f614bd882614b81565b8082825260208201915060208360051b85010192508d8311156151b0575f5ffd5b6020840193505b828410156151d25783358252602093840193909101906151b7565b8452506151e4915050602084016148bc565b60208201526151f5604084016141ef565b60408201528060208301525080855250506020830192506020810190506150da565b5f6101208236031215615228575f5ffd5b615230614380565b615239836141ef565b8152615247602084016141ef565b6020820152615258604084016141ef565b604082015261526960608401614129565b60608201526080838101359082015261528460a084016141ef565b60a082015260c0838101359082015261529f60e08401614a6a565b60e08201526101008301356001600160401b038111156152bd575f5ffd5b614dfe36828601615097565b8481526001600160401b0384811660208301528316604082015260c08101613967606083018461ffff815116825261ffff602082015116602083015262ffffff60408201511660408301525050565b5f60208284031215615328575f5ffd5b5051919050565b5f6020828403121561533f575f5ffd5b8151610f6e81614154565b634e487b7160e01b5f52603260045260245ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201525f613f1160608301848661535e565b5f610c983683614f86565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f65ffffffffffff83168061541257615412615070565b8065ffffffffffff84160691505092915050565b5f82825180855260208501945060208160051b830101602085015f5b8381101561548d57601f19858403018852815180511515845260208101519050604060208501526154766040850182614231565b6020998a0199909450929092019150600101615442565b50909695505050505050565b84815265ffffffffffff8416602082015260ff83166040820152608060608201525f613f116080830184615426565b6001600160a01b03841681526040602082018190525f90613967908301848661535e565b5f602082840312156154fc575f5ffd5b8151610f6e816141dc565b6020815261552060208201835165ffffffffffff169052565b5f602083015161553a604084018265ffffffffffff169052565b50604083015165ffffffffffff811660608401525060608301516001600160a01b038116608084015250608083015160a083015260a083015161558760c084018265ffffffffffff169052565b5060c083015160e083015260e08301516155a761010084018260ff169052565b5061010083015161012080840152613e54610140840182615426565b634e487b7160e01b5f52601160045260245ffd5b65ffffffffffff8181168382160190811115610c9857610c986155c3565b6001600160401b038281168282160390811115610c9857610c986155c3565b80820180821115610c9857610c986155c3565b5f5f60408385031215615638575f5ffd5b825161564381614ba3565b6020939093015192949293505050565b6001600160401b038181168382160190811115610c9857610c986155c3565b8082028115828204841417610c9857610c986155c3565b5f6001600160401b038316806156a1576156a1615070565b806001600160401b0384160491505092915050565b5f602082840312156156c6575f5ffd5b8151610f6e81614ba3565b5f82518060208501845e5f92019182525091905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220528534fe7195b2d7ae117d69a1bf4b3ca9026c4dcf967e9bd391ad01e0bfe22664736f6c634300081e0033