Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- LibForcedInclusion
- Optimization enabled
- true
- Compiler version
- v0.8.30+commit.73712a01
- Optimization runs
- 200
- EVM Version
- cancun
- Verified at
- 2026-06-24T11:59:16.615215Z
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/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_);
}
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/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));
}
}
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":{"contracts/layer1/core/libs/LibInboxSetup.sol":{"LibInboxSetup":"0x7cAC361f37757976a9Fc365dEC0935adbAfCA7dC"},"contracts/layer1/core/libs/LibForcedInclusion.sol":{"LibForcedInclusion":"0x7cAEDdD26DBce173Af33715B7f38a765B027EBE2"}},"evmVersion":"cancun"}
Contract ABI
[{"type":"error","name":"BlobNotFound","inputs":[]},{"type":"error","name":"InsufficientFee","inputs":[]},{"type":"error","name":"InvalidFeeDoubleThreshold","inputs":[]},{"type":"error","name":"NoBlobs","inputs":[]},{"type":"error","name":"OnlySingleBlobAllowed","inputs":[]},{"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}]
Contract Creation Code
0x610790610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061003f575f3560e01c806343c3d719146100435780639595548814610073575b5f5ffd5b6100566100513660046104d1565b6100a0565b6040516001600160401b0390911681526020015b60405180910390f35b81801561007e575f5ffd5b5061009261008d36600461052f565b61014c565b60405190815260200161006a565b5f5f826001600160401b0316116100ca57604051630ef1aed760e31b815260040160405180910390fd5b600184015465ffffffffffff8082169166010000000000009004165f6100f083836105fe565b65ffffffffffff1690505f61010e826001600160401b03881661061c565b610121906001600160401b03891661062f565b90506101406001600160401b0361013a88821684610646565b906102ff565b98975050505050505050565b5f5f61015783610318565b80515190915060011461017d576040516387a68e9d60e01b815260040160405180910390fd5b5f6101898787876100a0565b90505f61019a82633b9aca00610665565b6001600160401b03169050803410156101c55760405162976f7560e21b815260040160405180910390fd5b604080518082019091526001600160401b03831681526020810184905260018901805482918b915f91660100000000000090910465ffffffffffff1690600661020d8361068e565b82546101009290920a65ffffffffffff8181021990931691831602179091551681526020808201929092526040015f208251815467ffffffffffffffff19166001600160401b039091161781558282015180518051929391926001850192610279928492910190610459565b5060208201516001909101805460409384015165ffffffffffff1663010000000268ffffffffffffffffff1990911662ffffff90931692909217919091179055517f18c4fc1e6ac628dbb537b0375bf0efabf1ff2528af1ec22faa74d2da95c2947192506102e9915083906106b6565b60405180910390a1503403979650505050505050565b5f81831161030d578261030f565b815b90505b92915050565b604080516060808201835281525f6020808301829052928201529082015161ffff166103575760405163fdac229f60e01b815260040160405180910390fd5b5f826020015161ffff166001600160401b038111156103785761037861050a565b6040519080825280602002602001820160405280156103a1578160200160208202803683370190505b5090505f5b836020015161ffff168110156104295783516103c790829061ffff1661061c565b498282815181106103da576103da610746565b6020026020010181815250508181815181106103f8576103f8610746565b60200260200101515f5f1b0361042157604051637bb2fa2f60e11b815260040160405180910390fd5b6001016103a6565b50604080516060810182529182529283015162ffffff16602082015265ffffffffffff4216928101929092525090565b828054828255905f5260205f20908101928215610492579160200282015b82811115610492578251825591602001919060010190610477565b5061049e9291506104a2565b5090565b5b8082111561049e575f81556001016104a3565b80356001600160401b03811681146104cc575f5ffd5b919050565b5f5f5f606084860312156104e3575f5ffd5b833592506104f3602085016104b6565b9150610501604085016104b6565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b803561ffff811681146104cc575f5ffd5b5f5f5f5f84860360c0811215610543575f5ffd5b85359450610553602087016104b6565b9350610561604087016104b6565b92506060605f1982011215610574575f5ffd5b50604051606081018181106001600160401b03821117156105a357634e487b7160e01b5f52604160045260245ffd5b6040526105b26060870161051e565b81526105c06080870161051e565b602082015260a086013562ffffff811681146105da575f5ffd5b6040820152939692955090935050565b634e487b7160e01b5f52601160045260245ffd5b65ffffffffffff8281168282160390811115610312576103126105ea565b80820180821115610312576103126105ea565b8082028115828204841417610312576103126105ea565b5f8261066057634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160401b038181168382160290811690818114610687576106876105ea565b5092915050565b5f65ffffffffffff821665ffffffffffff81036106ad576106ad6105ea565b60010192915050565b602080825282516001600160401b031682820152828101516040808401528051606080850152805160c085018190525f939190910190839060e08601905b8083101561071757835182526020820191506020840193506001830192506106f4565b5062ffffff602085015116608087015265ffffffffffff60408501511660a08701528094505050505092915050565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220ff09d79be1f8e659a5cae954cfe21b41511f3854934700dc1126cbadd8f792d364736f6c634300081e0033
Deployed ByteCode
0x737caeddd26dbce173af33715b7f38a765b027ebe2301460806040526004361061003f575f3560e01c806343c3d719146100435780639595548814610073575b5f5ffd5b6100566100513660046104d1565b6100a0565b6040516001600160401b0390911681526020015b60405180910390f35b81801561007e575f5ffd5b5061009261008d36600461052f565b61014c565b60405190815260200161006a565b5f5f826001600160401b0316116100ca57604051630ef1aed760e31b815260040160405180910390fd5b600184015465ffffffffffff8082169166010000000000009004165f6100f083836105fe565b65ffffffffffff1690505f61010e826001600160401b03881661061c565b610121906001600160401b03891661062f565b90506101406001600160401b0361013a88821684610646565b906102ff565b98975050505050505050565b5f5f61015783610318565b80515190915060011461017d576040516387a68e9d60e01b815260040160405180910390fd5b5f6101898787876100a0565b90505f61019a82633b9aca00610665565b6001600160401b03169050803410156101c55760405162976f7560e21b815260040160405180910390fd5b604080518082019091526001600160401b03831681526020810184905260018901805482918b915f91660100000000000090910465ffffffffffff1690600661020d8361068e565b82546101009290920a65ffffffffffff8181021990931691831602179091551681526020808201929092526040015f208251815467ffffffffffffffff19166001600160401b039091161781558282015180518051929391926001850192610279928492910190610459565b5060208201516001909101805460409384015165ffffffffffff1663010000000268ffffffffffffffffff1990911662ffffff90931692909217919091179055517f18c4fc1e6ac628dbb537b0375bf0efabf1ff2528af1ec22faa74d2da95c2947192506102e9915083906106b6565b60405180910390a1503403979650505050505050565b5f81831161030d578261030f565b815b90505b92915050565b604080516060808201835281525f6020808301829052928201529082015161ffff166103575760405163fdac229f60e01b815260040160405180910390fd5b5f826020015161ffff166001600160401b038111156103785761037861050a565b6040519080825280602002602001820160405280156103a1578160200160208202803683370190505b5090505f5b836020015161ffff168110156104295783516103c790829061ffff1661061c565b498282815181106103da576103da610746565b6020026020010181815250508181815181106103f8576103f8610746565b60200260200101515f5f1b0361042157604051637bb2fa2f60e11b815260040160405180910390fd5b6001016103a6565b50604080516060810182529182529283015162ffffff16602082015265ffffffffffff4216928101929092525090565b828054828255905f5260205f20908101928215610492579160200282015b82811115610492578251825591602001919060010190610477565b5061049e9291506104a2565b5090565b5b8082111561049e575f81556001016104a3565b80356001600160401b03811681146104cc575f5ffd5b919050565b5f5f5f606084860312156104e3575f5ffd5b833592506104f3602085016104b6565b9150610501604085016104b6565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b803561ffff811681146104cc575f5ffd5b5f5f5f5f84860360c0811215610543575f5ffd5b85359450610553602087016104b6565b9350610561604087016104b6565b92506060605f1982011215610574575f5ffd5b50604051606081018181106001600160401b03821117156105a357634e487b7160e01b5f52604160045260245ffd5b6040526105b26060870161051e565b81526105c06080870161051e565b602082015260a086013562ffffff811681146105da575f5ffd5b6040820152939692955090935050565b634e487b7160e01b5f52601160045260245ffd5b65ffffffffffff8281168282160390811115610312576103126105ea565b80820180821115610312576103126105ea565b8082028115828204841417610312576103126105ea565b5f8261066057634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160401b038181168382160290811690818114610687576106876105ea565b5092915050565b5f65ffffffffffff821665ffffffffffff81036106ad576106ad6105ea565b60010192915050565b602080825282516001600160401b031682820152828101516040808401528051606080850152805160c085018190525f939190910190839060e08601905b8083101561071757835182526020820191506020840193506001830192506106f4565b5062ffffff602085015116608087015265ffffffffffff60408501511660a08701528094505050505092915050565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220ff09d79be1f8e659a5cae954cfe21b41511f3854934700dc1126cbadd8f792d364736f6c634300081e0033
External libraries
LibForcedInclusion : 0x7cAEDdD26DBce173Af33715B7f38a765B027EBE2
LibInboxSetup : 0x7cAC361f37757976a9Fc365dEC0935adbAfCA7dC