Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x4eB2Cada...7dceC0cA2 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
LineaRollup
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { L1MessageService } from "./messageService/l1/L1MessageService.sol";
import { ZkEvmV2 } from "./ZkEvmV2.sol";
import { ILineaRollup } from "./interfaces/l1/ILineaRollup.sol";
import { PermissionsManager } from "./lib/PermissionsManager.sol";
import { Utils } from "./lib/Utils.sol";
/**
* @title Contract to manage cross-chain messaging on L1, L2 data submission, and rollup proof verification.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
contract LineaRollup is
Initializable,
AccessControlUpgradeable,
ZkEvmV2,
L1MessageService,
PermissionsManager,
ILineaRollup
{
using Utils for *;
/// @notice This is the ABI version and not the reinitialize version.
string public constant CONTRACT_VERSION = "6.0";
/// @notice The role required to set/add proof verifiers by type.
bytes32 public constant VERIFIER_SETTER_ROLE = keccak256("VERIFIER_SETTER_ROLE");
/// @notice The role required to set/remove proof verifiers by type.
bytes32 public constant VERIFIER_UNSETTER_ROLE = keccak256("VERIFIER_UNSETTER_ROLE");
/// @dev Value indicating a shnarf exists.
uint256 internal constant SHNARF_EXISTS_DEFAULT_VALUE = 1;
/// @dev The default hash value.
bytes32 internal constant EMPTY_HASH = 0x0;
/// @dev The BLS Curve modulus value used.
uint256 internal constant BLS_CURVE_MODULUS =
52435875175126190479447740508185965837690552500527637822603658699938581184513;
/// @dev The well-known precompile address for point evaluation.
address internal constant POINT_EVALUATION_PRECOMPILE_ADDRESS = address(0x0a);
/// @dev The expected point evaluation return data length.
uint256 internal constant POINT_EVALUATION_RETURN_DATA_LENGTH = 64;
/// @dev The expected point evaluation field element length returned.
uint256 internal constant POINT_EVALUATION_FIELD_ELEMENTS_LENGTH = 4096;
/// @dev In practice, when used, this is expected to be a close approximation to 6 months, and is intentional.
uint256 internal constant SIX_MONTHS_IN_SECONDS = (365 / 2) * 24 * 60 * 60;
/// @dev DEPRECATED in favor of the single blobShnarfExists mapping.
mapping(bytes32 dataHash => bytes32 finalStateRootHash) public dataFinalStateRootHashes;
/// @dev DEPRECATED in favor of the single blobShnarfExists mapping.
mapping(bytes32 dataHash => bytes32 parentHash) public dataParents;
/// @dev DEPRECATED in favor of the single blobShnarfExists mapping.
mapping(bytes32 dataHash => bytes32 shnarfHash) public dataShnarfHashes;
/// @dev DEPRECATED in favor of the single blobShnarfExists mapping.
mapping(bytes32 dataHash => uint256 startingBlock) public dataStartingBlock;
/// @dev DEPRECATED in favor of the single blobShnarfExists mapping.
mapping(bytes32 dataHash => uint256 endingBlock) public dataEndingBlock;
/// @dev DEPRECATED in favor of currentFinalizedState hash.
uint256 public currentL2StoredL1MessageNumber;
/// @dev DEPRECATED in favor of currentFinalizedState hash.
bytes32 public currentL2StoredL1RollingHash;
/// @notice Contains the most recent finalized shnarf.
bytes32 public currentFinalizedShnarf;
/**
* @dev NB: THIS IS THE ONLY MAPPING BEING USED FOR DATA SUBMISSION TRACKING.
* @dev NB: This was shnarfFinalBlockNumbers and is replaced to indicate only that a shnarf exists with a value of 1.
*/
mapping(bytes32 shnarf => uint256 exists) public blobShnarfExists;
/// @notice Hash of the L2 computed L1 message number, rolling hash and finalized timestamp.
bytes32 public currentFinalizedState;
/// @notice The address of the fallback operator.
/// @dev This address is granted the OPERATOR_ROLE after six months of finalization inactivity by the current operators.
address public fallbackOperator;
/// @dev Total contract storage is 11 slots.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes LineaRollup and underlying service dependencies - used for new networks only.
* @dev DEFAULT_ADMIN_ROLE is set for the security council.
* @dev OPERATOR_ROLE is set for operators.
* @dev Note: This is used for new testnets and local/CI testing, and will not replace existing proxy based contracts.
* @param _initializationData The initial data used for proof verification.
*/
function initialize(InitializationData calldata _initializationData) external initializer {
if (_initializationData.defaultVerifier == address(0)) {
revert ZeroAddressNotAllowed();
}
__PauseManager_init(_initializationData.pauseTypeRoles, _initializationData.unpauseTypeRoles);
__MessageService_init(_initializationData.rateLimitPeriodInSeconds, _initializationData.rateLimitAmountInWei);
/**
* @dev DEFAULT_ADMIN_ROLE is set for the security council explicitly,
* as the permissions init purposefully does not allow DEFAULT_ADMIN_ROLE to be set.
*/
_grantRole(DEFAULT_ADMIN_ROLE, _initializationData.defaultAdmin);
__Permissions_init(_initializationData.roleAddresses);
verifiers[0] = _initializationData.defaultVerifier;
fallbackOperator = _initializationData.fallbackOperator;
emit FallbackOperatorAddressSet(msg.sender, _initializationData.fallbackOperator);
currentL2BlockNumber = _initializationData.initialL2BlockNumber;
stateRootHashes[_initializationData.initialL2BlockNumber] = _initializationData.initialStateRootHash;
bytes32 genesisShnarf = _computeShnarf(
EMPTY_HASH,
EMPTY_HASH,
_initializationData.initialStateRootHash,
EMPTY_HASH,
EMPTY_HASH
);
blobShnarfExists[genesisShnarf] = SHNARF_EXISTS_DEFAULT_VALUE;
currentFinalizedShnarf = genesisShnarf;
currentFinalizedState = _computeLastFinalizedState(0, EMPTY_HASH, _initializationData.genesisTimestamp);
}
/**
* @notice Sets permissions for a list of addresses and their roles as well as initialises the PauseManager pauseType:role mappings and fallback operator.
* @dev This function is a reinitializer and can only be called once per version. Should be called using an upgradeAndCall transaction to the ProxyAdmin.
* @param _roleAddresses The list of addresses and roles to assign permissions to.
* @param _pauseTypeRoles The list of pause types to associate with roles.
* @param _unpauseTypeRoles The list of unpause types to associate with roles.
* @param _fallbackOperator The address of the fallback operator.
*/
function reinitializeLineaRollupV6(
RoleAddress[] calldata _roleAddresses,
PauseTypeRole[] calldata _pauseTypeRoles,
PauseTypeRole[] calldata _unpauseTypeRoles,
address _fallbackOperator
) external reinitializer(6) {
__Permissions_init(_roleAddresses);
__PauseManager_init(_pauseTypeRoles, _unpauseTypeRoles);
if (_fallbackOperator == address(0)) {
revert ZeroAddressNotAllowed();
}
fallbackOperator = _fallbackOperator;
emit FallbackOperatorAddressSet(msg.sender, _fallbackOperator);
/// @dev using the constants requires string memory and more complex code.
emit LineaRollupVersionChanged(bytes8("5.0"), bytes8("6.0"));
}
/**
* @notice Revokes `role` from the calling account.
* @dev Fallback operator cannot renounce role. Reverts with OnlyNonFallbackOperator.
* @param _role The role to renounce.
* @param _account The account to renounce - can only be the _msgSender().
*/
function renounceRole(bytes32 _role, address _account) public override {
if (_account == fallbackOperator) {
revert OnlyNonFallbackOperator();
}
super.renounceRole(_role, _account);
}
/**
* @notice Adds or updates the verifier contract address for a proof type.
* @dev VERIFIER_SETTER_ROLE is required to execute.
* @param _newVerifierAddress The address for the verifier contract.
* @param _proofType The proof type being set/updated.
*/
function setVerifierAddress(address _newVerifierAddress, uint256 _proofType) external onlyRole(VERIFIER_SETTER_ROLE) {
if (_newVerifierAddress == address(0)) {
revert ZeroAddressNotAllowed();
}
emit VerifierAddressChanged(_newVerifierAddress, _proofType, msg.sender, verifiers[_proofType]);
verifiers[_proofType] = _newVerifierAddress;
}
/**
* @notice Sets the fallback operator role to the specified address if six months have passed since the last finalization.
* @dev Reverts if six months have not passed since the last finalization.
* @param _messageNumber Last finalized L1 message number as part of the feedback loop.
* @param _rollingHash Last finalized L1 rolling hash as part of the feedback loop.
* @param _lastFinalizedTimestamp Last finalized L2 block timestamp.
*/
function setFallbackOperator(uint256 _messageNumber, bytes32 _rollingHash, uint256 _lastFinalizedTimestamp) external {
if (block.timestamp < _lastFinalizedTimestamp + SIX_MONTHS_IN_SECONDS) {
revert LastFinalizationTimeNotLapsed();
}
if (currentFinalizedState != _computeLastFinalizedState(_messageNumber, _rollingHash, _lastFinalizedTimestamp)) {
revert FinalizationStateIncorrect(
currentFinalizedState,
_computeLastFinalizedState(_messageNumber, _rollingHash, _lastFinalizedTimestamp)
);
}
address fallbackOperatorAddress = fallbackOperator;
_grantRole(OPERATOR_ROLE, fallbackOperatorAddress);
emit FallbackOperatorRoleGranted(msg.sender, fallbackOperatorAddress);
}
/**
* @notice Unset the verifier contract address for a proof type.
* @dev VERIFIER_UNSETTER_ROLE is required to execute.
* @param _proofType The proof type being set/updated.
*/
function unsetVerifierAddress(uint256 _proofType) external onlyRole(VERIFIER_UNSETTER_ROLE) {
emit VerifierAddressChanged(address(0), _proofType, msg.sender, verifiers[_proofType]);
delete verifiers[_proofType];
}
/**
* @notice Submit one or more EIP-4844 blobs.
* @dev OPERATOR_ROLE is required to execute.
* @dev This should be a blob carrying transaction.
* @param _blobSubmissions The data for blob submission including proofs and required polynomials.
* @param _parentShnarf The parent shnarf used in continuity checks as it includes the parentStateRootHash in its computation.
* @param _finalBlobShnarf The expected final shnarf post computation of all the blob shnarfs.
*/
function submitBlobs(
BlobSubmission[] calldata _blobSubmissions,
bytes32 _parentShnarf,
bytes32 _finalBlobShnarf
) external whenTypeAndGeneralNotPaused(PauseType.BLOB_SUBMISSION) onlyRole(OPERATOR_ROLE) {
if (_blobSubmissions.length == 0) {
revert BlobSubmissionDataIsMissing();
}
if (blobhash(_blobSubmissions.length) != EMPTY_HASH) {
revert BlobSubmissionDataEmpty(_blobSubmissions.length);
}
if (blobShnarfExists[_parentShnarf] == 0) {
revert ParentBlobNotSubmitted(_parentShnarf);
}
/**
* @dev validate we haven't submitted the last shnarf. There is a final check at the end of the function verifying,
* that _finalBlobShnarf was computed correctly.
* Note: As only the last shnarf is stored, we don't need to validate shnarfs,
* computed for any previous blobs in the submission (if multiple are submitted).
*/
if (blobShnarfExists[_finalBlobShnarf] != 0) {
revert DataAlreadySubmitted(_finalBlobShnarf);
}
bytes32 currentDataEvaluationPoint;
bytes32 currentDataHash;
/// @dev Assigning in memory saves a lot of gas vs. calldata reading.
BlobSubmission memory blobSubmission;
bytes32 computedShnarf = _parentShnarf;
for (uint256 i; i < _blobSubmissions.length; i++) {
blobSubmission = _blobSubmissions[i];
currentDataHash = blobhash(i);
if (currentDataHash == EMPTY_HASH) {
revert EmptyBlobDataAtIndex(i);
}
bytes32 snarkHash = blobSubmission.snarkHash;
currentDataEvaluationPoint = Utils._efficientKeccak(snarkHash, currentDataHash);
_verifyPointEvaluation(
currentDataHash,
uint256(currentDataEvaluationPoint),
blobSubmission.dataEvaluationClaim,
blobSubmission.kzgCommitment,
blobSubmission.kzgProof
);
computedShnarf = _computeShnarf(
computedShnarf,
snarkHash,
blobSubmission.finalStateRootHash,
currentDataEvaluationPoint,
bytes32(blobSubmission.dataEvaluationClaim)
);
}
if (_finalBlobShnarf != computedShnarf) {
revert FinalShnarfWrong(_finalBlobShnarf, computedShnarf);
}
/// @dev use the last shnarf as the submission to store as technically it becomes the next parent shnarf.
blobShnarfExists[computedShnarf] = SHNARF_EXISTS_DEFAULT_VALUE;
emit DataSubmittedV3(_parentShnarf, computedShnarf, blobSubmission.finalStateRootHash);
}
/**
* @notice Submit blobs using compressed data via calldata.
* @dev OPERATOR_ROLE is required to execute.
* @param _submission The supporting data for compressed data submission including compressed data.
* @param _parentShnarf The parent shnarf used in continuity checks as it includes the parentStateRootHash in its computation.
* @param _expectedShnarf The expected shnarf post computation of all the submission.
*/
function submitDataAsCalldata(
CompressedCalldataSubmission calldata _submission,
bytes32 _parentShnarf,
bytes32 _expectedShnarf
) external whenTypeAndGeneralNotPaused(PauseType.CALLDATA_SUBMISSION) onlyRole(OPERATOR_ROLE) {
if (_submission.compressedData.length == 0) {
revert EmptySubmissionData();
}
if (blobShnarfExists[_expectedShnarf] != 0) {
revert DataAlreadySubmitted(_expectedShnarf);
}
if (blobShnarfExists[_parentShnarf] == 0) {
revert ParentBlobNotSubmitted(_parentShnarf);
}
bytes32 currentDataHash = keccak256(_submission.compressedData);
bytes32 dataEvaluationPoint = Utils._efficientKeccak(_submission.snarkHash, currentDataHash);
bytes32 computedShnarf = _computeShnarf(
_parentShnarf,
_submission.snarkHash,
_submission.finalStateRootHash,
dataEvaluationPoint,
_calculateY(_submission.compressedData, dataEvaluationPoint)
);
if (_expectedShnarf != computedShnarf) {
revert FinalShnarfWrong(_expectedShnarf, computedShnarf);
}
blobShnarfExists[computedShnarf] = SHNARF_EXISTS_DEFAULT_VALUE;
emit DataSubmittedV3(_parentShnarf, computedShnarf, _submission.finalStateRootHash);
}
/**
* @notice Internal function to compute and save the finalization state.
* @dev Using assembly this way is cheaper gas wise.
* @param _messageNumber Is the last L2 computed L1 message number in the finalization.
* @param _rollingHash Is the last L2 computed L1 rolling hash in the finalization.
* @param _timestamp The final timestamp in the finalization.
*/
function _computeLastFinalizedState(
uint256 _messageNumber,
bytes32 _rollingHash,
uint256 _timestamp
) internal pure returns (bytes32 hashedFinalizationState) {
assembly {
let mPtr := mload(0x40)
mstore(mPtr, _messageNumber)
mstore(add(mPtr, 0x20), _rollingHash)
mstore(add(mPtr, 0x40), _timestamp)
hashedFinalizationState := keccak256(mPtr, 0x60)
}
}
/**
* @notice Internal function to compute the shnarf more efficiently.
* @dev Using assembly this way is cheaper gas wise.
* @param _parentShnarf The shnarf of the parent data item.
* @param _snarkHash Is the computed hash for compressed data (using a SNARK-friendly hash function) that aggregates per data submission to be used in public input.
* @param _finalStateRootHash The final state root hash of the data being submitted.
* @param _dataEvaluationPoint The data evaluation point.
* @param _dataEvaluationClaim The data evaluation claim.
*/
function _computeShnarf(
bytes32 _parentShnarf,
bytes32 _snarkHash,
bytes32 _finalStateRootHash,
bytes32 _dataEvaluationPoint,
bytes32 _dataEvaluationClaim
) internal pure returns (bytes32 shnarf) {
assembly {
let mPtr := mload(0x40)
mstore(mPtr, _parentShnarf)
mstore(add(mPtr, 0x20), _snarkHash)
mstore(add(mPtr, 0x40), _finalStateRootHash)
mstore(add(mPtr, 0x60), _dataEvaluationPoint)
mstore(add(mPtr, 0x80), _dataEvaluationClaim)
shnarf := keccak256(mPtr, 0xA0)
}
}
/**
* @notice Performs point evaluation for the compressed blob.
* @dev _dataEvaluationPoint is modular reduced to be lower than the BLS_CURVE_MODULUS for precompile checks.
* @param _currentDataHash The current blob versioned hash.
* @param _dataEvaluationPoint The data evaluation point.
* @param _dataEvaluationClaim The data evaluation claim.
* @param _kzgCommitment The blob KZG commitment.
* @param _kzgProof The blob KZG point proof.
*/
function _verifyPointEvaluation(
bytes32 _currentDataHash,
uint256 _dataEvaluationPoint,
uint256 _dataEvaluationClaim,
bytes memory _kzgCommitment,
bytes memory _kzgProof
) internal view {
assembly {
_dataEvaluationPoint := mod(_dataEvaluationPoint, BLS_CURVE_MODULUS)
}
(bool success, bytes memory returnData) = POINT_EVALUATION_PRECOMPILE_ADDRESS.staticcall(
abi.encodePacked(_currentDataHash, _dataEvaluationPoint, _dataEvaluationClaim, _kzgCommitment, _kzgProof)
);
if (!success) {
revert PointEvaluationFailed();
}
if (returnData.length != POINT_EVALUATION_RETURN_DATA_LENGTH) {
revert PrecompileReturnDataLengthWrong(POINT_EVALUATION_RETURN_DATA_LENGTH, returnData.length);
}
uint256 fieldElements;
uint256 blsCurveModulus;
assembly {
fieldElements := mload(add(returnData, 0x20))
blsCurveModulus := mload(add(returnData, POINT_EVALUATION_RETURN_DATA_LENGTH))
}
if (fieldElements != POINT_EVALUATION_FIELD_ELEMENTS_LENGTH || blsCurveModulus != BLS_CURVE_MODULUS) {
revert PointEvaluationResponseInvalid(fieldElements, blsCurveModulus);
}
}
/**
* @notice Finalize compressed blocks with proof.
* @dev OPERATOR_ROLE is required to execute.
* @param _aggregatedProof The aggregated proof.
* @param _proofType The proof type.
* @param _finalizationData The full finalization data.
*/
function finalizeBlocks(
bytes calldata _aggregatedProof,
uint256 _proofType,
FinalizationDataV3 calldata _finalizationData
) external whenTypeAndGeneralNotPaused(PauseType.FINALIZATION) onlyRole(OPERATOR_ROLE) {
if (_aggregatedProof.length == 0) {
revert ProofIsEmpty();
}
uint256 lastFinalizedBlockNumber = currentL2BlockNumber;
if (stateRootHashes[lastFinalizedBlockNumber] != _finalizationData.parentStateRootHash) {
revert StartingRootHashDoesNotMatch();
}
/// @dev currentFinalizedShnarf is updated in _finalizeBlocks and lastFinalizedShnarf MUST be set beforehand for the transition.
bytes32 lastFinalizedShnarf = currentFinalizedShnarf;
bytes32 finalShnarf = _finalizeBlocks(_finalizationData, lastFinalizedBlockNumber);
uint256 publicInput = _computePublicInput(
_finalizationData,
lastFinalizedShnarf,
finalShnarf,
lastFinalizedBlockNumber,
_finalizationData.endBlockNumber
);
_verifyProof(publicInput, _proofType, _aggregatedProof);
}
/**
* @notice Internal function to finalize compressed blocks.
* @param _finalizationData The full finalization data.
* @param _lastFinalizedBlock The last finalized block.
* @return finalShnarf The final computed shnarf in finalizing.
*/
function _finalizeBlocks(
FinalizationDataV3 calldata _finalizationData,
uint256 _lastFinalizedBlock
) internal returns (bytes32 finalShnarf) {
if (_finalizationData.endBlockNumber <= _lastFinalizedBlock) {
revert FinalBlockNumberLessThanOrEqualToLastFinalizedBlock(_finalizationData.endBlockNumber, _lastFinalizedBlock);
}
_validateL2ComputedRollingHash(_finalizationData.l1RollingHashMessageNumber, _finalizationData.l1RollingHash);
if (
_computeLastFinalizedState(
_finalizationData.lastFinalizedL1RollingHashMessageNumber,
_finalizationData.lastFinalizedL1RollingHash,
_finalizationData.lastFinalizedTimestamp
) != currentFinalizedState
) {
revert FinalizationStateIncorrect(
_computeLastFinalizedState(
_finalizationData.lastFinalizedL1RollingHashMessageNumber,
_finalizationData.lastFinalizedL1RollingHash,
_finalizationData.lastFinalizedTimestamp
),
currentFinalizedState
);
}
if (_finalizationData.finalTimestamp >= block.timestamp) {
revert FinalizationInTheFuture(_finalizationData.finalTimestamp, block.timestamp);
}
if (_finalizationData.shnarfData.finalStateRootHash == EMPTY_HASH) {
revert FinalBlockStateEqualsZeroHash();
}
finalShnarf = _computeShnarf(
_finalizationData.shnarfData.parentShnarf,
_finalizationData.shnarfData.snarkHash,
_finalizationData.shnarfData.finalStateRootHash,
_finalizationData.shnarfData.dataEvaluationPoint,
_finalizationData.shnarfData.dataEvaluationClaim
);
if (blobShnarfExists[finalShnarf] == 0) {
revert FinalBlobNotSubmitted(finalShnarf);
}
_addL2MerkleRoots(_finalizationData.l2MerkleRoots, _finalizationData.l2MerkleTreesDepth);
_anchorL2MessagingBlocks(_finalizationData.l2MessagingBlocksOffsets, _lastFinalizedBlock);
stateRootHashes[_finalizationData.endBlockNumber] = _finalizationData.shnarfData.finalStateRootHash;
currentL2BlockNumber = _finalizationData.endBlockNumber;
currentFinalizedShnarf = finalShnarf;
currentFinalizedState = _computeLastFinalizedState(
_finalizationData.l1RollingHashMessageNumber,
_finalizationData.l1RollingHash,
_finalizationData.finalTimestamp
);
emit DataFinalizedV3(
++_lastFinalizedBlock,
_finalizationData.endBlockNumber,
finalShnarf,
_finalizationData.parentStateRootHash,
_finalizationData.shnarfData.finalStateRootHash
);
}
/**
* @notice Internal function to validate l1 rolling hash.
* @param _rollingHashMessageNumber Message number associated with the rolling hash as computed on L2.
* @param _rollingHash L1 rolling hash as computed on L2.
*/
function _validateL2ComputedRollingHash(uint256 _rollingHashMessageNumber, bytes32 _rollingHash) internal view {
if (_rollingHashMessageNumber == 0) {
if (_rollingHash != EMPTY_HASH) {
revert MissingMessageNumberForRollingHash(_rollingHash);
}
} else {
if (_rollingHash == EMPTY_HASH) {
revert MissingRollingHashForMessageNumber(_rollingHashMessageNumber);
}
if (rollingHashes[_rollingHashMessageNumber] != _rollingHash) {
revert L1RollingHashDoesNotExistOnL1(_rollingHashMessageNumber, _rollingHash);
}
}
}
/**
* @notice Internal function to calculate Y for public input generation.
* @param _data Compressed data from submission data.
* @param _dataEvaluationPoint The data evaluation point.
* @dev Each chunk of 32 bytes must start with a 0 byte.
* @dev The dataEvaluationPoint value is modulo-ed down during the computation and scalar field checking is not needed.
* @dev There is a hard constraint in the circuit to enforce the polynomial degree limit (4096), which will also be enforced with EIP-4844.
* @return compressedDataComputedY The Y calculated value using the Horner method.
*/
function _calculateY(
bytes calldata _data,
bytes32 _dataEvaluationPoint
) internal pure returns (bytes32 compressedDataComputedY) {
if (_data.length % 0x20 != 0) {
revert BytesLengthNotMultipleOf32();
}
bytes4 errorSelector = ILineaRollup.FirstByteIsNotZero.selector;
assembly {
for {
let i := _data.length
} gt(i, 0) {
} {
i := sub(i, 0x20)
let chunk := calldataload(add(_data.offset, i))
if iszero(iszero(and(chunk, 0xFF00000000000000000000000000000000000000000000000000000000000000))) {
let ptr := mload(0x40)
mstore(ptr, errorSelector)
revert(ptr, 0x4)
}
compressedDataComputedY := addmod(
mulmod(compressedDataComputedY, _dataEvaluationPoint, BLS_CURVE_MODULUS),
chunk,
BLS_CURVE_MODULUS
)
}
}
}
/**
* @notice Compute the public input.
* @dev Using assembly this way is cheaper gas wise.
* @dev NB: the dynamic sized fields are placed last in _finalizationData on purpose to optimise hashing ranges.
* @dev Computing the public input as the following:
* keccak256(
* abi.encode(
* _lastFinalizedShnarf,
* _finalShnarf,
* _finalizationData.lastFinalizedTimestamp,
* _finalizationData.finalTimestamp,
* _lastFinalizedBlockNumber,
* _finalizationData.endBlockNumber,
* _finalizationData.lastFinalizedL1RollingHash,
* _finalizationData.l1RollingHash,
* _finalizationData.lastFinalizedL1RollingHashMessageNumber,
* _finalizationData.l1RollingHashMessageNumber,
* _finalizationData.l2MerkleTreesDepth,
* keccak256(
* abi.encodePacked(_finalizationData.l2MerkleRoots)
* )
* )
* )
* Data is found at the following offsets:
* 0x00 parentStateRootHash
* 0x20 endBlockNumber
* 0x40 shnarfData.parentShnarf
* 0x60 shnarfData.snarkHash
* 0x80 shnarfData.finalStateRootHash
* 0xa0 shnarfData.dataEvaluationPoint
* 0xc0 shnarfData.dataEvaluationClaim
* 0xe0 lastFinalizedTimestamp
* 0x100 finalTimestamp
* 0x120 lastFinalizedL1RollingHash
* 0x140 l1RollingHash
* 0x160 lastFinalizedL1RollingHashMessageNumber
* 0x180 l1RollingHashMessageNumber
* 0x1a0 l2MerkleTreesDepth
* 0x1c0 l2MerkleRootsLengthLocation
* 0x1e0 l2MessagingBlocksOffsetsLengthLocation
* Dynamic l2MerkleRootsLength
* Dynamic l2MerkleRoots
* Dynamic l2MessagingBlocksOffsetsLength (location depends on where l2MerkleRoots ends)
* Dynamic l2MessagingBlocksOffsets (location depends on where l2MerkleRoots ends)
* @param _finalizationData The full finalization data.
* @param _finalShnarf The final shnarf in the finalization.
* @param _lastFinalizedBlockNumber The last finalized block number.
* @param _endBlockNumber End block number being finalized.
*/
function _computePublicInput(
FinalizationDataV3 calldata _finalizationData,
bytes32 _lastFinalizedShnarf,
bytes32 _finalShnarf,
uint256 _lastFinalizedBlockNumber,
uint256 _endBlockNumber
) private pure returns (uint256 publicInput) {
assembly {
let mPtr := mload(0x40)
mstore(mPtr, _lastFinalizedShnarf)
mstore(add(mPtr, 0x20), _finalShnarf)
/**
* _finalizationData.lastFinalizedTimestamp
* _finalizationData.finalTimestamp
*/
calldatacopy(add(mPtr, 0x40), add(_finalizationData, 0xe0), 0x40)
mstore(add(mPtr, 0x80), _lastFinalizedBlockNumber)
// _finalizationData.endBlockNumber
mstore(add(mPtr, 0xA0), _endBlockNumber)
/**
* _finalizationData.lastFinalizedL1RollingHash
* _finalizationData.l1RollingHash
* _finalizationData.lastFinalizedL1RollingHashMessageNumber
* _finalizationData.l1RollingHashMessageNumber
* _finalizationData.l2MerkleTreesDepth
*/
calldatacopy(add(mPtr, 0xC0), add(_finalizationData, 0x120), 0xA0)
/**
* @dev Note the following in hashing the _finalizationData.l2MerkleRoots array:
* The second memory pointer and free pointer are offset by 0x20 to temporarily hash the array outside the scope of working memory,
* as we need the space left for the array hash to be stored at 0x160.
*/
let mPtrMerkleRoot := add(mPtr, 0x180)
let merkleRootsLengthLocation := add(_finalizationData, calldataload(add(_finalizationData, 0x1c0)))
let merkleRootsLen := calldataload(merkleRootsLengthLocation)
calldatacopy(mPtrMerkleRoot, add(merkleRootsLengthLocation, 0x20), mul(merkleRootsLen, 0x20))
let l2MerkleRootsHash := keccak256(mPtrMerkleRoot, mul(merkleRootsLen, 0x20))
mstore(add(mPtr, 0x160), l2MerkleRootsHash)
publicInput := mod(keccak256(mPtr, 0x180), MODULO_R)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(account),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// 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;
}
}// 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);
}
}
}// 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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @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;
}// 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 IERC165Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/BitMaps.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
* Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
*/
library BitMaps {
struct BitMap {
mapping(uint256 => uint256) _data;
}
/**
* @dev Returns whether the bit at `index` is set.
*/
function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
return bitmap._data[bucket] & mask != 0;
}
/**
* @dev Sets the bit at `index` to the boolean `value`.
*/
function setTo(BitMap storage bitmap, uint256 index, bool value) internal {
if (value) {
set(bitmap, index);
} else {
unset(bitmap, index);
}
}
/**
* @dev Sets the bit at `index`.
*/
function set(BitMap storage bitmap, uint256 index) internal {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
bitmap._data[bucket] |= mask;
}
/**
* @dev Unsets the bit at `index`.
*/
function unset(BitMap storage bitmap, uint256 index) internal {
uint256 bucket = index >> 8;
uint256 mask = 1 << (index & 0xff);
bitmap._data[bucket] &= ~mask;
}
}// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Interface declaring generic errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IGenericErrors { /** * @dev Thrown when a parameter is the zero address. */ error ZeroAddressNotAllowed(); /** * @dev Thrown when a parameter is the zero hash. */ error ZeroHashNotAllowed(); /** * @dev Thrown when array lengths are mismatched. */ error ArrayLengthsDoNotMatch(); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Interface declaring pre-existing cross-chain messaging functions, events and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IMessageService { /** * @notice Emitted when a message is sent. * @param _from The indexed sender address of the message (msg.sender). * @param _to The indexed intended recipient address of the message on the other layer. * @param _fee The fee being being paid to deliver the message to the recipient in Wei. * @param _value The value being sent to the recipient in Wei. * @param _nonce The unique message number. * @param _calldata The calldata being passed to the intended recipient when being called on claiming. * @param _messageHash The indexed hash of the message parameters. * @dev _calldata has the _ because calldata is a reserved word. * @dev We include the message hash to save hashing costs on the rollup. * @dev This event is used on both L1 and L2. */ event MessageSent( address indexed _from, address indexed _to, uint256 _fee, uint256 _value, uint256 _nonce, bytes _calldata, bytes32 indexed _messageHash ); /** * @notice Emitted when a message is claimed. * @param _messageHash The indexed hash of the message that was claimed. */ event MessageClaimed(bytes32 indexed _messageHash); /** * @dev Thrown when fees are lower than the minimum fee. */ error FeeTooLow(); /** * @dev Thrown when the value sent is less than the fee. * @dev Value to forward on is msg.value - _fee. */ error ValueSentTooLow(); /** * @dev Thrown when the destination address reverts. */ error MessageSendingFailed(address destination); /** * @dev Thrown when the recipient address reverts. */ error FeePaymentFailed(address recipient); /** * @notice Sends a message for transporting from the given chain. * @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain. * @param _to The destination address on the destination chain. * @param _fee The message service fee on the origin chain. * @param _calldata The calldata used by the destination message service to call the destination contract. */ function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable; /** * @notice Deliver a message to the destination chain. * @notice Is called by the Postman, dApp or end user. * @param _from The msg.sender calling the origin message service. * @param _to The destination address on the destination chain. * @param _value The value to be transferred to the destination address. * @param _fee The message service fee on the origin chain. * @param _feeRecipient Address that will receive the fees. * @param _calldata The calldata used by the destination message service to call/forward to the destination contract. * @param _nonce Unique message number. */ function claimMessage( address _from, address _to, uint256 _fee, uint256 _value, address payable _feeRecipient, bytes calldata _calldata, uint256 _nonce ) external; /** * @notice Returns the original sender of the message on the origin layer. * @return originalSender The original sender of the message on the origin layer. */ function sender() external view returns (address originalSender); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Interface declaring pre-existing pausing functions, events and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IPauseManager { /** * @notice Structure defining a pause type and its associated role. * @dev This struct is used for both the `_pauseTypeRoles` and `_unPauseTypeRoles` mappings. * @param pauseType The type of pause. * @param role The role associated with the pause type. */ struct PauseTypeRole { PauseType pauseType; bytes32 role; } /** * @notice Enum defining the different types of pausing. * @dev The pause types are used to pause and unpause specific functionality. * @dev The UNUSED pause type is used as a default value to avoid accidental general pausing. * @dev Enums are uint8 by default. */ enum PauseType { UNUSED, GENERAL, L1_L2, L2_L1, BLOB_SUBMISSION, CALLDATA_SUBMISSION, FINALIZATION, INITIATE_TOKEN_BRIDGING, COMPLETE_TOKEN_BRIDGING } /** * @notice Emitted when a pause type is paused. * @param messageSender The address performing the pause. * @param pauseType The indexed pause type that was paused. */ event Paused(address messageSender, PauseType indexed pauseType); /** * @notice Emitted when a pause type is unpaused. * @param messageSender The address performing the unpause. * @param pauseType The indexed pause type that was unpaused. */ event UnPaused(address messageSender, PauseType indexed pauseType); /** * @notice Emitted when a pause type and its associated role are set in the `_pauseTypeRoles` mapping. * @param pauseType The indexed type of pause. * @param role The indexed role associated with the pause type. */ event PauseTypeRoleSet(PauseType indexed pauseType, bytes32 indexed role); /** * @notice Emitted when an unpause type and its associated role are set in the `_unPauseTypeRoles` mapping. * @param unPauseType The indexed type of unpause. * @param role The indexed role associated with the unpause type. */ event UnPauseTypeRoleSet(PauseType indexed unPauseType, bytes32 indexed role); /** * @dev Thrown when a specific pause type is paused. */ error IsPaused(PauseType pauseType); /** * @dev Thrown when a specific pause type is not paused and expected to be. */ error IsNotPaused(PauseType pauseType); /** * @notice Pauses functionality by specific type. * @dev Requires the role mapped in pauseTypeRoles for the pauseType. * @param _pauseType The pause type value. */ function pauseByType(PauseType _pauseType) external; /** * @notice Unpauses functionality by specific type. * @dev Requires the role mapped in unPauseTypeRoles for the pauseType. * @param _pauseType The pause type value. */ function unPauseByType(PauseType _pauseType) external; /** * @notice Check if a pause type is enabled. * @param _pauseType The pause type value. * @return pauseTypeIsPaused Returns true if the pause type if paused, false otherwise. */ function isPaused(PauseType _pauseType) external view returns (bool pauseTypeIsPaused); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Interface declaring permissions manager related data types. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IPermissionsManager { /** * @notice Structure defining a role and its associated address. * @param addressWithRole The address with the role. * @param role The role associated with the address. */ struct RoleAddress { address addressWithRole; bytes32 role; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Interface declaring rate limiting messaging functions, events and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IRateLimiter { /** * @notice Emitted when the Rate Limit is initialized. * @param periodInSeconds The time period in seconds the rate limiter has been initialized to. * @param limitInWei The limit in Wei the rate limiter has been initialized to. * @param currentPeriodEnd The time the current rate limit period will end. */ event RateLimitInitialized(uint256 periodInSeconds, uint256 limitInWei, uint256 currentPeriodEnd); /** * @notice Emitted when the amount in the period is reset to zero. * @param resettingAddress The indexed address of who reset the used amount back to zero. */ event AmountUsedInPeriodReset(address indexed resettingAddress); /** * @notice Emitted when the limit is changed. * @param amountChangeBy The indexed address of who changed the rate limit. * @param amount The rate limited amount in Wei that was set. * @param amountUsedLoweredToLimit Indicates if the amount used was lowered to the limit to avoid confusion. * @param usedAmountResetToZero Indicates if the amount used was set to zero because of the current period expiring. * @dev If the current used amount is higher than the new limit, the used amount is lowered to the limit. * @dev amountUsedLoweredToLimit and usedAmountResetToZero cannot be true at the same time. */ event LimitAmountChanged( address indexed amountChangeBy, uint256 amount, bool amountUsedLoweredToLimit, bool usedAmountResetToZero ); /** * @dev Thrown when an amount breaches the limit in the period. */ error RateLimitExceeded(); /** * @dev Thrown when the period is initialised to zero. */ error PeriodIsZero(); /** * @dev Thrown when the limit is initialised to zero. */ error LimitIsZero(); /** * @notice Resets the rate limit amount. * @dev If the used amount is higher, it is set to the limit to avoid confusion/issues. * @dev Only the RATE_LIMIT_SETTER_ROLE is allowed to execute this function. * @dev Emits the LimitAmountChanged event. * @dev usedLimitAmountToSet will use the default value of zero if period has expired. * @param _amount The amount to reset the limit to. */ function resetRateLimitAmount(uint256 _amount) external; /** * @notice Resets the amount used to zero. * @dev Only the USED_RATE_LIMIT_RESETTER_ROLE is allowed to execute this function. * @dev Emits the AmountUsedInPeriodReset event. */ function resetAmountUsedInPeriod() external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.26; /** * @title L1 Message manager interface for current functions, events and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IL1MessageManager { /** * @notice Emitted when a new message is sent and the rolling hash updated. * @param messageNumber The unique indexed message number for the message. * @param rollingHash The indexed rolling hash computed for the current message number. * @param messageHash The indexed hash of the message parameters. */ event RollingHashUpdated(uint256 indexed messageNumber, bytes32 indexed rollingHash, bytes32 indexed messageHash); /** * @notice Emitted when the L2 Merkle root has been anchored on L1. * @param l2MerkleRoot The indexed L2 Merkle root that has been anchored on L1 Ethereum. * @param treeDepth The indexed tree depth of the Merkle root. * @dev There may be more than one of these in a finalization depending on the amount of L2->L1 messages in the finalization. */ event L2MerkleRootAdded(bytes32 indexed l2MerkleRoot, uint256 indexed treeDepth); /** * @notice Emitted when the L2 block contains L2 messages during finalization. * @param l2Block The indexed L2 block containing L2 to L1 messages. * @dev This is used externally in the logic for determining which messages belong to which Merkle root when claiming. */ event L2MessagingBlockAnchored(uint256 indexed l2Block); /** * @dev Thrown when the message has already been claimed. */ error MessageAlreadyClaimed(uint256 messageIndex); /** * @dev Thrown when the L2 Merkle root has already been anchored on L1. */ error L2MerkleRootAlreadyAnchored(bytes32 merkleRoot); /** * @dev Thrown when the L2 messaging blocks offsets bytes length is not a multiple of 2. */ error BytesLengthNotMultipleOfTwo(uint256 bytesLength); /** * @notice Checks if the L2->L1 message is claimed or not. * @param _messageNumber The message number on L2. * @return isClaimed Returns whether or not the message with _messageNumber has been claimed. */ function isMessageClaimed(uint256 _messageNumber) external view returns (bool isClaimed); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.26; /** * @title L1 Message manager V1 interface for pre-existing errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IL1MessageManagerV1 { /** * @dev Thrown when the message has already been claimed. */ error MessageDoesNotExistOrHasAlreadyBeenClaimed(bytes32 messageHash); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.26; /** * @title L1 Message Service interface for pre-existing functions, events, structs and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IL1MessageService { /** * @param proof The Merkle proof array related to the claimed message. * @param messageNumber The message number of the claimed message. * @param leafIndex The leaf index related to the Merkle proof of the message. * @param from The address of the original sender. * @param to The address the message is intended for. * @param fee The fee being paid for the message delivery. * @param value The value to be transferred to the destination address. * @param feeRecipient The recipient for the fee. * @param merkleRoot The Merkle root of the claimed message. * @param data The calldata to pass to the recipient. */ struct ClaimMessageWithProofParams { bytes32[] proof; uint256 messageNumber; uint32 leafIndex; address from; address to; uint256 fee; uint256 value; address payable feeRecipient; bytes32 merkleRoot; bytes data; } /** * @dev Thrown when L2 Merkle root does not exist. */ error L2MerkleRootDoesNotExist(); /** * @dev Thrown when the Merkle proof is invalid. */ error InvalidMerkleProof(); /** * @dev Thrown when Merkle depth doesn't match proof length. */ error ProofLengthDifferentThanMerkleDepth(uint256 actual, uint256 expected); /** * @notice Claims and delivers a cross-chain message using a Merkle proof. * @dev if tree depth is empty, it will revert with L2MerkleRootDoesNotExist. * @dev if tree depth is different than proof size, it will revert with ProofLengthDifferentThanMerkleDepth. * @param _params Collection of claim data with proof and supporting data. */ function claimMessageWithProof(ClaimMessageWithProofParams calldata _params) external; }
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.26;
import { IPauseManager } from "../../interfaces/IPauseManager.sol";
import { IPermissionsManager } from "../../interfaces/IPermissionsManager.sol";
/**
* @title LineaRollup interface for current functions, structs, events and errors.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
interface ILineaRollup {
/**
* @notice Initialization data structure for the LineaRollup contract.
* @param initialStateRootHash The initial state root hash at initialization used for proof verification.
* @param initialL2BlockNumber The initial block number at initialization.
* @param genesisTimestamp The L2 genesis timestamp for first initialization.
* @param defaultVerifier The default verifier for rollup proofs.
* @param rateLimitPeriodInSeconds The period in which withdrawal amounts and fees will be accumulated.
* @param rateLimitAmountInWei The limit allowed for withdrawing in the rate limit period.
* @param roleAddresses The list of role address and roles to assign permissions to.
* @param pauseTypeRoles The list of pause types to associate with roles.
* @param unpauseTypeRoles The list of unpause types to associate with roles.
* @param fallbackOperator The account to be given OPERATOR_ROLE on when the time since last finalization lapses.
* @param defaultAdmin The account to be given DEFAULT_ADMIN_ROLE on initialization.
*/
struct InitializationData {
bytes32 initialStateRootHash;
uint256 initialL2BlockNumber;
uint256 genesisTimestamp;
address defaultVerifier;
uint256 rateLimitPeriodInSeconds;
uint256 rateLimitAmountInWei;
IPermissionsManager.RoleAddress[] roleAddresses;
IPauseManager.PauseTypeRole[] pauseTypeRoles;
IPauseManager.PauseTypeRole[] unpauseTypeRoles;
address fallbackOperator;
address defaultAdmin;
}
/**
* @notice Supporting data for compressed calldata submission including compressed data.
* @dev finalStateRootHash is used to set state root at the end of the data.
* @dev snarkHash is the computed hash for compressed data (using a SNARK-friendly hash function) that aggregates per data submission to be used in public input.
* @dev compressedData is the compressed transaction data. It contains ordered data for each L2 block - l2Timestamps, the encoded transaction data.
*/
struct CompressedCalldataSubmission {
bytes32 finalStateRootHash;
bytes32 snarkHash;
bytes compressedData;
}
/**
* @notice Shnarf data for validating a shnarf.
* @dev parentShnarf is the parent computed shnarf.
* @dev snarkHash is the computed hash for compressed data (using a SNARK-friendly hash function) that aggregates per data submission to be used in public input.
* @dev finalStateRootHash is the final state root hash.
* @dev dataEvaluationPoint is the data evaluation point.
* @dev dataEvaluationClaim is the data evaluation claim.
*/
struct ShnarfData {
bytes32 parentShnarf;
bytes32 snarkHash;
bytes32 finalStateRootHash;
bytes32 dataEvaluationPoint;
bytes32 dataEvaluationClaim;
}
/**
* @notice Data stucture for compressed blob data submission.
* @dev submissionData The supporting data for blob data submission excluding the compressed data.
* @dev dataEvaluationClaim The data evaluation claim.
* @dev kzgCommitment The blob KZG commitment.
* @dev kzgProof The blob KZG point proof.
*/
struct BlobSubmission {
uint256 dataEvaluationClaim;
bytes kzgCommitment;
bytes kzgProof;
bytes32 finalStateRootHash;
bytes32 snarkHash;
}
/**
* @notice Supporting data for finalization with proof.
* @dev NB: the dynamic sized fields are placed last on purpose for efficient keccaking on public input.
* @dev parentStateRootHash is the expected last state root hash finalized.
* @dev endBlockNumber is the end block finalizing until.
* @dev shnarfData contains data about the last data submission's shnarf used in finalization.
* @dev lastFinalizedTimestamp is the expected last finalized block's timestamp.
* @dev finalTimestamp is the timestamp of the last block being finalized.
* @dev lastFinalizedL1RollingHash is the last stored L2 computed rolling hash used in finalization.
* @dev l1RollingHash is the calculated rolling hash on L2 that is expected to match L1 at l1RollingHashMessageNumber.
* This value will be used along with the stored last finalized L2 calculated rolling hash in the public input.
* @dev lastFinalizedL1RollingHashMessageNumber is the last stored L2 computed message number used in finalization.
* @dev l1RollingHashMessageNumber is the calculated message number on L2 that is expected to match the existing L1 rolling hash.
* This value will be used along with the stored last finalized L2 calculated message number in the public input.
* @dev l2MerkleTreesDepth is the depth of all l2MerkleRoots.
* @dev l2MerkleRoots is an array of L2 message Merkle roots of depth l2MerkleTreesDepth between last finalized block and finalSubmissionData.finalBlockNumber.
* @dev l2MessagingBlocksOffsets indicates by offset from currentL2BlockNumber which L2 blocks contain MessageSent events.
*/
struct FinalizationDataV3 {
bytes32 parentStateRootHash;
uint256 endBlockNumber;
ShnarfData shnarfData;
uint256 lastFinalizedTimestamp;
uint256 finalTimestamp;
bytes32 lastFinalizedL1RollingHash;
bytes32 l1RollingHash;
uint256 lastFinalizedL1RollingHashMessageNumber;
uint256 l1RollingHashMessageNumber;
uint256 l2MerkleTreesDepth;
bytes32[] l2MerkleRoots;
bytes l2MessagingBlocksOffsets;
}
/**
* @notice Emitted when the LineaRollup contract version has changed.
* @dev All bytes8 values are string based SemVer in the format M.m - e.g. "6.0".
* @param previousVersion The previous version.
* @param newVersion The new version.
*/
event LineaRollupVersionChanged(bytes8 indexed previousVersion, bytes8 indexed newVersion);
/**
* @notice Emitted when the fallback operator role is granted.
* @param caller The address that called the function granting the role.
* @param fallbackOperator The fallback operator address that received the operator role.
*/
event FallbackOperatorRoleGranted(address indexed caller, address indexed fallbackOperator);
/**
* @notice Emitted when the fallback operator role is set on the contract.
* @param caller The address that set the fallback operator address.
* @param fallbackOperator The fallback operator address.
*/
event FallbackOperatorAddressSet(address indexed caller, address indexed fallbackOperator);
/**
* @notice Emitted when a verifier is set for a particular proof type.
* @param verifierAddress The indexed new verifier address being set.
* @param proofType The indexed proof type/index that the verifier is mapped to.
* @param verifierSetBy The index address who set the verifier at the mapping.
* @param oldVerifierAddress Indicates the previous address mapped to the proof type.
* @dev The verifier will be set by an account with the VERIFIER_SETTER_ROLE. Typically the Safe.
* @dev The oldVerifierAddress can be the zero address.
*/
event VerifierAddressChanged(
address indexed verifierAddress,
uint256 indexed proofType,
address indexed verifierSetBy,
address oldVerifierAddress
);
/**
* @notice Emitted when compressed data is being submitted and verified succesfully on L1.
* @dev The block range is indexed and parent shnarf included for state reconstruction simplicity.
* @param parentShnarf The parent shnarf for the data being submitted.
* @param shnarf The indexed shnarf for the data being submitted.
* @param finalStateRootHash The L2 state root hash that the current blob submission ends on. NB: The last blob in the collection.
*/
event DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash);
/**
* @notice Emitted when L2 blocks have been finalized on L1.
* @param startBlockNumber The indexed L2 block number indicating which block the finalization the data starts from.
* @param endBlockNumber The indexed L2 block number indicating which block the finalization the data ends on.
* @param shnarf The indexed shnarf being set as currentFinalizedShnarf in the current finalization.
* @param parentStateRootHash The parent L2 state root hash that the current finalization starts from.
* @param finalStateRootHash The L2 state root hash that the current finalization ends on.
*/
event DataFinalizedV3(
uint256 indexed startBlockNumber,
uint256 indexed endBlockNumber,
bytes32 indexed shnarf,
bytes32 parentStateRootHash,
bytes32 finalStateRootHash
);
/**
* @dev Thrown when the last finalization time has not lapsed when trying to grant the OPERATOR_ROLE to the fallback operator address.
*/
error LastFinalizationTimeNotLapsed();
/**
* @dev Thrown when the point evaluation precompile's call return data field(s) are wrong.
*/
error PointEvaluationResponseInvalid(uint256 fieldElements, uint256 blsCurveModulus);
/**
* @dev Thrown when the point evaluation precompile's call return data length is wrong.
*/
error PrecompileReturnDataLengthWrong(uint256 expected, uint256 actual);
/**
* @dev Thrown when the point evaluation precompile call returns false.
*/
error PointEvaluationFailed();
/**
* @dev Thrown when the blobhash at an index equals to the zero hash.
*/
error EmptyBlobDataAtIndex(uint256 index);
/**
* @dev Thrown when the data for multiple blobs submission has length zero.
*/
error BlobSubmissionDataIsMissing();
/**
* @dev Thrown when a blob has been submitted but there is no data for it.
*/
error BlobSubmissionDataEmpty(uint256 emptyBlobIndex);
/**
* @dev Thrown when the current data was already submitted.
*/
error DataAlreadySubmitted(bytes32 currentDataHash);
/**
* @dev Thrown when submissionData is empty.
*/
error EmptySubmissionData();
/**
* @dev Thrown when finalizationData.l1RollingHash does not exist on L1 (Feedback loop).
*/
error L1RollingHashDoesNotExistOnL1(uint256 messageNumber, bytes32 rollingHash);
/**
* @dev Thrown when finalization state does not match.
*/
error FinalizationStateIncorrect(bytes32 expected, bytes32 value);
/**
* @dev Thrown when the final block number in finalization data is less than or equal to the last finalized block during finalization.
*/
error FinalBlockNumberLessThanOrEqualToLastFinalizedBlock(uint256 finalBlockNumber, uint256 lastFinalizedBlock);
/**
* @dev Thrown when the final block state equals the zero hash during finalization.
*/
error FinalBlockStateEqualsZeroHash();
/**
* @dev Thrown when final l2 block timestamp higher than current block.timestamp during finalization.
*/
error FinalizationInTheFuture(uint256 l2BlockTimestamp, uint256 currentBlockTimestamp);
/**
* @dev Thrown when a rolling hash is provided without a corresponding message number.
*/
error MissingMessageNumberForRollingHash(bytes32 rollingHash);
/**
* @dev Thrown when a message number is provided without a corresponding rolling hash.
*/
error MissingRollingHashForMessageNumber(uint256 messageNumber);
/**
* @dev Thrown when the first byte is not zero.
* @dev This is used explicitly with the four bytes in assembly 0x729eebce.
*/
error FirstByteIsNotZero();
/**
* @dev Thrown when bytes length is not a multiple of 32.
*/
error BytesLengthNotMultipleOf32();
/**
* @dev Thrown when the computed shnarf does not match what is expected.
*/
error FinalShnarfWrong(bytes32 expected, bytes32 value);
/**
* @dev Thrown when a shnarf does not exist for a parent blob.
*/
error ParentBlobNotSubmitted(bytes32 shnarf);
/**
* @dev Thrown when a shnarf does not exist for the final blob being finalized.
*/
error FinalBlobNotSubmitted(bytes32 shnarf);
/**
* @dev Thrown when the fallback operator tries to renounce their operator role.
*/
error OnlyNonFallbackOperator();
/**
* @notice Adds or updates the verifier contract address for a proof type.
* @dev VERIFIER_SETTER_ROLE is required to execute.
* @param _newVerifierAddress The address for the verifier contract.
* @param _proofType The proof type being set/updated.
*/
function setVerifierAddress(address _newVerifierAddress, uint256 _proofType) external;
/**
* @notice Sets the fallback operator role to the specified address if six months have passed since the last finalization.
* @dev Reverts if six months have not passed since the last finalization.
* @param _messageNumber Last finalized L1 message number as part of the feedback loop.
* @param _rollingHash Last finalized L1 rolling hash as part of the feedback loop.
* @param _lastFinalizedTimestamp Last finalized L2 block timestamp.
*/
function setFallbackOperator(uint256 _messageNumber, bytes32 _rollingHash, uint256 _lastFinalizedTimestamp) external;
/**
* @notice Unsets the verifier contract address for a proof type.
* @dev VERIFIER_UNSETTER_ROLE is required to execute.
* @param _proofType The proof type being set/updated.
*/
function unsetVerifierAddress(uint256 _proofType) external;
/**
* @notice Submit one or more EIP-4844 blobs.
* @dev OPERATOR_ROLE is required to execute.
* @dev This should be a blob carrying transaction.
* @param _blobSubmissions The data for blob submission including proofs and required polynomials.
* @param _parentShnarf The parent shnarf used in continuity checks as it includes the parentStateRootHash in its computation.
* @param _finalBlobShnarf The expected final shnarf post computation of all the blob shnarfs.
*/
function submitBlobs(
BlobSubmission[] calldata _blobSubmissions,
bytes32 _parentShnarf,
bytes32 _finalBlobShnarf
) external;
/**
* @notice Submit blobs using compressed data via calldata.
* @dev OPERATOR_ROLE is required to execute.
* @param _submission The supporting data for compressed data submission including compressed data.
* @param _parentShnarf The parent shnarf used in continuity checks as it includes the parentStateRootHash in its computation.
* @param _expectedShnarf The expected shnarf post computation of all the submission.
*/
function submitDataAsCalldata(
CompressedCalldataSubmission calldata _submission,
bytes32 _parentShnarf,
bytes32 _expectedShnarf
) external;
/**
* @notice Finalize compressed blocks with proof.
* @dev OPERATOR_ROLE is required to execute.
* @param _aggregatedProof The aggregated proof.
* @param _proofType The proof type.
* @param _finalizationData The full finalization data.
*/
function finalizeBlocks(
bytes calldata _aggregatedProof,
uint256 _proofType,
FinalizationDataV3 calldata _finalizationData
) external;
}// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.26; /** * @title Interface declaring verifier functions. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IPlonkVerifier { /** * @notice Interface for verifier contracts. * @param _proof The proof used to verify. * @param _public_inputs The computed public inputs for the proof verification. * @return success Returns true if successfully verified. */ function Verify(bytes calldata _proof, uint256[] calldata _public_inputs) external returns (bool success); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.26; /** * @title ZkEvm rollup interface for pre-existing functions, events and errors. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ interface IZkEvmV2 { /** * @dev Thrown when the starting rootHash does not match the existing state. */ error StartingRootHashDoesNotMatch(); /** * @dev Thrown when zk proof is empty bytes. */ error ProofIsEmpty(); /** * @dev Thrown when zk proof type is invalid. */ error InvalidProofType(); /** * @dev Thrown when zk proof is invalid. */ error InvalidProof(); /** * @dev Thrown when the call to the verifier runs out of gas or reverts internally. */ error InvalidProofOrProofVerificationRanOutOfGas(string errorReason); }
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
import { PauseManager } from "./PauseManager.sol";
/**
* @title Contract to manage cross-chain function pausing roles for the LineaRollup.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract LineaRollupPauseManager is PauseManager {
/// @notice This is used to pause L1 to L2 communication.
bytes32 public constant PAUSE_L1_L2_ROLE = keccak256("PAUSE_L1_L2_ROLE");
/// @notice This is used to unpause L1 to L2 communication.
bytes32 public constant UNPAUSE_L1_L2_ROLE = keccak256("UNPAUSE_L1_L2_ROLE");
/// @notice This is used to pause L2 to L1 communication.
bytes32 public constant PAUSE_L2_L1_ROLE = keccak256("PAUSE_L2_L1_ROLE");
/// @notice This is used to unpause L2 to L1 communication.
bytes32 public constant UNPAUSE_L2_L1_ROLE = keccak256("UNPAUSE_L2_L1_ROLE");
/// @notice This is used to pause blob submission.
bytes32 public constant PAUSE_BLOB_SUBMISSION_ROLE = keccak256("PAUSE_BLOB_SUBMISSION_ROLE");
/// @notice This is used to unpause blob submission.
bytes32 public constant UNPAUSE_BLOB_SUBMISSION_ROLE = keccak256("UNPAUSE_BLOB_SUBMISSION_ROLE");
/// @notice This is used to pause finalization submission.
bytes32 public constant PAUSE_FINALIZATION_ROLE = keccak256("PAUSE_FINALIZATION_ROLE");
/// @notice This is used to unpause finalization submission.
bytes32 public constant UNPAUSE_FINALIZATION_ROLE = keccak256("UNPAUSE_FINALIZATION_ROLE");
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { IPauseManager } from "../interfaces/IPauseManager.sol";
/**
* @title Contract to manage cross-chain function pausing.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract PauseManager is Initializable, IPauseManager, AccessControlUpgradeable {
/// @notice This is used to pause all pausable functions.
bytes32 public constant PAUSE_ALL_ROLE = keccak256("PAUSE_ALL_ROLE");
/// @notice This is used to unpause all unpausable functions.
bytes32 public constant UNPAUSE_ALL_ROLE = keccak256("UNPAUSE_ALL_ROLE");
// @dev DEPRECATED. USE _pauseTypeStatusesBitMap INSTEAD
mapping(bytes32 pauseType => bool pauseStatus) public pauseTypeStatuses;
/// @dev The bitmap containing the pause statuses mapped by type.
uint256 private _pauseTypeStatusesBitMap;
/// @dev This maps the pause type to the role that is allowed to pause it.
mapping(PauseType pauseType => bytes32 role) private _pauseTypeRoles;
/// @dev This maps the unpause type to the role that is allowed to unpause it.
mapping(PauseType unPauseType => bytes32 role) private _unPauseTypeRoles;
/// @dev Total contract storage is 11 slots with the gap below.
/// @dev Keep 7 free storage slots for future implementation updates to avoid storage collision.
/// @dev Note: This was reduced previously to cater for new functionality.
uint256[7] private __gap;
/**
* @dev Modifier to make a function callable only when the specific and general types are not paused.
* @param _pauseType The pause type value being checked.
* Requirements:
*
* - The type must not be paused.
*/
modifier whenTypeAndGeneralNotPaused(PauseType _pauseType) {
_requireTypeAndGeneralNotPaused(_pauseType);
_;
}
/**
* @dev Modifier to make a function callable only when the type is not paused.
* @param _pauseType The pause type value being checked.
* Requirements:
*
* - The type must not be paused.
*/
modifier whenTypeNotPaused(PauseType _pauseType) {
_requireTypeNotPaused(_pauseType);
_;
}
/**
* @notice Initializes the pause manager with the given pause and unpause roles.
* @dev This function is called during contract initialization to set up the pause and unpause roles.
* @param _pauseTypeRoleAssignments An array of PauseTypeRole structs defining the pause types and their associated roles.
* @param _unpauseTypeRoleAssignments An array of PauseTypeRole structs defining the unpause types and their associated roles.
*/
function __PauseManager_init(
PauseTypeRole[] calldata _pauseTypeRoleAssignments,
PauseTypeRole[] calldata _unpauseTypeRoleAssignments
) internal onlyInitializing {
for (uint256 i; i < _pauseTypeRoleAssignments.length; i++) {
_pauseTypeRoles[_pauseTypeRoleAssignments[i].pauseType] = _pauseTypeRoleAssignments[i].role;
emit PauseTypeRoleSet(_pauseTypeRoleAssignments[i].pauseType, _pauseTypeRoleAssignments[i].role);
}
for (uint256 i; i < _unpauseTypeRoleAssignments.length; i++) {
_unPauseTypeRoles[_unpauseTypeRoleAssignments[i].pauseType] = _unpauseTypeRoleAssignments[i].role;
emit UnPauseTypeRoleSet(_unpauseTypeRoleAssignments[i].pauseType, _unpauseTypeRoleAssignments[i].role);
}
}
/**
* @dev Throws if the specific or general types are paused.
* @dev Checks the specific and general pause types.
* @param _pauseType The pause type value being checked.
*/
function _requireTypeAndGeneralNotPaused(PauseType _pauseType) internal view virtual {
uint256 pauseBitMap = _pauseTypeStatusesBitMap;
if (pauseBitMap & (1 << uint256(_pauseType)) != 0) {
revert IsPaused(_pauseType);
}
if (pauseBitMap & (1 << uint256(PauseType.GENERAL)) != 0) {
revert IsPaused(PauseType.GENERAL);
}
}
/**
* @dev Throws if the type is paused.
* @dev Checks the specific pause type.
* @param _pauseType The pause type value being checked.
*/
function _requireTypeNotPaused(PauseType _pauseType) internal view virtual {
if (isPaused(_pauseType)) {
revert IsPaused(_pauseType);
}
}
/**
* @notice Pauses functionality by specific type.
* @dev Requires the role mapped in `_pauseTypeRoles` for the pauseType.
* @param _pauseType The pause type value.
*/
function pauseByType(PauseType _pauseType) external onlyRole(_pauseTypeRoles[_pauseType]) {
if (isPaused(_pauseType)) {
revert IsPaused(_pauseType);
}
_pauseTypeStatusesBitMap |= 1 << uint256(_pauseType);
emit Paused(_msgSender(), _pauseType);
}
/**
* @notice Unpauses functionality by specific type.
* @dev Requires the role mapped in `_unPauseTypeRoles` for the pauseType.
* @param _pauseType The pause type value.
*/
function unPauseByType(PauseType _pauseType) external onlyRole(_unPauseTypeRoles[_pauseType]) {
if (!isPaused(_pauseType)) {
revert IsNotPaused(_pauseType);
}
_pauseTypeStatusesBitMap &= ~(1 << uint256(_pauseType));
emit UnPaused(_msgSender(), _pauseType);
}
/**
* @notice Check if a pause type is enabled.
* @param _pauseType The pause type value.
* @return pauseTypeIsPaused Returns true if the pause type if paused, false otherwise.
*/
function isPaused(PauseType _pauseType) public view returns (bool pauseTypeIsPaused) {
pauseTypeIsPaused = (_pauseTypeStatusesBitMap & (1 << uint256(_pauseType))) != 0;
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { IGenericErrors } from "../interfaces/IGenericErrors.sol";
import { IPermissionsManager } from "../interfaces/IPermissionsManager.sol";
/**
* @title Contract to manage permissions initialization.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract PermissionsManager is Initializable, AccessControlUpgradeable, IPermissionsManager, IGenericErrors {
/**
* @notice Sets permissions for a list of addresses and their roles.
* @param _roleAddresses The list of addresses and roles to assign permissions to.
*/
function __Permissions_init(RoleAddress[] calldata _roleAddresses) internal onlyInitializing {
for (uint256 i; i < _roleAddresses.length; i++) {
if (_roleAddresses[i].addressWithRole == address(0)) {
revert ZeroAddressNotAllowed();
}
if (_roleAddresses[i].role == 0x0) {
revert ZeroHashNotAllowed();
}
_grantRole(_roleAddresses[i].role, _roleAddresses[i].addressWithRole);
}
}
}// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Contract to manage some efficient hashing functions. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ library Utils { /** * @notice Performs a gas optimized keccak hash for two bytes32 values. * @param _left Left value. * @param _right Right value. */ function _efficientKeccak(bytes32 _left, bytes32 _right) internal pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, _left) mstore(0x20, _right) value := keccak256(0x00, 0x40) } } /** * @notice Performs a gas optimized keccak hash for uint256 and address. * @param _left Left value. * @param _right Right value. */ function _efficientKeccak(uint256 _left, address _right) internal pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, _left) mstore(0x20, _right) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol";
import { L1MessageManagerV1 } from "./v1/L1MessageManagerV1.sol";
import { IL1MessageManager } from "../../interfaces/l1/IL1MessageManager.sol";
import { Utils } from "../../lib/Utils.sol";
/**
* @title Contract to manage cross-chain message rolling hash computation and storage on L1.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract L1MessageManager is L1MessageManagerV1, IL1MessageManager {
using BitMaps for BitMaps.BitMap;
using Utils for *;
/// @notice Contains the L1 to L2 messaging rolling hashes mapped to message number computed on L1.
mapping(uint256 messageNumber => bytes32 rollingHash) public rollingHashes;
/// @notice This maps which message numbers have been claimed to prevent duplicate claiming.
BitMaps.BitMap internal _messageClaimedBitMap;
/// @notice Contains the L2 messages Merkle roots mapped to their tree depth.
mapping(bytes32 merkleRoot => uint256 treeDepth) public l2MerkleRootsDepths;
/// @dev Total contract storage is 53 slots including the gap below.
/// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision.
uint256[50] private __gap_L1MessageManager;
/**
* @notice Take an existing message hash, calculates the rolling hash and stores at the message number.
* @param _messageNumber The current message number being sent.
* @param _messageHash The hash of the message being sent.
*/
function _addRollingHash(uint256 _messageNumber, bytes32 _messageHash) internal {
unchecked {
bytes32 newRollingHash = Utils._efficientKeccak(rollingHashes[_messageNumber - 1], _messageHash);
rollingHashes[_messageNumber] = newRollingHash;
emit RollingHashUpdated(_messageNumber, newRollingHash, _messageHash);
}
}
/**
* @notice Set the L2->L1 message as claimed when a user claims a message on L1.
* @param _messageNumber The message number on L2.
*/
function _setL2L1MessageToClaimed(uint256 _messageNumber) internal {
if (_messageClaimedBitMap.get(_messageNumber)) {
revert MessageAlreadyClaimed(_messageNumber);
}
_messageClaimedBitMap.set(_messageNumber);
}
/**
* @notice Add the L2 Merkle roots to the storage.
* @dev This function is called during block finalization.
* @dev The _treeDepth does not need to be checked to be non-zero as it is,
* already enforced to be non-zero in the circuit, and used in the proof's public input.
* @param _newRoots New L2 Merkle roots.
*/
function _addL2MerkleRoots(bytes32[] calldata _newRoots, uint256 _treeDepth) internal {
for (uint256 i; i < _newRoots.length; ++i) {
if (l2MerkleRootsDepths[_newRoots[i]] != 0) {
revert L2MerkleRootAlreadyAnchored(_newRoots[i]);
}
l2MerkleRootsDepths[_newRoots[i]] = _treeDepth;
emit L2MerkleRootAdded(_newRoots[i], _treeDepth);
}
}
/**
* @notice Emit an event for each L2 block containing L2->L1 messages.
* @dev This function is called during block finalization.
* @param _l2MessagingBlocksOffsets Is a sequence of uint16 values, where each value plus the last finalized L2 block number.
* indicates which L2 blocks have L2->L1 messages.
* @param _currentL2BlockNumber Last L2 block number finalized on L1.
*/
function _anchorL2MessagingBlocks(bytes calldata _l2MessagingBlocksOffsets, uint256 _currentL2BlockNumber) internal {
if (_l2MessagingBlocksOffsets.length % 2 != 0) {
revert BytesLengthNotMultipleOfTwo(_l2MessagingBlocksOffsets.length);
}
uint256 l2BlockOffset;
unchecked {
for (uint256 i; i < _l2MessagingBlocksOffsets.length; ) {
assembly {
l2BlockOffset := shr(240, calldataload(add(_l2MessagingBlocksOffsets.offset, i)))
}
emit L2MessagingBlockAnchored(_currentL2BlockNumber + l2BlockOffset);
i += 2;
}
}
}
/**
* @notice Checks if the L2->L1 message is claimed or not.
* @param _messageNumber The message number on L2.
* @return isClaimed Returns whether or not the message with _messageNumber has been claimed.
*/
function isMessageClaimed(uint256 _messageNumber) external view returns (bool isClaimed) {
isClaimed = _messageClaimedBitMap.get(_messageNumber);
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { L1MessageServiceV1 } from "./v1/L1MessageServiceV1.sol";
import { L1MessageManager } from "./L1MessageManager.sol";
import { IL1MessageService } from "../../interfaces/l1/IL1MessageService.sol";
import { IGenericErrors } from "../../interfaces/IGenericErrors.sol";
import { SparseMerkleTreeVerifier } from "../lib/SparseMerkleTreeVerifier.sol";
import { TransientStorageHelpers } from "../lib/TransientStorageHelpers.sol";
import { MessageHashing } from "../lib/MessageHashing.sol";
/**
* @title Contract to manage cross-chain messaging on L1.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract L1MessageService is
AccessControlUpgradeable,
L1MessageServiceV1,
L1MessageManager,
IL1MessageService,
IGenericErrors
{
using SparseMerkleTreeVerifier for *;
using MessageHashing for *;
using TransientStorageHelpers for *;
/// @dev This is currently not in use, but is reserved for future upgrades.
uint256 public systemMigrationBlock;
/// @dev Total contract storage is 51 slots including the gap below.
/// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision.
uint256[50] private __gap_L1MessageService;
/**
* @notice Initialises underlying message service dependencies.
* @param _rateLimitPeriod The period to rate limit against.
* @param _rateLimitAmount The limit allowed for withdrawing the period.
*/
function __MessageService_init(uint256 _rateLimitPeriod, uint256 _rateLimitAmount) internal onlyInitializing {
__ERC165_init();
__Context_init();
__AccessControl_init();
__RateLimiter_init(_rateLimitPeriod, _rateLimitAmount);
nextMessageNumber = 1;
}
/**
* @notice Adds a message for sending cross-chain and emits MessageSent.
* @dev The message number is preset (nextMessageNumber) and only incremented at the end if successful for the next caller.
* @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain.
* @param _to The address the message is intended for.
* @param _fee The fee being paid for the message delivery.
* @param _calldata The calldata to pass to the recipient.
*/
function sendMessage(
address _to,
uint256 _fee,
bytes calldata _calldata
) external payable whenTypeAndGeneralNotPaused(PauseType.L1_L2) {
if (_to == address(0)) {
revert ZeroAddressNotAllowed();
}
if (_fee > msg.value) {
revert ValueSentTooLow();
}
uint256 messageNumber = nextMessageNumber++;
uint256 valueSent = msg.value - _fee;
bytes32 messageHash = MessageHashing._hashMessage(msg.sender, _to, _fee, valueSent, messageNumber, _calldata);
_addRollingHash(messageNumber, messageHash);
emit MessageSent(msg.sender, _to, _fee, valueSent, messageNumber, _calldata, messageHash);
}
/**
* @notice Claims and delivers a cross-chain message using a Merkle proof.
* @dev if tree depth is empty, it will revert with L2MerkleRootDoesNotExist.
* @dev if tree depth is different than proof size, it will revert with ProofLengthDifferentThanMerkleDepth.
* @param _params Collection of claim data with proof and supporting data.
*/
function claimMessageWithProof(
ClaimMessageWithProofParams calldata _params
) external nonReentrant distributeFees(_params.fee, _params.to, _params.data, _params.feeRecipient) {
_requireTypeAndGeneralNotPaused(PauseType.L2_L1);
uint256 merkleDepth = l2MerkleRootsDepths[_params.merkleRoot];
if (merkleDepth == 0) {
revert L2MerkleRootDoesNotExist();
}
if (merkleDepth != _params.proof.length) {
revert ProofLengthDifferentThanMerkleDepth(merkleDepth, _params.proof.length);
}
_setL2L1MessageToClaimed(_params.messageNumber);
_addUsedAmount(_params.fee + _params.value);
bytes32 messageLeafHash = MessageHashing._hashMessage(
_params.from,
_params.to,
_params.fee,
_params.value,
_params.messageNumber,
_params.data
);
if (
!SparseMerkleTreeVerifier._verifyMerkleProof(
messageLeafHash,
_params.proof,
_params.leafIndex,
_params.merkleRoot
)
) {
revert InvalidMerkleProof();
}
TransientStorageHelpers.tstoreAddress(MESSAGE_SENDER_TRANSIENT_KEY, _params.from);
(bool callSuccess, bytes memory returnData) = _params.to.call{ value: _params.value }(_params.data);
if (!callSuccess) {
if (returnData.length > 0) {
assembly {
let data_size := mload(returnData)
revert(add(0x20, returnData), data_size)
}
} else {
revert MessageSendingFailed(_params.to);
}
}
TransientStorageHelpers.tstoreAddress(MESSAGE_SENDER_TRANSIENT_KEY, DEFAULT_MESSAGE_SENDER_TRANSIENT_VALUE);
emit MessageClaimed(messageLeafHash);
}
/**
* @notice Claims and delivers a cross-chain message.
* @dev The message sender address is set temporarily in the transient storage when claiming.
* @return originalSender The message sender address that is stored temporarily in the transient storage when claiming.
*/
function sender() external view returns (address originalSender) {
originalSender = TransientStorageHelpers.tloadAddress(MESSAGE_SENDER_TRANSIENT_KEY);
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { TransientStorageHelpers } from "../lib/TransientStorageHelpers.sol";
/**
* @title Contract that helps prevent reentrant calls.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract TransientStorageReentrancyGuardUpgradeable {
using TransientStorageHelpers for *;
bytes32 private constant REENTRANCY_GUARD_TRANSIENT_KEY =
bytes32(uint256(keccak256("eip1967.reentrancy.guard.transient.key")) - 1);
uint256 private constant NOT_ENTERED = 0;
uint256 private constant ENTERED = 1;
error ReentrantCall();
/// @dev This gap is used to not shift down the storage layout after removing the OpenZeppelin ReentrancyGuardUpgradeable contract.
uint256[50] private __gap_ReentrancyGuardUpgradeable;
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
/**
* @notice Checks reentrancy and if not reentrant sets the transient reentry flag.
* @dev This uses the TransientStorageHelpers library and REENTRANCY_GUARD_TRANSIENT_KEY.
*/
function _nonReentrantBefore() private {
if (TransientStorageHelpers.tloadUint256(REENTRANCY_GUARD_TRANSIENT_KEY) != NOT_ENTERED) {
revert ReentrantCall();
}
TransientStorageHelpers.tstoreUint256(REENTRANCY_GUARD_TRANSIENT_KEY, ENTERED);
}
/**
* @notice Clears reentry transient storage flag.
* @dev This uses the TransientStorageHelpers library and REENTRANCY_GUARD_TRANSIENT_KEY.
*/
function _nonReentrantAfter() private {
TransientStorageHelpers.tstoreUint256(REENTRANCY_GUARD_TRANSIENT_KEY, NOT_ENTERED);
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { IL1MessageManagerV1 } from "../../../interfaces/l1/IL1MessageManagerV1.sol";
/**
* @title Contract to manage cross-chain message hashes storage and status on L1.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract L1MessageManagerV1 is IL1MessageManagerV1 {
/// @notice The 2 legacy status constants for message statuses.
uint8 public constant INBOX_STATUS_UNKNOWN = 0;
uint8 public constant INBOX_STATUS_RECEIVED = 1;
/// @notice The 3 legacy status constants for message statuses.
uint8 public constant OUTBOX_STATUS_UNKNOWN = 0;
uint8 public constant OUTBOX_STATUS_SENT = 1;
uint8 public constant OUTBOX_STATUS_RECEIVED = 2;
/// @dev DEPRECATED in favor of the rollingHashes mapping on the L1MessageManager for L1 to L2 messaging.
mapping(bytes32 messageHash => uint256 messageStatus) public outboxL1L2MessageStatus;
/**
* @dev Mapping to store L2->L1 message hashes status.
* @dev messageHash => messageStatus (0: unknown, 1: received).
* @dev For the most part this has been deprecated. This is only used for messages received pre-AlphaV2.
*/
mapping(bytes32 messageHash => uint256 messageStatus) public inboxL2L1MessageStatus;
/// @dev Keep free storage slots for future implementation updates to avoid storage collision.
// *******************************************************************************************
// NB: THIS GAP HAS BEEN PUSHED OUT IN FAVOUR OF THE GAP INSIDE THE REENTRANCY CODE
//uint256[50] private __gap;
// NB: DO NOT USE THIS GAP
// *******************************************************************************************
/// @dev Total contract storage is 2 slots.
/**
* @notice Update the status of L2->L1 message when a user claims a message on L1.
* @dev The L2->L1 message is removed from storage.
* @dev Due to the nature of the rollup, we should not get a second entry of this.
* @param _messageHash Hash of the message.
*/
function _updateL2L1MessageStatusToClaimed(bytes32 _messageHash) internal {
if (inboxL2L1MessageStatus[_messageHash] != INBOX_STATUS_RECEIVED) {
revert MessageDoesNotExistOrHasAlreadyBeenClaimed(_messageHash);
}
delete inboxL2L1MessageStatus[_messageHash];
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { LineaRollupPauseManager } from "../../../lib/LineaRollupPauseManager.sol";
import { RateLimiter } from "../../lib/RateLimiter.sol";
import { L1MessageManagerV1 } from "./L1MessageManagerV1.sol";
import { TransientStorageReentrancyGuardUpgradeable } from "../TransientStorageReentrancyGuardUpgradeable.sol";
import { IMessageService } from "../../../interfaces/IMessageService.sol";
import { TransientStorageHelpers } from "../../lib/TransientStorageHelpers.sol";
import { MessageHashing } from "../../lib/MessageHashing.sol";
/**
* @title Contract to manage cross-chain messaging on L1.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract L1MessageServiceV1 is
Initializable,
RateLimiter,
L1MessageManagerV1,
TransientStorageReentrancyGuardUpgradeable,
LineaRollupPauseManager,
IMessageService
{
using MessageHashing for *;
// @dev This is initialised to save user cost with existing slot.
uint256 public nextMessageNumber;
/// @dev DEPRECATED in favor of new transient storage with `MESSAGE_SENDER_TRANSIENT_KEY` key.
address internal _messageSender;
/// @dev Total contract storage is 52 slots including the gap below.
/// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision.
uint256[50] private __gap;
/// @dev adding these should not affect storage as they are constants and are stored in bytecode.
uint256 internal constant REFUND_OVERHEAD_IN_GAS = 48252;
/// @dev The transient storage key to set the message sender against while claiming.
bytes32 internal constant MESSAGE_SENDER_TRANSIENT_KEY =
bytes32(uint256(keccak256("eip1967.message.sender.transient.key")) - 1);
/// @notice The default value for the message sender reset to post claiming using the MESSAGE_SENDER_TRANSIENT_KEY.
address internal constant DEFAULT_MESSAGE_SENDER_TRANSIENT_VALUE = address(0);
/**
* @notice The unspent fee is refunded if applicable.
* @param _feeInWei The fee paid for delivery in Wei.
* @param _to The recipient of the message and gas refund.
* @param _calldata The calldata of the message.
*/
modifier distributeFees(
uint256 _feeInWei,
address _to,
bytes calldata _calldata,
address _feeRecipient
) {
//pre-execution
uint256 startingGas = gasleft();
_;
//post-execution
// we have a fee
if (_feeInWei > 0) {
// default postman fee
uint256 deliveryFee = _feeInWei;
// do we have empty calldata?
if (_calldata.length == 0) {
bool isDestinationEOA;
assembly {
isDestinationEOA := iszero(extcodesize(_to))
}
// are we calling an EOA
if (isDestinationEOA) {
// initial + cost to call and refund minus gasleft
deliveryFee = (startingGas + REFUND_OVERHEAD_IN_GAS - gasleft()) * tx.gasprice;
if (_feeInWei > deliveryFee) {
payable(_to).send(_feeInWei - deliveryFee);
} else {
deliveryFee = _feeInWei;
}
}
}
address feeReceiver = _feeRecipient == address(0) ? msg.sender : _feeRecipient;
bool callSuccess = payable(feeReceiver).send(deliveryFee);
if (!callSuccess) {
revert FeePaymentFailed(feeReceiver);
}
}
}
/**
* @notice Claims and delivers a cross-chain message.
* @dev _feeRecipient can be set to address(0) to receive as msg.sender.
* @dev The original message sender address is temporarily set in transient storage,
* while claiming. This address is used in sender().
* @param _from The address of the original sender.
* @param _to The address the message is intended for.
* @param _fee The fee being paid for the message delivery.
* @param _value The value to be transferred to the destination address.
* @param _feeRecipient The recipient for the fee.
* @param _calldata The calldata to pass to the recipient.
* @param _nonce The unique auto generated nonce used when sending the message.
*/
function claimMessage(
address _from,
address _to,
uint256 _fee,
uint256 _value,
address payable _feeRecipient,
bytes calldata _calldata,
uint256 _nonce
) external nonReentrant distributeFees(_fee, _to, _calldata, _feeRecipient) {
_requireTypeAndGeneralNotPaused(PauseType.L2_L1);
/// @dev This is placed earlier to fix the stack issue by using these two earlier on.
TransientStorageHelpers.tstoreAddress(MESSAGE_SENDER_TRANSIENT_KEY, _from);
bytes32 messageHash = MessageHashing._hashMessage(_from, _to, _fee, _value, _nonce, _calldata);
// @dev Status check and revert is in the message manager.
_updateL2L1MessageStatusToClaimed(messageHash);
_addUsedAmount(_fee + _value);
(bool callSuccess, bytes memory returnData) = _to.call{ value: _value }(_calldata);
if (!callSuccess) {
if (returnData.length > 0) {
assembly {
let data_size := mload(returnData)
revert(add(32, returnData), data_size)
}
} else {
revert MessageSendingFailed(_to);
}
}
TransientStorageHelpers.tstoreAddress(MESSAGE_SENDER_TRANSIENT_KEY, DEFAULT_MESSAGE_SENDER_TRANSIENT_VALUE);
emit MessageClaimed(messageHash);
}
}// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.19 <=0.8.26; /** * @title Library to hash cross-chain messages. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ library MessageHashing { /** * @notice Hashes messages using assembly for efficiency. * @dev Adding 0xc0 is to indicate the calldata offset relative to the memory being added to. * @dev If the calldata is not modulus 32, the extra bit needs to be added on at the end else the hash is wrong. * @param _from The from address. * @param _to The to address. * @param _fee The fee paid for delivery. * @param _valueSent The value to be sent when delivering. * @param _messageNumber The unique message number. * @param _calldata The calldata to be passed to the destination address. */ function _hashMessage( address _from, address _to, uint256 _fee, uint256 _valueSent, uint256 _messageNumber, bytes calldata _calldata ) internal pure returns (bytes32 messageHash) { assembly { let mPtr := mload(0x40) mstore(mPtr, _from) mstore(add(mPtr, 0x20), _to) mstore(add(mPtr, 0x40), _fee) mstore(add(mPtr, 0x60), _valueSent) mstore(add(mPtr, 0x80), _messageNumber) mstore(add(mPtr, 0xa0), 0xc0) mstore(add(mPtr, 0xc0), _calldata.length) let rem := mod(_calldata.length, 0x20) let extra := 0 if iszero(iszero(rem)) { extra := sub(0x20, rem) } calldatacopy(add(mPtr, 0xe0), _calldata.offset, _calldata.length) messageHash := keccak256(mPtr, add(0xe0, add(_calldata.length, extra))) } } }
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { IRateLimiter } from "../../interfaces/IRateLimiter.sol";
/**
* @title Rate Limiter by period and amount using the block timestamp.
* @author ConsenSys Software Inc.
* @notice You can use this control numeric limits over a period using timestamp.
* @custom:security-contact [email protected]
*/
contract RateLimiter is Initializable, IRateLimiter, AccessControlUpgradeable {
bytes32 public constant RATE_LIMIT_SETTER_ROLE = keccak256("RATE_LIMIT_SETTER_ROLE");
bytes32 public constant USED_RATE_LIMIT_RESETTER_ROLE = keccak256("USED_RATE_LIMIT_RESETTER_ROLE");
uint256 public periodInSeconds; // how much time before limit resets.
uint256 public limitInWei; // max ether to withdraw per period.
/// @dev Public for ease of consumption.
/// @notice The time at which the current period ends at.
uint256 public currentPeriodEnd;
/// @dev Public for ease of consumption.
/// @notice Amounts already withdrawn this period.
uint256 public currentPeriodAmountInWei;
/// @dev Total contract storage is 14 slots with the gap below.
/// @dev Keep 10 free storage slots for future implementation updates to avoid storage collision.
uint256[10] private __gap;
/**
* @notice Initialises the limits and period for the rate limiter.
* @param _periodInSeconds The length of the period in seconds.
* @param _limitInWei The limit allowed in the period in Wei.
*/
function __RateLimiter_init(uint256 _periodInSeconds, uint256 _limitInWei) internal onlyInitializing {
if (_periodInSeconds == 0) {
revert PeriodIsZero();
}
if (_limitInWei == 0) {
revert LimitIsZero();
}
periodInSeconds = _periodInSeconds;
limitInWei = _limitInWei;
currentPeriodEnd = block.timestamp + _periodInSeconds;
emit RateLimitInitialized(periodInSeconds, limitInWei, currentPeriodEnd);
}
/**
* @notice Increments the amount used in the period.
* @dev The amount determining logic is external to this (e.g. fees are included when calling here).
* @dev Ignores the calculation if _usedAmount is zero.
* @dev Reverts if the limit is breached.
* @param _usedAmount The amount used to be added.
*/
function _addUsedAmount(uint256 _usedAmount) internal {
if (_usedAmount != 0) {
if (currentPeriodEnd < block.timestamp) {
currentPeriodEnd = block.timestamp + periodInSeconds;
} else {
_usedAmount += currentPeriodAmountInWei;
}
if (_usedAmount > limitInWei) {
revert RateLimitExceeded();
}
currentPeriodAmountInWei = _usedAmount;
}
}
/**
* @notice Resets the rate limit amount.
* @dev If the used amount is higher, it is set to the limit to avoid confusion/issues.
* @dev Only the RATE_LIMIT_SETTER_ROLE is allowed to execute this function.
* @dev Emits the LimitAmountChanged event.
* @dev usedLimitAmountToSet will use the default value of zero if period has expired.
* @param _amount The amount to reset the limit to.
*/
function resetRateLimitAmount(uint256 _amount) external onlyRole(RATE_LIMIT_SETTER_ROLE) {
uint256 usedLimitAmountToSet;
bool amountUsedLoweredToLimit;
bool usedAmountResetToZero;
if (currentPeriodEnd < block.timestamp) {
currentPeriodEnd = block.timestamp + periodInSeconds;
usedAmountResetToZero = true;
} else {
if (_amount < currentPeriodAmountInWei) {
usedLimitAmountToSet = _amount;
amountUsedLoweredToLimit = true;
}
}
limitInWei = _amount;
if (usedAmountResetToZero || amountUsedLoweredToLimit) {
currentPeriodAmountInWei = usedLimitAmountToSet;
}
emit LimitAmountChanged(_msgSender(), _amount, amountUsedLoweredToLimit, usedAmountResetToZero);
}
/**
* @notice Resets the amount used to zero.
* @dev Only the USED_RATE_LIMIT_RESETTER_ROLE is allowed to execute this function.
* @dev Emits the AmountUsedInPeriodReset event.
*/
function resetAmountUsedInPeriod() external onlyRole(USED_RATE_LIMIT_RESETTER_ROLE) {
currentPeriodAmountInWei = 0;
emit AmountUsedInPeriodReset(_msgSender());
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { Utils } from "../../lib/Utils.sol";
/**
* @title Library to verify sparse merkle proofs and to get the leaf hash value
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
library SparseMerkleTreeVerifier {
using Utils for *;
/**
* @dev Value doesn't fit in a uint of `bits` size.
* @dev This is based on OpenZeppelin's SafeCast library.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev Custom error for when the leaf index is out of bounds.
*/
error LeafIndexOutOfBounds(uint32 leafIndex, uint32 maxAllowedIndex);
/**
* @notice Verify merkle proof
* @param _leafHash Leaf hash.
* @param _proof Sparse merkle tree proof.
* @param _leafIndex Index of the leaf.
* @param _root Merkle root.
* @dev The depth of the tree is expected to be validated elsewhere beforehand.
* @return proofIsValid Returns if the proof is valid or not.
*/
function _verifyMerkleProof(
bytes32 _leafHash,
bytes32[] calldata _proof,
uint32 _leafIndex,
bytes32 _root
) internal pure returns (bool proofIsValid) {
uint32 maxAllowedIndex = safeCastToUint32((2 ** _proof.length) - 1);
if (_leafIndex > maxAllowedIndex) {
revert LeafIndexOutOfBounds(_leafIndex, maxAllowedIndex);
}
bytes32 node = _leafHash;
for (uint256 height; height < _proof.length; ++height) {
if (((_leafIndex >> height) & 1) == 1) {
node = Utils._efficientKeccak(_proof[height], node);
} else {
node = Utils._efficientKeccak(node, _proof[height]);
}
}
proofIsValid = node == _root;
}
/**
* @notice Tries to safely cast to uint32.
* @param _value The value being cast to uint32.
* @return castUint32 Returns a uint32 safely cast.
* @dev This is based on OpenZeppelin's SafeCast library.
*/
function safeCastToUint32(uint256 _value) internal pure returns (uint32 castUint32) {
if (_value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, _value);
}
castUint32 = uint32(_value);
}
}// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.26; /** * @title Library that provides helper functions to interact with transient storage. * @author ConsenSys Software Inc. * @custom:security-contact [email protected] */ library TransientStorageHelpers { /** * @notice Internal function that stores a uint256 value at a given key in the EVM's transient storage using the `tstore` opcode. * @param _key The key in the EVM transient storage where the value should be stored. * @param _value The uint256 value to be stored at the specified key in the EVM transient storage. */ function tstoreUint256(bytes32 _key, uint256 _value) internal { assembly { tstore(_key, _value) } } /** * @notice Internal function that retrieves a uint256 value from the EVM's transient storage using the `tload` opcode. * @param _key The key in the EVM transient storage from which the value should be retrieved. * @return value The uint256 value retrieved from the specified key in the EVM transient storage. */ function tloadUint256(bytes32 _key) internal view returns (uint256 value) { assembly { value := tload(_key) } } /** * @notice Internal function that stores an address at a given key in the EVM's transient storage using the `tstore` opcode. * @param _key The key in the EVM transient storage where the value should be stored. * @param _addr The address to be stored at the specified key in the EVM transient storage. */ function tstoreAddress(bytes32 _key, address _addr) internal { assembly { tstore(_key, _addr) } } /** * @notice Internal function that retrieves an address from the EVM's transient storage using the `tload` opcode. * @param _key The key in the EVM transient storage from which the value should be retrieved. * @return addr The address retrieved from the specified key in the EVM transient storage. */ function tloadAddress(bytes32 _key) internal view returns (address addr) { assembly { addr := tload(_key) } } }
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { L1MessageServiceV1 } from "./messageService/l1/v1/L1MessageServiceV1.sol";
import { IZkEvmV2 } from "./interfaces/l1/IZkEvmV2.sol";
import { IPlonkVerifier } from "./interfaces/l1/IPlonkVerifier.sol";
/**
* @title Contract to manage cross-chain L1 rollup proving.
* @author ConsenSys Software Inc.
* @custom:security-contact [email protected]
*/
abstract contract ZkEvmV2 is Initializable, AccessControlUpgradeable, L1MessageServiceV1, IZkEvmV2 {
uint256 internal constant MODULO_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
/// @dev DEPRECATED in favor of currentFinalizedState hash.
uint256 public currentTimestamp;
/// @notice The most recent finalized L2 block number.
uint256 public currentL2BlockNumber;
/// @notice The most recent L2 state root hash mapped by block number.
mapping(uint256 blockNumber => bytes32 stateRootHash) public stateRootHashes;
/// @notice The verifier address to use for a proof type when proving.
mapping(uint256 proofType => address verifierAddress) public verifiers;
/// @dev Total contract storage is 54 slots with the gap below.
/// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision.
uint256[50] private __gap;
/**
* @notice Verifies the proof with locally computed public inputs.
* @dev If the verifier based on proof type is not found, it reverts with InvalidProofType.
* @param _publicInput The computed public input hash cast as uint256.
* @param _proofType The proof type to determine which verifier contract to use.
* @param _proof The proof to be verified with the proof type verifier contract.
*/
function _verifyProof(uint256 _publicInput, uint256 _proofType, bytes calldata _proof) internal {
uint256[] memory publicInput = new uint256[](1);
publicInput[0] = _publicInput;
address verifierToUse = verifiers[_proofType];
if (verifierToUse == address(0)) {
revert InvalidProofType();
}
(bool callSuccess, bytes memory result) = verifierToUse.call(
abi.encodeWithSelector(IPlonkVerifier.Verify.selector, _proof, publicInput)
);
if (!callSuccess) {
if (result.length > 0) {
assembly {
let dataOffset := add(result, 0x20)
// Store the modified first 32 bytes back into memory overwriting the location after having swapped out the selector.
mstore(
dataOffset,
or(
// InvalidProofOrProofVerificationRanOutOfGas(string) = 0xca389c44bf373a5a506ab5a7d8a53cb0ea12ba7c5872fd2bc4a0e31614c00a85.
shl(224, 0xca389c44),
and(mload(dataOffset), 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
)
)
revert(dataOffset, mload(result))
}
} else {
revert InvalidProofOrProofVerificationRanOutOfGas("Unknown");
}
}
bool proofSucceeded = abi.decode(result, (bool));
if (!proofSucceeded) {
revert InvalidProof();
}
}
}{
"viaIR": false,
"optimizer": {
"enabled": true,
"runs": 10000
},
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayLengthsDoNotMatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"emptyBlobIndex","type":"uint256"}],"name":"BlobSubmissionDataEmpty","type":"error"},{"inputs":[],"name":"BlobSubmissionDataIsMissing","type":"error"},{"inputs":[],"name":"BytesLengthNotMultipleOf32","type":"error"},{"inputs":[{"internalType":"uint256","name":"bytesLength","type":"uint256"}],"name":"BytesLengthNotMultipleOfTwo","type":"error"},{"inputs":[{"internalType":"bytes32","name":"currentDataHash","type":"bytes32"}],"name":"DataAlreadySubmitted","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"EmptyBlobDataAtIndex","type":"error"},{"inputs":[],"name":"EmptySubmissionData","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"FeePaymentFailed","type":"error"},{"inputs":[],"name":"FeeTooLow","type":"error"},{"inputs":[{"internalType":"bytes32","name":"shnarf","type":"bytes32"}],"name":"FinalBlobNotSubmitted","type":"error"},{"inputs":[{"internalType":"uint256","name":"finalBlockNumber","type":"uint256"},{"internalType":"uint256","name":"lastFinalizedBlock","type":"uint256"}],"name":"FinalBlockNumberLessThanOrEqualToLastFinalizedBlock","type":"error"},{"inputs":[],"name":"FinalBlockStateEqualsZeroHash","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"FinalShnarfWrong","type":"error"},{"inputs":[{"internalType":"uint256","name":"l2BlockTimestamp","type":"uint256"},{"internalType":"uint256","name":"currentBlockTimestamp","type":"uint256"}],"name":"FinalizationInTheFuture","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"FinalizationStateIncorrect","type":"error"},{"inputs":[],"name":"FirstByteIsNotZero","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"string","name":"errorReason","type":"string"}],"name":"InvalidProofOrProofVerificationRanOutOfGas","type":"error"},{"inputs":[],"name":"InvalidProofType","type":"error"},{"inputs":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"}],"name":"IsNotPaused","type":"error"},{"inputs":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"}],"name":"IsPaused","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageNumber","type":"uint256"},{"internalType":"bytes32","name":"rollingHash","type":"bytes32"}],"name":"L1RollingHashDoesNotExistOnL1","type":"error"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"L2MerkleRootAlreadyAnchored","type":"error"},{"inputs":[],"name":"L2MerkleRootDoesNotExist","type":"error"},{"inputs":[],"name":"LastFinalizationTimeNotLapsed","type":"error"},{"inputs":[{"internalType":"uint32","name":"leafIndex","type":"uint32"},{"internalType":"uint32","name":"maxAllowedIndex","type":"uint32"}],"name":"LeafIndexOutOfBounds","type":"error"},{"inputs":[],"name":"LimitIsZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageIndex","type":"uint256"}],"name":"MessageAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"MessageDoesNotExistOrHasAlreadyBeenClaimed","type":"error"},{"inputs":[{"internalType":"address","name":"destination","type":"address"}],"name":"MessageSendingFailed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"rollingHash","type":"bytes32"}],"name":"MissingMessageNumberForRollingHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageNumber","type":"uint256"}],"name":"MissingRollingHashForMessageNumber","type":"error"},{"inputs":[],"name":"OnlyNonFallbackOperator","type":"error"},{"inputs":[{"internalType":"bytes32","name":"shnarf","type":"bytes32"}],"name":"ParentBlobNotSubmitted","type":"error"},{"inputs":[],"name":"PeriodIsZero","type":"error"},{"inputs":[],"name":"PointEvaluationFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"fieldElements","type":"uint256"},{"internalType":"uint256","name":"blsCurveModulus","type":"uint256"}],"name":"PointEvaluationResponseInvalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"PrecompileReturnDataLengthWrong","type":"error"},{"inputs":[],"name":"ProofIsEmpty","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"ProofLengthDifferentThanMerkleDepth","type":"error"},{"inputs":[],"name":"RateLimitExceeded","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"StartingRootHashDoesNotMatch","type":"error"},{"inputs":[],"name":"ValueSentTooLow","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"ZeroHashNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"resettingAddress","type":"address"}],"name":"AmountUsedInPeriodReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"startBlockNumber","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlockNumber","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"shnarf","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"parentStateRootHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"}],"name":"DataFinalizedV3","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"parentShnarf","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"shnarf","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"}],"name":"DataSubmittedV3","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"fallbackOperator","type":"address"}],"name":"FallbackOperatorAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"fallbackOperator","type":"address"}],"name":"FallbackOperatorRoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"l2MerkleRoot","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"treeDepth","type":"uint256"}],"name":"L2MerkleRootAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"l2Block","type":"uint256"}],"name":"L2MessagingBlockAnchored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"amountChangeBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"amountUsedLoweredToLimit","type":"bool"},{"indexed":false,"internalType":"bool","name":"usedAmountResetToZero","type":"bool"}],"name":"LimitAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes8","name":"previousVersion","type":"bytes8"},{"indexed":true,"internalType":"bytes8","name":"newVersion","type":"bytes8"}],"name":"LineaRollupVersionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_messageHash","type":"bytes32"}],"name":"MessageClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_calldata","type":"bytes"},{"indexed":true,"internalType":"bytes32","name":"_messageHash","type":"bytes32"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"},{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"PauseTypeRoleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"messageSender","type":"address"},{"indexed":true,"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"periodInSeconds","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"limitInWei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentPeriodEnd","type":"uint256"}],"name":"RateLimitInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"messageNumber","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"rollingHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"RollingHashUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum IPauseManager.PauseType","name":"unPauseType","type":"uint8"},{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"UnPauseTypeRoleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"messageSender","type":"address"},{"indexed":true,"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"}],"name":"UnPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"verifierAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"proofType","type":"uint256"},{"indexed":true,"internalType":"address","name":"verifierSetBy","type":"address"},{"indexed":false,"internalType":"address","name":"oldVerifierAddress","type":"address"}],"name":"VerifierAddressChanged","type":"event"},{"inputs":[],"name":"CONTRACT_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INBOX_STATUS_RECEIVED","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INBOX_STATUS_UNKNOWN","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OUTBOX_STATUS_RECEIVED","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OUTBOX_STATUS_SENT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OUTBOX_STATUS_UNKNOWN","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ALL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_BLOB_SUBMISSION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_FINALIZATION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_L1_L2_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_L2_L1_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_LIMIT_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSE_ALL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSE_BLOB_SUBMISSION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSE_FINALIZATION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSE_L1_L2_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNPAUSE_L2_L1_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USED_RATE_LIMIT_RESETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFIER_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFIER_UNSETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"shnarf","type":"bytes32"}],"name":"blobShnarfExists","outputs":[{"internalType":"uint256","name":"exists","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"address payable","name":"_feeRecipient","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"claimMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"messageNumber","type":"uint256"},{"internalType":"uint32","name":"leafIndex","type":"uint32"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address payable","name":"feeRecipient","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IL1MessageService.ClaimMessageWithProofParams","name":"_params","type":"tuple"}],"name":"claimMessageWithProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentFinalizedShnarf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentFinalizedState","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentL2BlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentL2StoredL1MessageNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentL2StoredL1RollingHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPeriodAmountInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPeriodEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"dataEndingBlock","outputs":[{"internalType":"uint256","name":"endingBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"dataFinalStateRootHashes","outputs":[{"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"dataParents","outputs":[{"internalType":"bytes32","name":"parentHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"dataShnarfHashes","outputs":[{"internalType":"bytes32","name":"shnarfHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"dataStartingBlock","outputs":[{"internalType":"uint256","name":"startingBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fallbackOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_aggregatedProof","type":"bytes"},{"internalType":"uint256","name":"_proofType","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentStateRootHash","type":"bytes32"},{"internalType":"uint256","name":"endBlockNumber","type":"uint256"},{"components":[{"internalType":"bytes32","name":"parentShnarf","type":"bytes32"},{"internalType":"bytes32","name":"snarkHash","type":"bytes32"},{"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"},{"internalType":"bytes32","name":"dataEvaluationPoint","type":"bytes32"},{"internalType":"bytes32","name":"dataEvaluationClaim","type":"bytes32"}],"internalType":"struct ILineaRollup.ShnarfData","name":"shnarfData","type":"tuple"},{"internalType":"uint256","name":"lastFinalizedTimestamp","type":"uint256"},{"internalType":"uint256","name":"finalTimestamp","type":"uint256"},{"internalType":"bytes32","name":"lastFinalizedL1RollingHash","type":"bytes32"},{"internalType":"bytes32","name":"l1RollingHash","type":"bytes32"},{"internalType":"uint256","name":"lastFinalizedL1RollingHashMessageNumber","type":"uint256"},{"internalType":"uint256","name":"l1RollingHashMessageNumber","type":"uint256"},{"internalType":"uint256","name":"l2MerkleTreesDepth","type":"uint256"},{"internalType":"bytes32[]","name":"l2MerkleRoots","type":"bytes32[]"},{"internalType":"bytes","name":"l2MessagingBlocksOffsets","type":"bytes"}],"internalType":"struct ILineaRollup.FinalizationDataV3","name":"_finalizationData","type":"tuple"}],"name":"finalizeBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"inboxL2L1MessageStatus","outputs":[{"internalType":"uint256","name":"messageStatus","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"initialStateRootHash","type":"bytes32"},{"internalType":"uint256","name":"initialL2BlockNumber","type":"uint256"},{"internalType":"uint256","name":"genesisTimestamp","type":"uint256"},{"internalType":"address","name":"defaultVerifier","type":"address"},{"internalType":"uint256","name":"rateLimitPeriodInSeconds","type":"uint256"},{"internalType":"uint256","name":"rateLimitAmountInWei","type":"uint256"},{"components":[{"internalType":"address","name":"addressWithRole","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPermissionsManager.RoleAddress[]","name":"roleAddresses","type":"tuple[]"},{"components":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPauseManager.PauseTypeRole[]","name":"pauseTypeRoles","type":"tuple[]"},{"components":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPauseManager.PauseTypeRole[]","name":"unpauseTypeRoles","type":"tuple[]"},{"internalType":"address","name":"fallbackOperator","type":"address"},{"internalType":"address","name":"defaultAdmin","type":"address"}],"internalType":"struct ILineaRollup.InitializationData","name":"_initializationData","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_messageNumber","type":"uint256"}],"name":"isMessageClaimed","outputs":[{"internalType":"bool","name":"isClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IPauseManager.PauseType","name":"_pauseType","type":"uint8"}],"name":"isPaused","outputs":[{"internalType":"bool","name":"pauseTypeIsPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"l2MerkleRootsDepths","outputs":[{"internalType":"uint256","name":"treeDepth","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextMessageNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"outboxL1L2MessageStatus","outputs":[{"internalType":"uint256","name":"messageStatus","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IPauseManager.PauseType","name":"_pauseType","type":"uint8"}],"name":"pauseByType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"pauseType","type":"bytes32"}],"name":"pauseTypeStatuses","outputs":[{"internalType":"bool","name":"pauseStatus","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodInSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"addressWithRole","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPermissionsManager.RoleAddress[]","name":"_roleAddresses","type":"tuple[]"},{"components":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPauseManager.PauseTypeRole[]","name":"_pauseTypeRoles","type":"tuple[]"},{"components":[{"internalType":"enum IPauseManager.PauseType","name":"pauseType","type":"uint8"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"internalType":"struct IPauseManager.PauseTypeRole[]","name":"_unpauseTypeRoles","type":"tuple[]"},{"internalType":"address","name":"_fallbackOperator","type":"address"}],"name":"reinitializeLineaRollupV6","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetAmountUsedInPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"resetRateLimitAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"messageNumber","type":"uint256"}],"name":"rollingHashes","outputs":[{"internalType":"bytes32","name":"rollingHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"sender","outputs":[{"internalType":"address","name":"originalSender","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_messageNumber","type":"uint256"},{"internalType":"bytes32","name":"_rollingHash","type":"bytes32"},{"internalType":"uint256","name":"_lastFinalizedTimestamp","type":"uint256"}],"name":"setFallbackOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVerifierAddress","type":"address"},{"internalType":"uint256","name":"_proofType","type":"uint256"}],"name":"setVerifierAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"stateRootHashes","outputs":[{"internalType":"bytes32","name":"stateRootHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"dataEvaluationClaim","type":"uint256"},{"internalType":"bytes","name":"kzgCommitment","type":"bytes"},{"internalType":"bytes","name":"kzgProof","type":"bytes"},{"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"},{"internalType":"bytes32","name":"snarkHash","type":"bytes32"}],"internalType":"struct ILineaRollup.BlobSubmission[]","name":"_blobSubmissions","type":"tuple[]"},{"internalType":"bytes32","name":"_parentShnarf","type":"bytes32"},{"internalType":"bytes32","name":"_finalBlobShnarf","type":"bytes32"}],"name":"submitBlobs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"finalStateRootHash","type":"bytes32"},{"internalType":"bytes32","name":"snarkHash","type":"bytes32"},{"internalType":"bytes","name":"compressedData","type":"bytes"}],"internalType":"struct ILineaRollup.CompressedCalldataSubmission","name":"_submission","type":"tuple"},{"internalType":"bytes32","name":"_parentShnarf","type":"bytes32"},{"internalType":"bytes32","name":"_expectedShnarf","type":"bytes32"}],"name":"submitDataAsCalldata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemMigrationBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IPauseManager.PauseType","name":"_pauseType","type":"uint8"}],"name":"unPauseByType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proofType","type":"uint256"}],"name":"unsetVerifierAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proofType","type":"uint256"}],"name":"verifiers","outputs":[{"internalType":"address","name":"verifierAddress","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
0x6080604052348015600e575f80fd5b5060156019565b60d3565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161460d1575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61535e806100e05f395ff3fe608060405260043610610483575f3560e01c806373bd07b711610251578063b837dbe91161013c578063cc5782f6116100b7578063d547741f11610087578063d722bbfc1161006d578063d722bbfc14610e53578063e196fb5d14610e86578063f5b541a614610ea5575f80fd5b8063d547741f14610e1e578063d5d4b83514610e3d575f80fd5b8063cc5782f614610d87578063cc6f725114610db5578063cd9b9e9a14610de8578063cf5b276414610dfe575f80fd5b8063bf3e75051161010c578063c0c4e584116100f2578063c0c4e58414610d34578063c1dc0f0714610d53578063c211697414610d68575f80fd5b8063bf3e750514610cec578063c0729ab114610d1f575f80fd5b8063b837dbe914610c66578063b9174ba314610c7b578063bc61e73314610cae578063bcc3003d14610ccd575f80fd5b80639ac25d08116101cc578063a98e773d1161019c578063ad422ff011610182578063ad422ff014610c0a578063aea4f74514610c1f578063b59faa6014610c33575f80fd5b8063a98e773d14610bb6578063ac1eff6814610bd5575f80fd5b80639ac25d0814610b3e5780639ee8b21114610b715780639f3ce55a14610b90578063a217fddf14610ba3575f80fd5b8063914e57eb11610221578063921b278e11610207578063921b278e14610b09578063986fcddd14610a2757806399467a3514610b1f575f80fd5b8063914e57eb14610a9957806391d1485414610ac5575f80fd5b806373bd07b714610a135780637d1e8c5514610a275780638be745d114610a3a5780638de4948714610a66575f80fd5b80634cdd389b1161037157806360e83cf3116102ec57806367e404ce116102bc578063695378f5116102a2578063695378f5146109975780636a906b80146109ad5780636e673843146109e0575f80fd5b806367e404ce1461094c5780636854f6bc14610978575f80fd5b806360e83cf3146108a257806363213155146108ce5780636463fb2a1461090157806366f96e9814610920575f80fd5b806358794456116103415780635c721a0c116103275780635c721a0c1461081f5780635ed73ceb1461084a5780636078bfd814610876575f80fd5b8063587944561461080a5780635b7eb4bd14610728575f80fd5b80634cdd389b1461076d5780635230eef214610799578063557eac73146107cc5780635603c65f146107eb575f80fd5b8063289581741161040157806338b90333116103d15780633fc08b65116103b75780633fc08b65146106fd57806348922ab714610728578063491e09361461074e575f80fd5b806338b90333146106755780633b12eccb146106ca575f80fd5b806328958174146106025780632c70645c146106215780632f2ff15d1461063757806336568abe14610656575f80fd5b806312d3fa9a116104565780631f443da01161043c5780631f443da01461057c5780632130d812146105a8578063248a9ca3146105d4575f80fd5b806312d3fa9a146105335780631e2ff94f14610566575f80fd5b806301ffc9a71461048757806303134d1d146104bb57806305861180146104fc5780631065a39914610512575b5f80fd5b348015610492575f80fd5b506104a66104a13660046146a1565b610ed8565b60405190151581526020015b60405180910390f35b3480156104c6575f80fd5b506104ee7f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104b2565b348015610507575f80fd5b506104ee6101bb5481565b34801561051d575f80fd5b5061053161052c3660046146e0565b610f70565b005b34801561053e575f80fd5b506104ee7f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b348015610571575f80fd5b506104ee6101185481565b348015610587575f80fd5b506104ee6105963660046146fe565b6101b96020525f908152604090205481565b3480156105b3575f80fd5b506104ee6105c23660046146fe565b6101be6020525f908152604090205481565b3480156105df575f80fd5b506104ee6105ee3660046146fe565b5f9081526065602052604090206001015490565b34801561060d575f80fd5b5061053161061c3660046146fe565b61106c565b34801561062c575f80fd5b506104ee6101835481565b348015610642575f80fd5b50610531610651366004614729565b61111f565b348015610661575f80fd5b50610531610670366004614729565b611148565b348015610680575f80fd5b506106bd6040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104b29190614757565b3480156106d5575f80fd5b506104ee7fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610708575f80fd5b506104ee6107173660046146fe565b60a56020525f908152604090205481565b348015610733575f80fd5b5061073c600181565b60405160ff90911681526020016104b2565b348015610759575f80fd5b506105316107683660046147d1565b61119f565b348015610778575f80fd5b506104ee6107873660046146fe565b6101b76020525f908152604090205481565b3480156107a4575f80fd5b506104ee7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107d7575f80fd5b506105316107e63660046146fe565b611455565b3480156107f6575f80fd5b50610531610805366004614861565b61151b565b348015610815575f80fd5b506104ee60995481565b34801561082a575f80fd5b506104ee6108393660046146fe565b60a66020525f908152604090205481565b348015610855575f80fd5b506104ee6108643660046146fe565b6101ba6020525f908152604090205481565b348015610881575f80fd5b506104ee6108903660046146fe565b6101b66020525f908152604090205481565b3480156108ad575f80fd5b506104ee6108bc3660046146fe565b6101506020525f908152604090205481565b3480156108d9575f80fd5b506104ee7fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b34801561090c575f80fd5b5061053161091b3660046148d9565b611613565b34801561092b575f80fd5b506104ee61093a3660046146fe565b6101b86020525f908152604090205481565b348015610957575f80fd5b50610960611a6c565b6040516001600160a01b0390911681526020016104b2565b348015610983575f80fd5b50610531610992366004614911565b611aa4565b3480156109a2575f80fd5b506104ee6101195481565b3480156109b8575f80fd5b506104ee7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b3480156109eb575f80fd5b506104ee7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a1e575f80fd5b5061073c600281565b348015610a32575f80fd5b5061073c5f81565b348015610a45575f80fd5b506104ee610a543660046146fe565b61011a6020525f908152604090205481565b348015610a71575f80fd5b506104ee7fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610aa4575f80fd5b506104ee610ab33660046146fe565b61014e6020525f908152604090205481565b348015610ad0575f80fd5b506104a6610adf366004614729565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b14575f80fd5b506104ee6101bf5481565b348015610b2a575f80fd5b50610531610b3936600461495f565b611ce4565b348015610b49575f80fd5b506104ee7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b7c575f80fd5b506104a6610b8b3660046146fe565b611fc8565b610531610b9e3660046149dc565b611feb565b348015610bae575f80fd5b506104ee5f81565b348015610bc1575f80fd5b50610531610bd0366004614a34565b61210d565b348015610be0575f80fd5b50610960610bef3660046146fe565b61011b6020525f90815260409020546001600160a01b031681565b348015610c15575f80fd5b506104ee60985481565b348015610c2a575f80fd5b506105316124c7565b348015610c3e575f80fd5b506104ee7fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c71575f80fd5b506104ee60e45481565b348015610c86575f80fd5b506104ee7f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cb9575f80fd5b506104a6610cc83660046146e0565b612522565b348015610cd8575f80fd5b50610531610ce7366004614a6c565b612546565b348015610cf7575f80fd5b506104ee7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d2a575f80fd5b506104ee609a5481565b348015610d3f575f80fd5b50610531610d4e366004614ad6565b612676565b348015610d5e575f80fd5b506104ee60975481565b348015610d73575f80fd5b50610531610d82366004614b88565b6128dc565b348015610d92575f80fd5b506104a6610da13660046146fe565b60d96020525f908152604090205460ff1681565b348015610dc0575f80fd5b506104ee7fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610df3575f80fd5b506104ee6101bd5481565b348015610e09575f80fd5b506101c054610960906001600160a01b031681565b348015610e29575f80fd5b50610531610e38366004614729565b6129e2565b348015610e48575f80fd5b506104ee6101bc5481565b348015610e5e575f80fd5b506104ee7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610e91575f80fd5b50610531610ea03660046146e0565b612a06565b348015610eb0575f80fd5b506104ee7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f6a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f826008811115610f8557610f85614bb2565b6008811115610f9657610f96614bb2565b81526020019081526020015f2054610fad81612ade565b610fb682612522565b610ff757816040517f18659654000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b60405180910390fd5b81600881111561100957611009614bb2565b60da8054600190921b19909116905581600881111561102a5761102a614bb2565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61109681612ade565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f8281526065602052604090206001015461113981612ade565b6111438383612ae8565b505050565b6101c0546001600160a01b0390811690821603611191576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61119b8282612ba6565b5050565b6111a7612c48565b85878484875f5a90506111ba6003612ce5565b6111ee6111e860017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b8f612d77565b5f6111fe8f8f8f8f8c8f8f612d7e565b905061120981612dd7565b61121b6112168d8f614c5e565b612e31565b5f808f6001600160a01b03168e8d8d604051611238929190614c71565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150816112d4578051156112915780518082602001fd5b8f6040517f54613443000000000000000000000000000000000000000000000000000000008152600401610fee91906001600160a01b0391909116815260200190565b61130861130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5f612d77565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a250508615905061143d57855f8490036113b357853b1580156113b1573a5a61135c61bc7c86614c5e565b6113669190614c4b565b6113709190614c80565b9150818811156113ad576001600160a01b0387166108fc611391848b614c4b565b6040518115909202915f818181858888f19350505050506113b1565b8791505b505b5f6001600160a01b038416156113c957836113cb565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611439576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b50505050505061144b612ea7565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261147f81612ade565b5f805f4260995410156114a4576097546114999042614c5e565b6099555060016114b6565b609a548510156114b657849250600191505b609885905580806114c45750815b156114cf57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b600661152681612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92961155081612ade565b5f85900361158a576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a60205260409020548435146115d6576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6115e58684612ed5565b90505f6115f9878484878b602001356131c2565b905061160781898c8c61324a565b50505050505050505050565b61161b612c48565b60a0810180359061162f9060808401614c97565b61163d610120840184614cb2565b61164e610100860160e08701614c97565b5f5a905061165c6003612ce5565b6101008701355f9081526101506020526040812054908190036116ab576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b58880614d13565b9050811461170457806116c88980614d13565b6040517f5e3fd6ad0000000000000000000000000000000000000000000000000000000081526004810193909352602483015250604401610fee565b61171188602001356134ae565b61172661121660c08a013560a08b0135614c5e565b5f61176f61173a60808b0160608c01614c97565b61174a60a08c0160808d01614c97565b8b60a001358c60c001358d602001358e80610120019061176a9190614cb2565b612d7e565b905061179a8161177f8b80614d13565b61178f60608e0160408f01614d77565b8d6101000135613526565b6117d0576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118136117fe60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b61180e60808c0160608d01614c97565b612d77565b5f8061182560a08c0160808d01614c97565b6001600160a01b031660c08c01356118416101208e018e614cb2565b60405161184f929190614c71565b5f6040518083038185875af1925050503d805f8114611889576040519150601f19603f3d011682016040523d82523d5f602084013e61188e565b606091505b5091509150816118f6578051156118a85780518082602001fd5b6118b860a08c0160808d01614c97565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610fee565b61192461130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611a5b57855f8490036119d157853b1580156119cf573a5a61197a61bc7c86614c5e565b6119849190614c4b565b61198e9190614c80565b9150818811156119cb576001600160a01b0387166108fc6119af848b614c4b565b6040518115909202915f818181858888f19350505050506119cf565b8791505b505b5f6001600160a01b038416156119e757836119e9565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611a57576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b505050505050611a69612ea7565b50565b5f611a9f611a9b60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5c90565b905090565b6005611aaf81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611ad981612ade565b611ae66040860186614cb2565b90505f03611b20576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611b69576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b5f8481526101be60205260408120549003611bb3576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f611bc16040870187614cb2565b604051611bcf929190614c71565b604051809103902090505f611bf18760200135835f9182526020526040902090565b90505f611c3d8760208a01358a3585611c16611c1060408f018f614cb2565b89613633565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611c82576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610fee565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611cd2908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611cef81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611d1981612ade565b5f859003611d53576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611d8f576040517f8019aff700000000000000000000000000000000000000000000000000000000815260048101869052602401610fee565b5f8481526101be60205260408120549003611dd9576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f8381526101be602052604090205415611e22576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611f27578a8a82818110611e6b57611e6b614d9a565b9050602002810190611e7d9190614dc7565b611e8690614ee4565b81499450925083611ec6576040517fc0e41e1d00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b60808301515f8181526020869052604090209550611ef485875f1c865f015187602001518860400151613734565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611e51565b50808714611f6b576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810188905260248101829052604401610fee565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610f6a565b6002611ff681612ce5565b6001600160a01b038516612036576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34841115612070576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261208083614f71565b9091555090505f6120918634614c4b565b90505f6120a333898985878b8b612d7e565b90506120af83826138d6565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516120fb959493929190614fd1565b60405180910390a45050505050505050565b5f54610100900460ff161580801561212b57505f54600160ff909116105b806121445750303b15801561214457505f5460ff166001145b6121d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561222c575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f61223d6080840160608501614c97565b6001600160a01b03160361227d576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122a061228d60e0840184615001565b61229b610100860186615001565b613952565b6122b282608001358360a00135613c00565b6122cd5f6122c861016085016101408601614c97565b612ae8565b6122e26122dd60c0840184615001565b613cc1565b6122f26080830160608401614c97565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561236461014083016101208401614c97565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123af61014083016101208401614c97565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a8252604080822085359081905581518381528085018490528083019190915260608082018490526080820184905260a09091208084526101be8552828420600190556101bd55815183815293840192909252808501359083015290206101bf55801561119b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96124f181612ade565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561253557612535614bb2565b60da54600190911b16151592915050565b61255362f099c082614c5e565b42101561258c576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612604576101bf546040805185815260208101859052908101839052606090206040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b6101c0546001600160a01b031661263b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612ae8565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561269657505f5460ff8083169116105b612722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561275c8888613cc1565b61276886868686613952565b6001600160a01b0382166127a8576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c61290681612ade565b6001600160a01b038316612946576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152606560205260409020600101546129fc81612ade565b6111438383613e6f565b60db5f826008811115612a1b57612a1b614bb2565b6008811115612a2c57612a2c614bb2565b81526020019081526020015f2054612a4381612ade565b612a4c82612522565b15612a8557816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b816008811115612a9757612a97614bb2565b60da8054600190921b9091179055816008811115612ab757612ab7614bb2565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593361104d565b611a698133613f0e565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612b623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610fee565b61119b8282613e6f565b5f612c77611a9b60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b14612cae576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ce3612cdc60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b6001612d77565b565b60da54816008811115612cfa57612cfa614bb2565b6001901b811615612d3957816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b600281161561119b5760016040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612dbc578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612e21576040517f992d87c300000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b5f90815260a66020526040812055565b8015611a6957426099541015612e5657609754612e4e9042614c5e565b609955612e66565b609a54612e639082614c5e565b90505b609854811115612ea2576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612ce361130260017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b5f81836020013511612f20576040517f706144050000000000000000000000000000000000000000000000000000000081526020840135600482015260248101839052604401610fee565b612f34836101800135846101400135613f9c565b6101bf54604080516101608601358152610120860135602082015260e0860135918101919091526060902014612fca57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b4283610100013510613015576040517fbf81c6e00000000000000000000000000000000000000000000000000000000081526101008401356004820152426024820152604401610fee565b6080830135613050576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61309360408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036130df576040517fedeae83c00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b6130fb6130f06101c0850185614d13565b856101a00135614069565b61311261310c6101e0850185614cb2565b84614175565b6020808401355f81815261011a909252604090912060808501359055610119556101bd819055613167610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561317a84614f71565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061327e5761327e614d9a565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806132dc576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161330593929190615065565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161337091906150d6565b5f604051808303815f865af19150503d805f81146133a9576040519150601f19603f3d011682016040523d82523d5f602084013e6133ae565b606091505b509150915081613455578051156133f357602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e000000000000000000000000000000000000000000000000006044820152606401610fee565b5f8180602001905181019061346a91906150e1565b9050806134a3576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613504576040517f335a4a9000000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f806135476001613538876002615221565b6135429190614c4b565b614202565b90508063ffffffff168463ffffffff16111561359f576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff808616600483015282166024820152604401610fee565b865f5b8681101561362557600163ffffffff8716821c811690036135ef576135e88888838181106135d2576135d2614d9a565b90506020020135835f9182526020526040902090565b915061361d565b61361a8289898481811061360557613605614d9a565b905060200201355f9182526020526040902090565b91505b6001016135a2565b509092149695505050505050565b5f61363f60208461522c565b15613676576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561372b57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156136dc57604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff0000000187870908935050613699565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b0316878787878760405160200161377f959493929190615264565b60408051601f1981840301815290829052613799916150d6565b5f60405180830381855afa9150503d805f81146137d1576040519150601f19603f3d011682016040523d82523d5f602084013e6137d6565b606091505b509150915081613812576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461385a578051604080517ff75db381000000000000000000000000000000000000000000000000000000008152610fee9290600401918252602082015260400190565b602081015160408201516110008214158061389557507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156134a3576040517f68dcad5f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff166139e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b83811015613af057848482818110613a0457613a04614d9a565b9050604002016020013560db5f878785818110613a2357613a23614d9a565b613a3992602060409092020190810191506146e0565b6008811115613a4a57613a4a614bb2565b6008811115613a5b57613a5b614bb2565b815260208101919091526040015f2055848482818110613a7d57613a7d614d9a565b90506040020160200135858583818110613a9957613a99614d9a565b613aaf92602060409092020190810191506146e0565b6008811115613ac057613ac0614bb2565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a36001016139ea565b505f5b81811015613bf957828282818110613b0d57613b0d614d9a565b9050604002016020013560dc5f858585818110613b2c57613b2c614d9a565b613b4292602060409092020190810191506146e0565b6008811115613b5357613b53614bb2565b6008811115613b6457613b64614bb2565b815260208101919091526040015f2055828282818110613b8657613b86614d9a565b90506040020160200135838383818110613ba257613ba2614d9a565b613bb892602060409092020190810191506146e0565b6008811115613bc957613bc9614bb2565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613af3565b5050505050565b5f54610100900460ff16613c96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b613c9e61424f565b613ca661424f565b613cae61424f565b613cb882826142e5565b5050600160e455565b5f54610100900460ff16613d57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b81811015611143575f838383818110613d7457613d74614d9a565b613d8a9260206040909202019081019150614c97565b6001600160a01b031603613dca576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ddc57613ddc614d9a565b905060400201602001355f801b03613e20576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e67838383818110613e3557613e35614d9a565b90506040020160200135848484818110613e5157613e51614d9a565b6122c89260206040909202019081019150614c97565b600101613d59565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff161561119b575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b57613f408161444b565b613f4b83602061445d565b604051602001613f5c92919061528a565b60408051601f19818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fee91600401614757565b815f03613fde57801561119b576040517f0c25659200000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b80614018576040517f5228f4c800000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f82815261014e6020526040902054811461119b576040517f36459fa00000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b5f5b8281101561416f576101505f85858481811061408957614089614d9a565b9050602002013581526020019081526020015f20545f146140f2578383828181106140b6576140b6614d9a565b905060200201356040517fe5d14425000000000000000000000000000000000000000000000000000000008152600401610fee91815260200190565b816101505f86868581811061410957614109614d9a565b9050602002013581526020019081526020015f20819055508184848381811061413457614134614d9a565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161406b565b50505050565b61418060028361522c565b156141ba576040517f0c91d77600000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f805b83811015613bf9576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016141bd565b5f63ffffffff82111561424b576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401610fee565b5090565b5f54610100900460ff16612ce3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f54610100900460ff1661437b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b815f036143b4576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036143ed576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556144018242614c5e565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016124bb565b6060610f6a6001600160a01b03831660145b60605f61446b836002614c80565b614476906002614c5e565b67ffffffffffffffff81111561448e5761448e614e03565b6040519080825280601f01601f1916602001820160405280156144b8576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106144ee576144ee614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061455057614550614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61458a846002614c80565b614595906001614c5e565b90505b6001811115614631577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145d6576145d6614d9a565b1a60f81b8282815181106145ec576145ec614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361462a816152f4565b9050614598565b50831561469a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610fee565b9392505050565b5f602082840312156146b1575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461469a575f80fd5b5f602082840312156146f0575f80fd5b81356009811061469a575f80fd5b5f6020828403121561470e575f80fd5b5035919050565b6001600160a01b0381168114611a69575f80fd5b5f806040838503121561473a575f80fd5b82359150602083013561474c81614715565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f84011261479c575f80fd5b50813567ffffffffffffffff8111156147b3575f80fd5b6020830191508360208285010111156147ca575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156147e8575f80fd5b88356147f381614715565b9750602089013561480381614715565b96506040890135955060608901359450608089013561482181614715565b935060a089013567ffffffffffffffff81111561483c575f80fd5b6148488b828c0161478c565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614874575f80fd5b843567ffffffffffffffff81111561488a575f80fd5b6148968782880161478c565b90955093505060208501359150604085013567ffffffffffffffff8111156148bc575f80fd5b850161020081880312156148ce575f80fd5b939692955090935050565b5f602082840312156148e9575f80fd5b813567ffffffffffffffff8111156148ff575f80fd5b8201610140818503121561469a575f80fd5b5f805f60608486031215614923575f80fd5b833567ffffffffffffffff811115614939575f80fd5b84016060818703121561494a575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614972575f80fd5b843567ffffffffffffffff811115614988575f80fd5b8501601f81018713614998575f80fd5b803567ffffffffffffffff8111156149ae575f80fd5b8760208260051b84010111156149c2575f80fd5b602091820198909750908601359560400135945092505050565b5f805f80606085870312156149ef575f80fd5b84356149fa81614715565b935060208501359250604085013567ffffffffffffffff811115614a1c575f80fd5b614a288782880161478c565b95989497509550505050565b5f60208284031215614a44575f80fd5b813567ffffffffffffffff811115614a5a575f80fd5b8201610160818503121561469a575f80fd5b5f805f60608486031215614a7e575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614aa5575f80fd5b50813567ffffffffffffffff811115614abc575f80fd5b6020830191508360208260061b85010111156147ca575f80fd5b5f805f805f805f6080888a031215614aec575f80fd5b873567ffffffffffffffff811115614b02575f80fd5b614b0e8a828b01614a95565b909850965050602088013567ffffffffffffffff811115614b2d575f80fd5b614b398a828b01614a95565b909650945050604088013567ffffffffffffffff811115614b58575f80fd5b614b648a828b01614a95565b9094509250506060880135614b7881614715565b8091505092959891949750929550565b5f8060408385031215614b99575f80fd5b8235614ba481614715565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614c18577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610f6a57610f6a614c1e565b80820180821115610f6a57610f6a614c1e565b818382375f9101908152919050565b8082028115828204841417610f6a57610f6a614c1e565b5f60208284031215614ca7575f80fd5b813561469a81614715565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614ce5575f80fd5b83018035915067ffffffffffffffff821115614cff575f80fd5b6020019150368190038213156147ca575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d46575f80fd5b83018035915067ffffffffffffffff821115614d60575f80fd5b6020019150600581901b36038213156147ca575f80fd5b5f60208284031215614d87575f80fd5b813563ffffffff8116811461469a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614df9575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614e5357614e53614e03565b60405290565b5f82601f830112614e68575f80fd5b813567ffffffffffffffff811115614e8257614e82614e03565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614eb157614eb1614e03565b604052818152838201602001851015614ec8575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ef4575f80fd5b614efc614e30565b82358152602083013567ffffffffffffffff811115614f19575f80fd5b614f2536828601614e59565b602083015250604083013567ffffffffffffffff811115614f44575f80fd5b614f5036828601614e59565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fa157614fa1614c1e565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f614ff6608083018486614fa8565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615034575f80fd5b83018035915067ffffffffffffffff82111561504e575f80fd5b6020019150600681901b36038213156147ca575f80fd5b604081525f615078604083018587614fa8565b82810360208401528084518083526020830191506020860192505f5b818110156150b2578351835260209384019390920191600101615094565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61469a82846150bf565b5f602082840312156150f1575f80fd5b8151801515811461469a575f80fd5b6001815b600184111561513b5780850481111561511f5761511f614c1e565b600184161561512d57908102905b60019390931c928002615104565b935093915050565b5f8261515157506001610f6a565b8161515d57505f610f6a565b8160018114615173576002811461517d57615199565b6001915050610f6a565b60ff84111561518e5761518e614c1e565b50506001821b610f6a565b5060208310610133831016604e8410600b84101617156151bc575081810a610f6a565b6151e77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615100565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561521957615219614c1e565b029392505050565b5f61469a8383615143565b5f8261525f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f614ff661528460608401866150bf565b846150bf565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6152bb60178301856150bf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526152eb60118201856150bf565b95945050505050565b5f8161530257615302614c1e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220f37ab9d49b246192cc1f4c0273d18fcd431dc83c67e6b7fb35993ccad3328d4e64736f6c634300081a0033
Deployed Bytecode
0x608060405260043610610483575f3560e01c806373bd07b711610251578063b837dbe91161013c578063cc5782f6116100b7578063d547741f11610087578063d722bbfc1161006d578063d722bbfc14610e53578063e196fb5d14610e86578063f5b541a614610ea5575f80fd5b8063d547741f14610e1e578063d5d4b83514610e3d575f80fd5b8063cc5782f614610d87578063cc6f725114610db5578063cd9b9e9a14610de8578063cf5b276414610dfe575f80fd5b8063bf3e75051161010c578063c0c4e584116100f2578063c0c4e58414610d34578063c1dc0f0714610d53578063c211697414610d68575f80fd5b8063bf3e750514610cec578063c0729ab114610d1f575f80fd5b8063b837dbe914610c66578063b9174ba314610c7b578063bc61e73314610cae578063bcc3003d14610ccd575f80fd5b80639ac25d08116101cc578063a98e773d1161019c578063ad422ff011610182578063ad422ff014610c0a578063aea4f74514610c1f578063b59faa6014610c33575f80fd5b8063a98e773d14610bb6578063ac1eff6814610bd5575f80fd5b80639ac25d0814610b3e5780639ee8b21114610b715780639f3ce55a14610b90578063a217fddf14610ba3575f80fd5b8063914e57eb11610221578063921b278e11610207578063921b278e14610b09578063986fcddd14610a2757806399467a3514610b1f575f80fd5b8063914e57eb14610a9957806391d1485414610ac5575f80fd5b806373bd07b714610a135780637d1e8c5514610a275780638be745d114610a3a5780638de4948714610a66575f80fd5b80634cdd389b1161037157806360e83cf3116102ec57806367e404ce116102bc578063695378f5116102a2578063695378f5146109975780636a906b80146109ad5780636e673843146109e0575f80fd5b806367e404ce1461094c5780636854f6bc14610978575f80fd5b806360e83cf3146108a257806363213155146108ce5780636463fb2a1461090157806366f96e9814610920575f80fd5b806358794456116103415780635c721a0c116103275780635c721a0c1461081f5780635ed73ceb1461084a5780636078bfd814610876575f80fd5b8063587944561461080a5780635b7eb4bd14610728575f80fd5b80634cdd389b1461076d5780635230eef214610799578063557eac73146107cc5780635603c65f146107eb575f80fd5b8063289581741161040157806338b90333116103d15780633fc08b65116103b75780633fc08b65146106fd57806348922ab714610728578063491e09361461074e575f80fd5b806338b90333146106755780633b12eccb146106ca575f80fd5b806328958174146106025780632c70645c146106215780632f2ff15d1461063757806336568abe14610656575f80fd5b806312d3fa9a116104565780631f443da01161043c5780631f443da01461057c5780632130d812146105a8578063248a9ca3146105d4575f80fd5b806312d3fa9a146105335780631e2ff94f14610566575f80fd5b806301ffc9a71461048757806303134d1d146104bb57806305861180146104fc5780631065a39914610512575b5f80fd5b348015610492575f80fd5b506104a66104a13660046146a1565b610ed8565b60405190151581526020015b60405180910390f35b3480156104c6575f80fd5b506104ee7f1ab87f7458c0e3d07e9881c14ee67f0141703614fd48ea5b15ed987e5f4b030e81565b6040519081526020016104b2565b348015610507575f80fd5b506104ee6101bb5481565b34801561051d575f80fd5b5061053161052c3660046146e0565b610f70565b005b34801561053e575f80fd5b506104ee7f67c2dca7476ee0fe1dd3cba13428c6760bfe2599a6dfe26a9ad7ef27317c6e7781565b348015610571575f80fd5b506104ee6101185481565b348015610587575f80fd5b506104ee6105963660046146fe565b6101b96020525f908152604090205481565b3480156105b3575f80fd5b506104ee6105c23660046146fe565b6101be6020525f908152604090205481565b3480156105df575f80fd5b506104ee6105ee3660046146fe565b5f9081526065602052604090206001015490565b34801561060d575f80fd5b5061053161061c3660046146fe565b61106c565b34801561062c575f80fd5b506104ee6101835481565b348015610642575f80fd5b50610531610651366004614729565b61111f565b348015610661575f80fd5b50610531610670366004614729565b611148565b348015610680575f80fd5b506106bd6040518060400160405280600381526020017f362e30000000000000000000000000000000000000000000000000000000000081525081565b6040516104b29190614757565b3480156106d5575f80fd5b506104ee7fb6cc65f42901ed602aec1619cc1ead29d487cd489094a37615153eaeb991d77081565b348015610708575f80fd5b506104ee6107173660046146fe565b60a56020525f908152604090205481565b348015610733575f80fd5b5061073c600181565b60405160ff90911681526020016104b2565b348015610759575f80fd5b506105316107683660046147d1565b61119f565b348015610778575f80fd5b506104ee6107873660046146fe565b6101b76020525f908152604090205481565b3480156107a4575f80fd5b506104ee7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf981565b3480156107d7575f80fd5b506105316107e63660046146fe565b611455565b3480156107f6575f80fd5b50610531610805366004614861565b61151b565b348015610815575f80fd5b506104ee60995481565b34801561082a575f80fd5b506104ee6108393660046146fe565b60a66020525f908152604090205481565b348015610855575f80fd5b506104ee6108643660046146fe565b6101ba6020525f908152604090205481565b348015610881575f80fd5b506104ee6108903660046146fe565b6101b66020525f908152604090205481565b3480156108ad575f80fd5b506104ee6108bc3660046146fe565b6101506020525f908152604090205481565b3480156108d9575f80fd5b506104ee7fe37c272ea30e2bb381ad7cf89ae754b49153250609f36d0cbdad8b64c184bb5c81565b34801561090c575f80fd5b5061053161091b3660046148d9565b611613565b34801561092b575f80fd5b506104ee61093a3660046146fe565b6101b86020525f908152604090205481565b348015610957575f80fd5b50610960611a6c565b6040516001600160a01b0390911681526020016104b2565b348015610983575f80fd5b50610531610992366004614911565b611aa4565b3480156109a2575f80fd5b506104ee6101195481565b3480156109b8575f80fd5b506104ee7fd8b4c34c2ec1f3194471108c64ad2beda340c0337ee4ca35592f9ef270f4228b81565b3480156109eb575f80fd5b506104ee7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c81565b348015610a1e575f80fd5b5061073c600281565b348015610a32575f80fd5b5061073c5f81565b348015610a45575f80fd5b506104ee610a543660046146fe565b61011a6020525f908152604090205481565b348015610a71575f80fd5b506104ee7fe1fce82838dd7a42cfe783f60dc6233c8aa2c4fc66e77817805e767ec5e349b681565b348015610aa4575f80fd5b506104ee610ab33660046146fe565b61014e6020525f908152604090205481565b348015610ad0575f80fd5b506104a6610adf366004614729565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610b14575f80fd5b506104ee6101bf5481565b348015610b2a575f80fd5b50610531610b3936600461495f565b611ce4565b348015610b49575f80fd5b506104ee7f56bdc3c9ec86cb7db110a7699b2ade72f0b8819727d9f7d906b012641505fa7781565b348015610b7c575f80fd5b506104a6610b8b3660046146fe565b611fc8565b610531610b9e3660046149dc565b611feb565b348015610bae575f80fd5b506104ee5f81565b348015610bc1575f80fd5b50610531610bd0366004614a34565b61210d565b348015610be0575f80fd5b50610960610bef3660046146fe565b61011b6020525f90815260409020546001600160a01b031681565b348015610c15575f80fd5b506104ee60985481565b348015610c2a575f80fd5b506105316124c7565b348015610c3e575f80fd5b506104ee7fe4831f9e4316ac2c65117d1f602fbf56d38128a9973d5e3fdbc5b77265c18d4081565b348015610c71575f80fd5b506104ee60e45481565b348015610c86575f80fd5b506104ee7f430a7f0cb00b5ebbe63cecc96e82cf959a883e7c13a95110854f1fa6b3fbf59881565b348015610cb9575f80fd5b506104a6610cc83660046146e0565b612522565b348015610cd8575f80fd5b50610531610ce7366004614a6c565b612546565b348015610cf7575f80fd5b506104ee7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8281565b348015610d2a575f80fd5b506104ee609a5481565b348015610d3f575f80fd5b50610531610d4e366004614ad6565b612676565b348015610d5e575f80fd5b506104ee60975481565b348015610d73575f80fd5b50610531610d82366004614b88565b6128dc565b348015610d92575f80fd5b506104a6610da13660046146fe565b60d96020525f908152604090205460ff1681565b348015610dc0575f80fd5b506104ee7fe8cb6172fcf5cbaae022b7c910224a4f0c20d53227e630056efff182155a5abc81565b348015610df3575f80fd5b506104ee6101bd5481565b348015610e09575f80fd5b506101c054610960906001600160a01b031681565b348015610e29575f80fd5b50610531610e38366004614729565b6129e2565b348015610e48575f80fd5b506104ee6101bc5481565b348015610e5e575f80fd5b506104ee7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a81565b348015610e91575f80fd5b50610531610ea03660046146e0565b612a06565b348015610eb0575f80fd5b506104ee7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f6a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60dc5f826008811115610f8557610f85614bb2565b6008811115610f9657610f96614bb2565b81526020019081526020015f2054610fad81612ade565b610fb682612522565b610ff757816040517f18659654000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b60405180910390fd5b81600881111561100957611009614bb2565b60da8054600190921b19909116905581600881111561102a5761102a614bb2565b7fd071d2b85dec4489435b541d2f0e2570db09b09db9efd8703948d44a433df65a335b6040516001600160a01b03909116815260200160405180910390a25050565b7f6b5661ddfbd1fbd525c902a513e0f47d9c74f1c1ee8a2d4f1937ad305fb8f41a61109681612ade565b5f82815261011b602090815260408083205490516001600160a01b0390911681523392859290917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b5f8281526065602052604090206001015461113981612ade565b6111438383612ae8565b505050565b6101c0546001600160a01b0390811690821603611191576040517f7f7497e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61119b8282612ba6565b5050565b6111a7612c48565b85878484875f5a90506111ba6003612ce5565b6111ee6111e860017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b8f612d77565b5f6111fe8f8f8f8f8c8f8f612d7e565b905061120981612dd7565b61121b6112168d8f614c5e565b612e31565b5f808f6001600160a01b03168e8d8d604051611238929190614c71565b5f6040518083038185875af1925050503d805f8114611272576040519150601f19603f3d011682016040523d82523d5f602084013e611277565b606091505b5091509150816112d4578051156112915780518082602001fd5b8f6040517f54613443000000000000000000000000000000000000000000000000000000008152600401610fee91906001600160a01b0391909116815260200190565b61130861130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5f612d77565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a250508615905061143d57855f8490036113b357853b1580156113b1573a5a61135c61bc7c86614c5e565b6113669190614c4b565b6113709190614c80565b9150818811156113ad576001600160a01b0387166108fc611391848b614c4b565b6040518115909202915f818181858888f19350505050506113b1565b8791505b505b5f6001600160a01b038416156113c957836113cb565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611439576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b50505050505061144b612ea7565b5050505050505050565b7f1185e52d62bfbbea270e57d3d09733d221b53ab7a18bae82bb3c6c74bab16d8261147f81612ade565b5f805f4260995410156114a4576097546114999042614c5e565b6099555060016114b6565b609a548510156114b657849250600191505b609885905580806114c45750815b156114cf57609a8390555b60408051868152831515602082015282151581830152905133917fbc3dc0cb5c15c51c81316450d44048838bb478b9809447d01c766a06f3e9f2c8919081900360600190a25050505050565b600661152681612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92961155081612ade565b5f85900361158a576040517f7907d79b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610119545f81815261011a60205260409020548435146115d6576040517fead4c30e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101bd545f6115e58684612ed5565b90505f6115f9878484878b602001356131c2565b905061160781898c8c61324a565b50505050505050505050565b61161b612c48565b60a0810180359061162f9060808401614c97565b61163d610120840184614cb2565b61164e610100860160e08701614c97565b5f5a905061165c6003612ce5565b6101008701355f9081526101506020526040812054908190036116ab576040517f4e68667500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b58880614d13565b9050811461170457806116c88980614d13565b6040517f5e3fd6ad0000000000000000000000000000000000000000000000000000000081526004810193909352602483015250604401610fee565b61171188602001356134ae565b61172661121660c08a013560a08b0135614c5e565b5f61176f61173a60808b0160608c01614c97565b61174a60a08c0160808d01614c97565b8b60a001358c60c001358d602001358e80610120019061176a9190614cb2565b612d7e565b905061179a8161177f8b80614d13565b61178f60608e0160408f01614d77565b8d6101000135613526565b6117d0576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118136117fe60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b61180e60808c0160608d01614c97565b612d77565b5f8061182560a08c0160808d01614c97565b6001600160a01b031660c08c01356118416101208e018e614cb2565b60405161184f929190614c71565b5f6040518083038185875af1925050503d805f8114611889576040519150601f19603f3d011682016040523d82523d5f602084013e61188e565b606091505b5091509150816118f6578051156118a85780518082602001fd5b6118b860a08c0160808d01614c97565b6040517f546134430000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610fee565b61192461130260017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b60405183907fa4c827e719e911e8f19393ccdb85b5102f08f0910604d340ba38390b7ff2ab0e905f90a2505050505f861115611a5b57855f8490036119d157853b1580156119cf573a5a61197a61bc7c86614c5e565b6119849190614c4b565b61198e9190614c80565b9150818811156119cb576001600160a01b0387166108fc6119af848b614c4b565b6040518115909202915f818181858888f19350505050506119cf565b8791505b505b5f6001600160a01b038416156119e757836119e9565b335b90505f816001600160a01b03166108fc8490811502906040515f60405180830381858888f19350505050905080611a57576040517fa57c4df40000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610fee565b5050505b505050505050611a69612ea7565b50565b5f611a9f611a9b60017f3095e8dc547eeb8bf90020768c67e29e974614469d8f71638ac29f39b96e4893614c4b565b5c90565b905090565b6005611aaf81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611ad981612ade565b611ae66040860186614cb2565b90505f03611b20576040517fc01eab5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8381526101be602052604090205415611b69576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b5f8481526101be60205260408120549003611bb3576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f611bc16040870187614cb2565b604051611bcf929190614c71565b604051809103902090505f611bf18760200135835f9182526020526040902090565b90505f611c3d8760208a01358a3585611c16611c1060408f018f614cb2565b89613633565b604080519586526020860194909452928401919091526060830152608082015260a0902090565b9050808614611c82576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810187905260248101829052604401610fee565b5f8181526101be602052604090819020600190555181907f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee07231990611cd2908a908c3590918252602082015260400190565b60405180910390a25050505050505050565b6004611cef81612ce5565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929611d1981612ade565b5f859003611d53576040517fb1504a5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b844915611d8f576040517f8019aff700000000000000000000000000000000000000000000000000000000815260048101869052602401610fee565b5f8481526101be60205260408120549003611dd9576040517f6e5424c200000000000000000000000000000000000000000000000000000000815260048101859052602401610fee565b5f8381526101be602052604090205415611e22576040517f0f06cd1500000000000000000000000000000000000000000000000000000000815260048101849052602401610fee565b6040805160a0810182525f808252606060208301819052928201839052918101829052608081018290528190865f5b89811015611f27578a8a82818110611e6b57611e6b614d9a565b9050602002810190611e7d9190614dc7565b611e8690614ee4565b81499450925083611ec6576040517fc0e41e1d00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b60808301515f8181526020869052604090209550611ef485875f1c865f015187602001518860400151613734565b6060848101518551604080519687526020870194909452928501528301869052608083015260a090912090600101611e51565b50808714611f6b576040517fd3664fb30000000000000000000000000000000000000000000000000000000081526004810188905260248101829052604401610fee565b5f8181526101be602090815260409182902060019055606084015182518b81529182015282917f55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319910160405180910390a250505050505050505050565b600881901c5f90815261014f6020526040812054600160ff84161b161515610f6a565b6002611ff681612ce5565b6001600160a01b038516612036576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34841115612070576040517fb03b693200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e480545f918261208083614f71565b9091555090505f6120918634614c4b565b90505f6120a333898985878b8b612d7e565b90506120af83826138d6565b80886001600160a01b0316336001600160a01b03167fe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c8a86888c8c6040516120fb959493929190614fd1565b60405180910390a45050505050505050565b5f54610100900460ff161580801561212b57505f54600160ff909116105b806121445750303b15801561214457505f5460ff166001145b6121d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561222c575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b5f61223d6080840160608501614c97565b6001600160a01b03160361227d576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122a061228d60e0840184615001565b61229b610100860186615001565b613952565b6122b282608001358360a00135613c00565b6122cd5f6122c861016085016101408601614c97565b612ae8565b6122e26122dd60c0840184615001565b613cc1565b6122f26080830160608401614c97565b5f805261011b6020527f033d11f27e62ab919708ec716731da80d261a6e4253259b7acde9bf89d28ec1880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905561236461014083016101208401614c97565b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556123af61014083016101208401614c97565b6001600160a01b0316336001600160a01b03167f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f60405160405180910390a36020828101356101198190555f90815261011a8252604080822085359081905581518381528085018490528083019190915260608082018490526080820184905260a09091208084526101be8552828420600190556101bd55815183815293840192909252808501359083015290206101bf55801561119b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b7f0cf0d2deb70d7bdac2fa48c4ac99bc558170be0ce5fcb994caefa4bf7b96edf96124f181612ade565b5f609a81905560405133917fba88c025b0cbb77022c0c487beef24f759f1e4be2f51a205bc427cee19c2eaa691a250565b5f81600881111561253557612535614bb2565b60da54600190911b16151592915050565b61255362f099c082614c5e565b42101561258c576040517f4306cbb100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815260208101849052908101829052606090206101bf5414612604576101bf546040805185815260208101859052908101839052606090206040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b6101c0546001600160a01b031661263b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92982612ae8565b6040516001600160a01b0382169033907f9fc8868f8577b31b805ee65bb52325782b5e2708dbdb7f04c7467c6785fccb30905f90a350505050565b5f54600690610100900460ff1615801561269657505f5460ff8083169116105b612722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610fee565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905561275c8888613cc1565b61276886868686613952565b6001600160a01b0382166127a8576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101c080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03841690811790915560405133907f1f82add12d98b5eaed4d6a6d5f74cfc7a85e5c90c335ab5562f77f220ed45d5f905f90a36040517f362e300000000000000000000000000000000000000000000000000000000000907f352e300000000000000000000000000000000000000000000000000000000000907f2f8492a7a430cf917798dfb60bc5af634f68e6c40287947df0ea6f7ec0669bd8905f90a35f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050505050565b7f32937fd5162e282df7e9a14a5073a2425321c7966eaf70ed6c838a1006d84c4c61290681612ade565b6001600160a01b038316612946576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815261011b60209081526040918290205491516001600160a01b03928316815233928592908716917f4a29db3fc6b42bda201e4b4d69ce8d575eeeba5f153509c0d0a342af0f1bd021910160405180910390a4505f90815261011b6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152606560205260409020600101546129fc81612ade565b6111438383613e6f565b60db5f826008811115612a1b57612a1b614bb2565b6008811115612a2c57612a2c614bb2565b81526020019081526020015f2054612a4381612ade565b612a4c82612522565b15612a8557816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b816008811115612a9757612a97614bb2565b60da8054600190921b9091179055816008811115612ab757612ab7614bb2565b7f534f879afd40abb4e39f8e1b77a316be4c8e3521d9cf5a3a3db8959d574d45593361104d565b611a698133613f0e565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b575f8281526065602090815260408083206001600160a01b0385168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612b623390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381163314612c3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610fee565b61119b8282613e6f565b5f612c77611a9b60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b14612cae576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ce3612cdc60017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b6001612d77565b565b60da54816008811115612cfa57612cfa614bb2565b6001901b811615612d3957816040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b600281161561119b5760016040517fc0a71b58000000000000000000000000000000000000000000000000000000008152600401610fee9190614bdf565b80825d5050565b5f60405188815287602082015286604082015285606082015284608082015260c060a08201528260c0820152602083065f8115612dbc578160200390505b848660e085013790930160e001902098975050505050505050565b5f81815260a66020526040902054600114612e21576040517f992d87c300000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b5f90815260a66020526040812055565b8015611a6957426099541015612e5657609754612e4e9042614c5e565b609955612e66565b609a54612e639082614c5e565b90505b609854811115612ea2576040517fa74c1c5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a55565b612ce361130260017f084edf88d5959696dcc7aab5c8674a33a1ef78f37dda21b782ed03bddb22ade5614c4b565b5f81836020013511612f20576040517f706144050000000000000000000000000000000000000000000000000000000081526020840135600482015260248101839052604401610fee565b612f34836101800135846101400135613f9c565b6101bf54604080516101608601358152610120860135602082015260e0860135918101919091526060902014612fca57604080516101608501358152610120850135602082015260e085013591810191909152606090206101bf546040517fbc5aad1100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610fee565b4283610100013510613015576040517fbf81c6e00000000000000000000000000000000000000000000000000000000081526101008401356004820152426024820152604401610fee565b6080830135613050576040517f2898482a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61309360408401356060850135608086013560a087013560c0880135604080519586526020860194909452928401919091526060830152608082015260a0902090565b5f8181526101be6020526040812054919250036130df576040517fedeae83c00000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b6130fb6130f06101c0850185614d13565b856101a00135614069565b61311261310c6101e0850185614cb2565b84614175565b6020808401355f81815261011a909252604090912060808501359055610119556101bd819055613167610180840135610140850135610100860135604080519384526020840192909252908201526060902090565b6101bf5580602084013561317a84614f71565b60408051873581526080880135602082015291955085917fa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb910160405180910390a492915050565b5f604051858152846020820152604060e0880160408301378360808201528260a082015260a0610120880160c083013761018081016101c088013588018035602081026020830184376020029091206101608301525061018090207f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190069695505050505050565b6040805160018082528183019092525f916020808301908036833701905050905084815f8151811061327e5761327e614d9a565b6020908102919091018101919091525f85815261011b90915260409020546001600160a01b0316806132dc576040517f69ed70ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80826001600160a01b0316637e4f7a8a60e01b87878760405160240161330593929190615065565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161337091906150d6565b5f604051808303815f865af19150503d805f81146133a9576040519150601f19603f3d011682016040523d82523d5f602084013e6133ae565b606091505b509150915081613455578051156133f357602081017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81511663ca389c4460e01b178152815181fd5b6040517fca389c4400000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f556e6b6e6f776e000000000000000000000000000000000000000000000000006044820152606401610fee565b5f8180602001905181019061346a91906150e1565b9050806134a3576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b600881901c5f90815261014f6020526040902054600160ff83161b1615613504576040517f335a4a9000000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b600881901c5f90815261014f602052604090208054600160ff84161b17905550565b5f806135476001613538876002615221565b6135429190614c4b565b614202565b90508063ffffffff168463ffffffff16111561359f576040517ff7ec909700000000000000000000000000000000000000000000000000000000815263ffffffff808616600483015282166024820152604401610fee565b865f5b8681101561362557600163ffffffff8716821c811690036135ef576135e88888838181106135d2576135d2614d9a565b90506020020135835f9182526020526040902090565b915061361d565b61361a8289898481811061360557613605614d9a565b905060200201355f9182526020526040902090565b91505b6001016135a2565b509092149695505050505050565b5f61363f60208461522c565b15613676576040517f6426c6c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f729eebce00000000000000000000000000000000000000000000000000000000835b801561372b57602081039050808601357fff000000000000000000000000000000000000000000000000000000000000008116156136dc57604051838152600481fd5b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001817f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff0000000187870908935050613699565b50509392505050565b7f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001840693505f80600a6001600160a01b0316878787878760405160200161377f959493929190615264565b60408051601f1981840301815290829052613799916150d6565b5f60405180830381855afa9150503d805f81146137d1576040519150601f19603f3d011682016040523d82523d5f602084013e6137d6565b606091505b509150915081613812576040517fa71194af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604081511461385a578051604080517ff75db381000000000000000000000000000000000000000000000000000000008152610fee9290600401918252602082015260400190565b602081015160408201516110008214158061389557507f73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff000000018114155b156134a3576040517f68dcad5f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015f90815261014e60208181526040808420548452848252808420868552929091528083208290555190918391839186917fea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f63399190a4505050565b5f54610100900460ff166139e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b83811015613af057848482818110613a0457613a04614d9a565b9050604002016020013560db5f878785818110613a2357613a23614d9a565b613a3992602060409092020190810191506146e0565b6008811115613a4a57613a4a614bb2565b6008811115613a5b57613a5b614bb2565b815260208101919091526040015f2055848482818110613a7d57613a7d614d9a565b90506040020160200135858583818110613a9957613a99614d9a565b613aaf92602060409092020190810191506146e0565b6008811115613ac057613ac0614bb2565b6040517f33aa8fd1ce49e1761bc8d27fd53414bfefc45d690feed0ce55019d7d3aec6091905f90a36001016139ea565b505f5b81811015613bf957828282818110613b0d57613b0d614d9a565b9050604002016020013560dc5f858585818110613b2c57613b2c614d9a565b613b4292602060409092020190810191506146e0565b6008811115613b5357613b53614bb2565b6008811115613b6457613b64614bb2565b815260208101919091526040015f2055828282818110613b8657613b86614d9a565b90506040020160200135838383818110613ba257613ba2614d9a565b613bb892602060409092020190810191506146e0565b6008811115613bc957613bc9614bb2565b6040517fe7bf4b8dc0c17a52dc9e52323a3ab61cb2079db35f969125b1f8a3d984c6f6c2905f90a3600101613af3565b5050505050565b5f54610100900460ff16613c96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b613c9e61424f565b613ca661424f565b613cae61424f565b613cb882826142e5565b5050600160e455565b5f54610100900460ff16613d57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f5b81811015611143575f838383818110613d7457613d74614d9a565b613d8a9260206040909202019081019150614c97565b6001600160a01b031603613dca576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828282818110613ddc57613ddc614d9a565b905060400201602001355f801b03613e20576040517f0742d05300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e67838383818110613e3557613e35614d9a565b90506040020160200135848484818110613e5157613e51614d9a565b6122c89260206040909202019081019150614c97565b600101613d59565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff161561119b575f8281526065602090815260408083206001600160a01b038516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f8281526065602090815260408083206001600160a01b038516845290915290205460ff1661119b57613f408161444b565b613f4b83602061445d565b604051602001613f5c92919061528a565b60408051601f19818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fee91600401614757565b815f03613fde57801561119b576040517f0c25659200000000000000000000000000000000000000000000000000000000815260048101829052602401610fee565b80614018576040517f5228f4c800000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f82815261014e6020526040902054811461119b576040517f36459fa00000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610fee565b5f5b8281101561416f576101505f85858481811061408957614089614d9a565b9050602002013581526020019081526020015f20545f146140f2578383828181106140b6576140b6614d9a565b905060200201356040517fe5d14425000000000000000000000000000000000000000000000000000000008152600401610fee91815260200190565b816101505f86868581811061410957614109614d9a565b9050602002013581526020019081526020015f20819055508184848381811061413457614134614d9a565b905060200201357f300e6f978eee6a4b0bba78dd8400dc64fd5652dbfc868a2258e16d0977be222b60405160405180910390a360010161406b565b50505050565b61418060028361522c565b156141ba576040517f0c91d77600000000000000000000000000000000000000000000000000000000815260048101839052602401610fee565b5f805b83811015613bf9576040518582013560f01c9250838301907f3c116827db9db3a30c1a25db8b0ee4bab9d2b223560209cfd839601b621c726d905f90a26002016141bd565b5f63ffffffff82111561424b576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526020600482015260248101839052604401610fee565b5090565b5f54610100900460ff16612ce3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b5f54610100900460ff1661437b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610fee565b815f036143b4576040517fb5ed5a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f036143ed576040517fd10d72bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609782905560988190556144018242614c5e565b60998190556097546098546040805192835260208301919091528101919091527f8f805c372b66240792580418b7328c0c554ae235f0932475c51b026887fe26a9906060016124bb565b6060610f6a6001600160a01b03831660145b60605f61446b836002614c80565b614476906002614c5e565b67ffffffffffffffff81111561448e5761448e614e03565b6040519080825280601f01601f1916602001820160405280156144b8576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106144ee576144ee614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061455057614550614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61458a846002614c80565b614595906001614c5e565b90505b6001811115614631577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106145d6576145d6614d9a565b1a60f81b8282815181106145ec576145ec614d9a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c9361462a816152f4565b9050614598565b50831561469a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610fee565b9392505050565b5f602082840312156146b1575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461469a575f80fd5b5f602082840312156146f0575f80fd5b81356009811061469a575f80fd5b5f6020828403121561470e575f80fd5b5035919050565b6001600160a01b0381168114611a69575f80fd5b5f806040838503121561473a575f80fd5b82359150602083013561474c81614715565b809150509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8083601f84011261479c575f80fd5b50813567ffffffffffffffff8111156147b3575f80fd5b6020830191508360208285010111156147ca575f80fd5b9250929050565b5f805f805f805f8060e0898b0312156147e8575f80fd5b88356147f381614715565b9750602089013561480381614715565b96506040890135955060608901359450608089013561482181614715565b935060a089013567ffffffffffffffff81111561483c575f80fd5b6148488b828c0161478c565b999c989b50969995989497949560c00135949350505050565b5f805f8060608587031215614874575f80fd5b843567ffffffffffffffff81111561488a575f80fd5b6148968782880161478c565b90955093505060208501359150604085013567ffffffffffffffff8111156148bc575f80fd5b850161020081880312156148ce575f80fd5b939692955090935050565b5f602082840312156148e9575f80fd5b813567ffffffffffffffff8111156148ff575f80fd5b8201610140818503121561469a575f80fd5b5f805f60608486031215614923575f80fd5b833567ffffffffffffffff811115614939575f80fd5b84016060818703121561494a575f80fd5b95602085013595506040909401359392505050565b5f805f8060608587031215614972575f80fd5b843567ffffffffffffffff811115614988575f80fd5b8501601f81018713614998575f80fd5b803567ffffffffffffffff8111156149ae575f80fd5b8760208260051b84010111156149c2575f80fd5b602091820198909750908601359560400135945092505050565b5f805f80606085870312156149ef575f80fd5b84356149fa81614715565b935060208501359250604085013567ffffffffffffffff811115614a1c575f80fd5b614a288782880161478c565b95989497509550505050565b5f60208284031215614a44575f80fd5b813567ffffffffffffffff811115614a5a575f80fd5b8201610160818503121561469a575f80fd5b5f805f60608486031215614a7e575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112614aa5575f80fd5b50813567ffffffffffffffff811115614abc575f80fd5b6020830191508360208260061b85010111156147ca575f80fd5b5f805f805f805f6080888a031215614aec575f80fd5b873567ffffffffffffffff811115614b02575f80fd5b614b0e8a828b01614a95565b909850965050602088013567ffffffffffffffff811115614b2d575f80fd5b614b398a828b01614a95565b909650945050604088013567ffffffffffffffff811115614b58575f80fd5b614b648a828b01614a95565b9094509250506060880135614b7881614715565b8091505092959891949750929550565b5f8060408385031215614b99575f80fd5b8235614ba481614715565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6020810160098310614c18577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b91905290565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610f6a57610f6a614c1e565b80820180821115610f6a57610f6a614c1e565b818382375f9101908152919050565b8082028115828204841417610f6a57610f6a614c1e565b5f60208284031215614ca7575f80fd5b813561469a81614715565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614ce5575f80fd5b83018035915067ffffffffffffffff821115614cff575f80fd5b6020019150368190038213156147ca575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d46575f80fd5b83018035915067ffffffffffffffff821115614d60575f80fd5b6020019150600581901b36038213156147ca575f80fd5b5f60208284031215614d87575f80fd5b813563ffffffff8116811461469a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112614df9575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715614e5357614e53614e03565b60405290565b5f82601f830112614e68575f80fd5b813567ffffffffffffffff811115614e8257614e82614e03565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715614eb157614eb1614e03565b604052818152838201602001851015614ec8575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60a08236031215614ef4575f80fd5b614efc614e30565b82358152602083013567ffffffffffffffff811115614f19575f80fd5b614f2536828601614e59565b602083015250604083013567ffffffffffffffff811115614f44575f80fd5b614f5036828601614e59565b60408301525060608381013590820152608092830135928101929092525090565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fa157614fa1614c1e565b5060010190565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b858152846020820152836040820152608060608201525f614ff6608083018486614fa8565b979650505050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615034575f80fd5b83018035915067ffffffffffffffff82111561504e575f80fd5b6020019150600681901b36038213156147ca575f80fd5b604081525f615078604083018587614fa8565b82810360208401528084518083526020830191506020860192505f5b818110156150b2578351835260209384019390920191600101615094565b5090979650505050505050565b5f81518060208401855e5f93019283525090919050565b5f61469a82846150bf565b5f602082840312156150f1575f80fd5b8151801515811461469a575f80fd5b6001815b600184111561513b5780850481111561511f5761511f614c1e565b600184161561512d57908102905b60019390931c928002615104565b935093915050565b5f8261515157506001610f6a565b8161515d57505f610f6a565b8160018114615173576002811461517d57615199565b6001915050610f6a565b60ff84111561518e5761518e614c1e565b50506001821b610f6a565b5060208310610133831016604e8410600b84101617156151bc575081810a610f6a565b6151e77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615100565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561521957615219614c1e565b029392505050565b5f61469a8383615143565b5f8261525f577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500690565b8581528460208201528360408201525f614ff661528460608401866150bf565b846150bf565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f6152bb60178301856150bf565b7f206973206d697373696e6720726f6c652000000000000000000000000000000081526152eb60118201856150bf565b95945050505050565b5f8161530257615302614c1e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220f37ab9d49b246192cc1f4c0273d18fcd431dc83c67e6b7fb35993ccad3328d4e64736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.