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
- prague
- Verified at
- 2025-12-15T12:39:36.247620Z
contracts/layer1/core/libs/LibForcedInclusion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
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.24;
/// @title LibBlobs
/// @notice Library for handling blobs.
/// @custom:security-contact security@taiko.xyz
library LibBlobs {
// ---------------------------------------------------------------
// Constants
// ---------------------------------------------------------------
uint256 internal constant FIELD_ELEMENT_BYTES = 32;
uint256 internal constant BLOB_FIELD_ELEMENTS = 4096;
uint256 internal constant BLOB_BYTES = BLOB_FIELD_ELEMENTS * FIELD_ELEMENT_BYTES;
// ---------------------------------------------------------------
// Structs
// ---------------------------------------------------------------
/// @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":true,"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":"0xf88Ef5437749A225621101BE8C1BE1A0cE967758"},"contracts/layer1/core/libs/LibForcedInclusion.sol":{"LibForcedInclusion":"0xd1a27F331c17eD8Cbb6DAbce67A42d6b8a6B0e14"}},"evmVersion":"prague"}
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
0x60808060405234601b576105dc90816100208239308160320152f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806343c3d7191461043f5763959554881461002f575f80fd5b307f00000000000000000000000000000000000000000000000000000000000000001461043b5760c036600319011261043b5760043561006d61047a565b610075610490565b91606036606319011261043b5761008a6104a6565b9060643561ffff8116810361043b5782526084359361ffff8516850361043b576020830194855260a4359362ffffff8516850361043b57604084019485525f60406100d36104a6565b60608152826020820152015261ffff8651161561042c5761ffff865116946100fa86610567565b6040519690601f01601f191687016001600160401b038111888210176103e75760405280875261012c601f1991610567565b013660208801375f5b61ffff885116811015610184576101518161ffff8851166104c5565b4961015c828961057e565b52610167818861057e565b511561017557600101610135565b637bb2fa2f60e11b5f5260045ffd5b505162ffffff1693506001856101986104a6565b95818752602087015265ffffffffffff42166040870152510361041d576001600160401b03916101c891846104d2565b1691633b9aca008302916001600160401b0383169283036103fb5782341061040f5760405193604085018581106001600160401b038211176103e7576040528452602084019182526001810180549065ffffffffffff8260301c169165ffffffffffff83146103fb576bffffffffffff0000000000006001840160301b16906bffffffffffff00000000000019161790555f5260205260405f206001600160401b038451166001600160401b031982541617815560018101908251918251908151916001600160401b0383116103e7576801000000000000000083116103e75781548383558084106103c1575b50602001905f5260205f205f5b8381106103ad57505050506002019062ffffff60208201511668ffffffffffff0000006040845493015160181b169168ffffffffffffffffff1916171790556001600160401b036040519360208552511660208401525160408084015260c08301908051916060808601528251809152602060e086019301905f5b8181106103975760208481015162ffffff166080890152604085015165ffffffffffff1660a0890152867f18c4fc1e6ac628dbb537b0375bf0efabf1ff2528af1ec22faa74d2da95c294718988038aa16040519034038152f35b825185526020948501949092019160010161033d565b6001906020845194019381840155016102c2565b825f528360205f2091820191015b8181106103dc57506102b5565b5f81556001016103cf565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b62976f7560e21b5f5260045ffd5b6387a68e9d60e01b5f5260045ffd5b63fdac229f60e01b5f5260045ffd5b5f80fd5b606036600319011261043b57602061046961045861047a565b610460610490565b906004356104d2565b6001600160401b0360405191168152f35b602435906001600160401b038216820361043b57565b604435906001600160401b038216820361043b57565b60405190606082018281106001600160401b038211176103e757604052565b919082018092116103fb57565b916001600160401b0316918215610558576001015465ffffffffffff8082169160301c160365ffffffffffff81116103fb5761051e65ffffffffffff6001600160401b039216846104c5565b91168181029181830414901517156103fb57046001600160401b0381111561054c57506001600160401b0390565b6001600160401b031690565b630ef1aed760e31b5f5260045ffd5b6001600160401b0381116103e75760051b60200190565b80518210156105925760209160051b010190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220ab057f956a81c6714f99b74ebdfcaa93619ab61759704e64fecc62fd052941ee64736f6c634300081e0033
Deployed ByteCode
0x60806040526004361015610011575f80fd5b5f3560e01c806343c3d7191461043f5763959554881461002f575f80fd5b307f000000000000000000000000d1a27f331c17ed8cbb6dabce67a42d6b8a6b0e141461043b5760c036600319011261043b5760043561006d61047a565b610075610490565b91606036606319011261043b5761008a6104a6565b9060643561ffff8116810361043b5782526084359361ffff8516850361043b576020830194855260a4359362ffffff8516850361043b57604084019485525f60406100d36104a6565b60608152826020820152015261ffff8651161561042c5761ffff865116946100fa86610567565b6040519690601f01601f191687016001600160401b038111888210176103e75760405280875261012c601f1991610567565b013660208801375f5b61ffff885116811015610184576101518161ffff8851166104c5565b4961015c828961057e565b52610167818861057e565b511561017557600101610135565b637bb2fa2f60e11b5f5260045ffd5b505162ffffff1693506001856101986104a6565b95818752602087015265ffffffffffff42166040870152510361041d576001600160401b03916101c891846104d2565b1691633b9aca008302916001600160401b0383169283036103fb5782341061040f5760405193604085018581106001600160401b038211176103e7576040528452602084019182526001810180549065ffffffffffff8260301c169165ffffffffffff83146103fb576bffffffffffff0000000000006001840160301b16906bffffffffffff00000000000019161790555f5260205260405f206001600160401b038451166001600160401b031982541617815560018101908251918251908151916001600160401b0383116103e7576801000000000000000083116103e75781548383558084106103c1575b50602001905f5260205f205f5b8381106103ad57505050506002019062ffffff60208201511668ffffffffffff0000006040845493015160181b169168ffffffffffffffffff1916171790556001600160401b036040519360208552511660208401525160408084015260c08301908051916060808601528251809152602060e086019301905f5b8181106103975760208481015162ffffff166080890152604085015165ffffffffffff1660a0890152867f18c4fc1e6ac628dbb537b0375bf0efabf1ff2528af1ec22faa74d2da95c294718988038aa16040519034038152f35b825185526020948501949092019160010161033d565b6001906020845194019381840155016102c2565b825f528360205f2091820191015b8181106103dc57506102b5565b5f81556001016103cf565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b62976f7560e21b5f5260045ffd5b6387a68e9d60e01b5f5260045ffd5b63fdac229f60e01b5f5260045ffd5b5f80fd5b606036600319011261043b57602061046961045861047a565b610460610490565b906004356104d2565b6001600160401b0360405191168152f35b602435906001600160401b038216820361043b57565b604435906001600160401b038216820361043b57565b60405190606082018281106001600160401b038211176103e757604052565b919082018092116103fb57565b916001600160401b0316918215610558576001015465ffffffffffff8082169160301c160365ffffffffffff81116103fb5761051e65ffffffffffff6001600160401b039216846104c5565b91168181029181830414901517156103fb57046001600160401b0381111561054c57506001600160401b0390565b6001600160401b031690565b630ef1aed760e31b5f5260045ffd5b6001600160401b0381116103e75760051b60200190565b80518210156105925760209160051b010190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220ab057f956a81c6714f99b74ebdfcaa93619ab61759704e64fecc62fd052941ee64736f6c634300081e0033
External libraries
LibForcedInclusion : 0xd1a27F331c17eD8Cbb6DAbce67A42d6b8a6B0e14
LibInboxSetup : 0xf88Ef5437749A225621101BE8C1BE1A0cE967758