CairoFactRegistryModule

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "@HerodotusDev/solidity-mmr/src/lib/StatelessMmr.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;

import "./StatelessMmrHelpers.sol";

///    _____       _ _     _ _ _           __  __ __  __ _____
///   / ____|     | (_)   | (_) |         |  \/  |  \/  |  __ \
///  | (___   ___ | |_  __| |_| |_ _   _  | \  / | \  / | |__) |
///   \___ \ / _ \| | |/ _` | | __| | | | | |\/| | |\/| |  _  /
///   ____) | (_) | | | (_| | | |_| |_| | | |  | | |  | | | \ \
///  |_____/ \___/|_|_|\__,_|_|\__|\__, | |_|  |_|_|  |_|_|  \_\
///                                 __/ |
///                                |___/

///
/// @title StatelessMmr -- A Solidity implementation of Merkle Mountain Range
/// @author Herodotus Ltd
/// @notice Library for appending bytes32 values (i.e., acting as an accumulator)
///         and verifying Merkle inclusion proofs
///
library StatelessMmr {
    error InvalidProof();
    error IndexOutOfBounds();
    error InvalidRoot();
    error InvalidPeaksArrayLength();

    ///
    /// @notice Append a new element to the MMR
    /// @param elem Element to append
    /// @param peaks The latest peaks
    /// @param lastElementsCount The latest elements count
    /// @param lastRoot  The latest root
    /// @return The updated elements count and the new root hash of the tree
    ///
    function append(
        bytes32 elem,
        bytes32[] memory peaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32) {
        (uint updatedElementsCount, bytes32 newRoot, ) = doAppend(
            elem,
            peaks,
            lastElementsCount,
            lastRoot
        );

        return (updatedElementsCount, newRoot);
    }

    ///
    /// Same as `append` but also returns the updated peaks
    ///
    function appendWithPeaksRetrieval(
        bytes32 elem,
        bytes32[] memory peaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32, bytes32[] memory) {
        (
            uint updatedElementsCount,
            bytes32 newRoot,
            bytes32[] memory updatedPeaks
        ) = doAppend(elem, peaks, lastElementsCount, lastRoot);

        return (updatedElementsCount, newRoot, updatedPeaks);
    }

    ///
    /// @param elems Elements to append (in order)
    /// @param peaks The latest peaks
    /// @param lastElementsCount The latest elements count
    /// @param lastRoot The latest tree root hash
    /// @return The newest elements count and the newest tree root hash
    ///
    function multiAppend(
        bytes32[] memory elems,
        bytes32[] memory peaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32) {
        uint elementsCount = lastElementsCount;
        bytes32 root = lastRoot;
        bytes32[] memory updatedPeaks = peaks;

        for (uint i = 0; i < elems.length; ++i) {
            (elementsCount, root, updatedPeaks) = appendWithPeaksRetrieval(
                elems[i],
                updatedPeaks,
                elementsCount,
                root
            );
        }
        return (elementsCount, root);
    }

    ///
    /// Same as `multiAppend` but also returns the updated peaks
    ///
    function multiAppendWithPeaksRetrieval(
        bytes32[] memory elems,
        bytes32[] memory peaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32, bytes32[] memory) {
        uint elementsCount = lastElementsCount;
        bytes32 root = lastRoot;
        bytes32[] memory updatedPeaks = peaks;

        for (uint i = 0; i < elems.length; ++i) {
            (elementsCount, root, updatedPeaks) = appendWithPeaksRetrieval(
                elems[i],
                updatedPeaks,
                elementsCount,
                root
            );
        }
        return (elementsCount, root, updatedPeaks);
    }

    ///
    /// @notice Efficient version of `multiAppend` that takes in all the precomputed peaks
    /// @param elems Elements to append (in order)
    /// @param allPeaks All the precomputed peaks computed off-chain (more gas efficient)
    /// @param lastElementsCount The latest elements count
    /// @param lastRoot The latest tree root hash
    /// @return The newest elements count and the newest tree root hash
    ///
    function multiAppendWithPrecomputedPeaks(
        bytes32[] memory elems,
        bytes32[][] memory allPeaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32) {
        uint elementsCount = lastElementsCount;
        bytes32 root = lastRoot;

        for (uint i = 0; i < elems.length; ++i) {
            (elementsCount, root) = append(
                elems[i],
                allPeaks[i],
                elementsCount,
                root
            );
        }
        return (elementsCount, root);
    }

    ///
    /// @notice Verify a Merkle inclusion proof
    /// @dev Reverts if the proof is invalid
    /// @param proof The Merkle inclusion proof
    /// @param peaks The peaks at the time of inclusion
    /// @param elementsCount The element count at the time of inclusion
    /// @param root The tree root hash at the time of inclusion
    ///
    function verifyProof(
        uint index,
        bytes32 value,
        bytes32[] memory proof,
        bytes32[] memory peaks,
        uint elementsCount,
        bytes32 root
    ) internal pure {
        if (index > elementsCount) {
            revert IndexOutOfBounds();
        }
        bytes32 computedRoot = computeRoot(peaks, bytes32(elementsCount));
        if (computedRoot != root) {
            revert InvalidRoot();
        }

        bytes32 topPeak = getProofTopPeak(0, value, index, proof);

        bool isValid = StatelessMmrHelpers.arrayContains(topPeak, peaks);
        if (!isValid) {
            revert InvalidProof();
        }
    }

    ///   _    _      _                   ______                _   _
    ///  | |  | |    | |                 |  ____|              | | (_)
    ///  | |__| | ___| |_ __   ___ _ __  | |__ _   _ _ __   ___| |_ _  ___  _ __  ___
    ///  |  __  |/ _ \ | '_ \ / _ \ '__| |  __| | | | '_ \ / __| __| |/ _ \| '_ \/ __|
    ///  | |  | |  __/ | |_) |  __/ |    | |  | |_| | | | | (__| |_| | (_) | | | \__ \
    ///  |_|  |_|\___|_| .__/ \___|_|    |_|   \__,_|_| |_|\___|\__|_|\___/|_| |_|___/
    ///                | |
    ///                |_|

    ///
    /// @notice Computes the root hash of the given peaks and tree size
    /// @param peaks Peaks to compute the root from
    /// @param size Tree size to to compute the root from
    /// @return The root hash of the following peaks and tree size
    ///
    function computeRoot(
        bytes32[] memory peaks,
        bytes32 size
    ) internal pure returns (bytes32) {
        bytes32 baggedPeaks = bagPeaks(peaks);
        return keccak256(abi.encode(size, baggedPeaks));
    }

    ///
    /// @notice Bag the peaks: recursively hashing peaks together to form a single hash
    /// @param peaks The peaks to bag
    /// @return The bagged peaks
    ///
    function bagPeaks(bytes32[] memory peaks) internal pure returns (bytes32) {
        if (peaks.length < 1) {
            revert InvalidPeaksArrayLength();
        }
        if (peaks.length == 1) {
            return peaks[0];
        }

        uint len = peaks.length;
        bytes32 root0 = keccak256(abi.encode(peaks[len - 2], peaks[len - 1]));
        bytes32[] memory reversedPeaks = new bytes32[](len - 2);
        for (uint i = 0; i < len - 2; i++) {
            reversedPeaks[i] = peaks[len - 3 - i];
        }

        bytes32 bags = root0;
        for (uint i = 0; i < reversedPeaks.length; i++) {
            bags = keccak256(abi.encode(reversedPeaks[i], bags));
        }
        return bags;
    }

    function doAppend(
        bytes32 elem,
        bytes32[] memory peaks,
        uint lastElementsCount,
        bytes32 lastRoot
    ) internal pure returns (uint, bytes32, bytes32[] memory) {
        uint elementsCount = lastElementsCount + 1;
        if (lastElementsCount == 0) {
            bytes32 root0 = elem;
            bytes32 firstRoot = keccak256(abi.encode(uint(1), root0));
            bytes32[] memory newPeaks = new bytes32[](1);
            newPeaks[0] = root0;
            return (elementsCount, firstRoot, newPeaks);
        }

        uint leafCount = StatelessMmrHelpers.mmrSizeToLeafCount(
            elementsCount - 1
        );
        uint numberOfPeaks = StatelessMmrHelpers.countOnes(leafCount);
        if (peaks.length != numberOfPeaks) {
            revert InvalidPeaksArrayLength();
        }

        bytes32 computedRoot = computeRoot(peaks, bytes32(lastElementsCount));
        if (computedRoot != lastRoot) {
            revert InvalidRoot();
        }

        bytes32[] memory appendPeaks = StatelessMmrHelpers.newArrWithElem(
            peaks,
            elem
        );

        uint appendNoMerges = StatelessMmrHelpers.leafCountToAppendNoMerges(leafCount);
        bytes32[] memory updatedPeaks = appendPerformMerging(
            appendPeaks,
            appendNoMerges
        );

        uint updatedElementsCount = elementsCount + appendNoMerges;

        bytes32 newRoot = computeRoot(
            updatedPeaks,
            bytes32(updatedElementsCount)
        );
        return (updatedElementsCount, newRoot, updatedPeaks);
    }

    function appendPerformMerging(
        bytes32[] memory peaks,
        uint noMerges
    ) internal pure returns (bytes32[] memory) {
        uint peaksLen = peaks.length;
        bytes32 accHash = peaks[peaksLen - 1];
        for (uint i = 0; i < noMerges; i++) {
            bytes32 hash = peaks[peaksLen - i - 2];
            accHash = keccak256(abi.encode(hash, accHash));
        }
        bytes32[] memory newPeaks = new bytes32[](peaksLen - noMerges);
        for (uint i = 0; i < peaksLen - noMerges - 1; i++) {
            newPeaks[i] = peaks[i];
        }
        newPeaks[peaksLen - noMerges - 1] = accHash;

        return newPeaks;
    }

    function getProofTopPeak(
        uint height,
        bytes32 hash,
        uint elementsCount,
        bytes32[] memory proof
    ) internal pure returns (bytes32) {
        uint leafIndex = StatelessMmrHelpers.mmrIndexToLeafIndex(elementsCount);
        for (uint i = 0; i < proof.length; ++i) {
            bytes32 currentSibling = proof[i];

            bool isRightChild = leafIndex % 2 == 1;
            if (isRightChild) {
                bytes32 hashed = keccak256(abi.encode(currentSibling, hash));
                elementsCount += 1;

                hash = hashed;
            } else {
                bytes32 hashed = keccak256(abi.encode(hash, currentSibling));
                elementsCount += 2 << height;

                hash = hashed;
            }
            ++height;
            leafIndex /= 2;
        }
        return hash;
    }
}
"
    },
    "@HerodotusDev/solidity-mmr/src/lib/StatelessMmrHelpers.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;

library StatelessMmrHelpers {
    // Returns the height of a given `index`. The height of the root is 0
    function getHeight(uint index) internal pure returns (uint) {
        require(index >= 1, "index must be at least 1");

        uint bits = bitLength(index);
        uint ones = allOnes(bits);

        if (index != ones) {
            uint shifted = 1 << (bits - 1);
            uint recHeight = getHeight(index - (shifted - 1));
            return recHeight;
        }

        return bits - 1;
    }

    // Returns the number of bits in `num`
    function bitLength(uint256 num) internal pure returns (uint256) {
        require(num >= 0, "num must be greater than or equal to zero");

        uint256 bitPosition = 0;
        uint256 curN = 1;
        while (num >= curN) {
            bitPosition += 1;
            curN <<= 1;
        }
        return bitPosition;
    }

    // Returns a number having all its bits set to 1 for a given `bitsLength`
    function allOnes(uint256 bitsLength) internal pure returns (uint256) {
        require(bitsLength >= 0, "bitsLength must be greater or equal to zero");
        return (1 << bitsLength) - 1;
    }

    // Returns a number of ones in bit representation of a number
    function countOnes(uint256 num) internal pure returns (uint256) {
        uint256 count = 0;
        for (; num > 0; count++) {
            num = num & (num - 1);
        }
        return count;
    }

    // Returns the sibling offset from `height`
    function siblingOffset(uint256 height) internal pure returns (uint256) {
        return (2 << height) - 1;
    }

    // Returns the parent offset from `height`
    function parentOffset(uint256 height) internal pure returns (uint256) {
        return 2 << height;
    }

    // Returns number of leaves for a given mmr size
    function mmrSizeToLeafCount(uint256 mmrSize) internal pure returns (uint256) {
        uint256 leafCount = 0;
        uint256 mountainLeafCount = 1 << bitLength(mmrSize);
        for(; mountainLeafCount > 0; mountainLeafCount /= 2) {
            uint256 mountainSize = 2 * mountainLeafCount - 1;
            if (mountainSize <= mmrSize) {
                leafCount += mountainLeafCount;
                mmrSize -= mountainSize;
            }
        }
        require(mmrSize == 0, "mmrSize can't be associated with a valid MMR size");
        return leafCount;
    }

    // Returns leaf index (0-based) for a given mmr (element) index
    function mmrIndexToLeafIndex(uint256 mmrIndex) internal pure returns (uint256) {
        return mmrSizeToLeafCount(mmrIndex - 1);
    }

    function leafCountToAppendNoMerges(uint256 leafCount) internal pure returns (uint256) {
        uint256 count = 0;
        while(leafCount > 0 && (leafCount & 1) == 1) {
            count += 1;
            leafCount /= 2;
        }
        return count;
    }

    // Creates a new array from source and returns a new one containing all previous elements + `elem`
    function newArrWithElem(
        bytes32[] memory sourceArr,
        bytes32 elem
    ) internal pure returns (bytes32[] memory) {
        bytes32[] memory outputArray = new bytes32[](sourceArr.length + 1);
        uint i = 0;
        for (; i < sourceArr.length; i++) {
            outputArray[i] = sourceArr[i];
        }
        outputArray[i] = elem;
        return outputArray;
    }

    // Returns true if `elem` is in `arr`
    function arrayContains(
        bytes32 elem,
        bytes32[] memory arr
    ) internal pure returns (bool) {
        for (uint i = 0; i < arr.length; ++i) {
            if (arr[i] == elem) {
                return true;
            }
        }
        return false;
    }
}
"
    },
    "src/interfaces/external/IAggregatorsFactory.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

interface IAggregatorsFactory {
    error AccessControlBadConfirmation();
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
    error ERC1167FailedCreateClone();

    event AggregatorCreation(address aggregator, uint256 newAggregatorId, uint256 detachedFromAggregatorId);
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
    event Upgrade(address oldTemplate, address newTemplate);
    event UpgradeProposal(address newTemplate);

    function DEFAULT_ADMIN_ROLE() external view returns (bytes32);

    function DELAY() external view returns (uint256);

    function KECCAK_MMR_INITIAL_ROOT() external view returns (bytes32);

    function OPERATOR_ROLE() external view returns (bytes32);

    function POSEIDON_MMR_INITIAL_ROOT() external view returns (bytes32);

    function aggregatorsById(uint256) external view returns (address);

    function aggregatorsCount() external view returns (uint256);

    function createAggregator(uint256 aggregatorId) external returns (address);

    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    function grantRole(bytes32 role, address account) external;

    function hasRole(bytes32 role, address account) external view returns (bool);

    function proposeUpgrade(address newTemplate) external;

    function renounceRole(bytes32 role, address callerConfirmation) external;

    function revokeRole(bytes32 role, address account) external;

    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    function template() external view returns (address);

    function upgrade(uint256 updateId) external;

    function upgrades(uint256) external view returns (uint256 timestamp, address newTemplate);

    function upgradesCount() external view returns (uint256);
}
"
    },
    "src/interfaces/external/IFactsRegistry.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

interface IFactsRegistry {
    function isValid(bytes32 fact) external view returns (bool);

    function setValid(bytes32 fact) external;
}
"
    },
    "src/interfaces/external/IStarknet.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IStarknet {
    function stateBlockNumber() external view returns (int256);

    function stateBlockHash() external view returns (uint256);
}
"
    },
    "src/interfaces/ILibSatellite.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

/// @notice This is IMMUTABLE! without re-deploying the whole Satellite Diamond!
interface ILibSatellite {
    // ========================= Types ========================= //

    struct Module {
        address moduleAddress;
        bytes4[] functionSelectors;
    }

    struct ModuleAddressAndPosition {
        address moduleAddress;
        uint96 functionSelectorPosition; // position in moduleFunctionSelectors.functionSelectors array
    }

    struct ModuleFunctionSelectors {
        bytes4[] functionSelectors;
        uint256 moduleAddressPosition; // position of moduleAddress in moduleAddresses array
    }

    /// @dev Add=0, Replace=1, Remove=2
    enum ModuleMaintenanceAction {
        Add,
        Replace,
        Remove
    }

    struct ModuleMaintenance {
        address moduleAddress;
        ModuleMaintenanceAction action;
        bytes4[] functionSelectors;
    }

    /// @notice This struct represents a Merkle Mountain Range accumulating provably valid block hashes
    /// @dev each MMR is mapped to a unique ID also referred to as mmrId
    struct MmrInfo {
        /// @notice isOffchainGrown if true the MMR can be grown with Offchain Growing Modules
        /// @notice if false the MMR can be grown with Onchain Growing Module
        bool isOffchainGrown;
        /// @notice latestSize represents the latest size of the MMR
        uint256 latestSize;
        /// @notice mmrSizeToRoot maps the  MMR size => the MMR root, that way we have automatic versioning
        mapping(uint256 => bytes32) mmrSizeToRoot;
    }

    struct SatelliteData {
        /// @notice satelliteAddress is the address of the satellite deployed on the chain given in the mapping
        /// @dev it is uint256 because Starknet addresses must fit
        uint256 satelliteAddress;
        /// @notice inboxAddress is the address of the contract that sends messages from our chain to the chain of the satellite
        /// @dev if inboxAddress is non-zero, satellite can send messages to that chain
        address inboxAddress;
        /// @notice sendMessageSelector is the selector of the satellite's function that sends message to the destination chain
        /// @dev if satellite is not connected (inboxAddress == 0x0), sendMessageSelector must be 0
        bytes4 sendMessageSelector;
        /// @notice canReceive is true if this satellite can receive messages from the chain given in the mapping
        bool canReceive;
    }

    struct SatelliteStorage {
        // ========================= Diamond-related storage ========================= //

        /// @dev maps function selector to the module address and the position of the selector in the moduleFunctionSelectors.selectors array
        mapping(bytes4 => ModuleAddressAndPosition) selectorToModuleAndPosition;
        /// @dev maps module addresses to function selectors
        mapping(address => ModuleFunctionSelectors) moduleFunctionSelectors;
        /// @dev module addresses
        address[] moduleAddresses;
        /// @dev owner of the contract
        address contractOwner;
        //
        // ========================= Core Satellite storage ========================= //

        /// @dev mapping of ChainId => MMR ID => hashing function => MMR info
        /// @dev hashingFunction is a 32 byte keccak hash of the hashing function name, eg: keccak256("keccak256"), keccak256("poseidon")
        mapping(uint256 => mapping(uint256 => mapping(bytes32 => MmrInfo))) mmrs;
        /// @notice mapping of ChainId => hashing function => block number => block parent hash
        mapping(uint256 => mapping(bytes32 => mapping(uint256 => bytes32))) receivedParentHashes;
        //
        // ======================= Satellite Registry storage ======================= //

        /// @dev mapping of ChainId => SatelliteData struct
        mapping(uint256 => SatelliteData) satelliteRegistry;
        /// @dev set of (aliased) addresses of satellites that can send messages to our chain
        mapping(address => bool) senderSatellites;
        //
        // ========================== Satellite Ownership ========================== //

        mapping(address => bool) admins;
    }

    // ========================= Errors ========================= //

    /// @notice Error indicating the caller must be a satellite module
    error MustBeSatelliteModule();
    /// @notice Error indicating the caller must be the contract owner
    error MustBeContractOwner();
    /// @notice Error indicating the module maintenance action is incorrect
    error IncorrectModuleMaintenanceAction(ModuleMaintenanceAction action);
    /// @notice Error indicating there are no selectors in the module to maintenance
    error NoSelectorsInModuleToMaintenance();
    /// @notice Error indicating the module address is zero
    error AddModuleAddressZero();
    /// @notice Error indicating the function already exists
    error AddFunctionAlreadyExists(bytes4 selector);
    /// @notice Error indicating the function already exists
    error ReplaceFunctionWithSameFunction(bytes4 selector);
    /// @notice Error indicating the function does not exist
    error RemoveFunctionDoesNotExist();
    /// @notice Error indicating the function is immutable and cannot be removed
    error RemoveImmutableFunction();
    /// @notice Error indicating the init address is zero but calldata is not empty
    error InitAddressZeroButCalldataNotEmpty();
    /// @notice Error indicating the calldata is empty but init is not address(0)
    error CalldataEmptyButInitNotEmpty();
    /// @notice Error indicating the init function reverted
    error InitFunctionReverted(string errors);
    /// @notice Error indicating the address has no code
    error AddressHasNoCode(string details);

    // ========================= Events ========================= //

    /// @notice Event emitted when satellite maintenance occurs
    event SatelliteMaintenance(ModuleMaintenance[] _satelliteMaintenance, address _init, bytes _calldata);
    /// @notice Event emitted when ownership is transferred
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    /// @notice Event emitted when admins are updated
    event AdminsUpdated(address[] accounts, bool isAdmin);
}
"
    },
    "src/interfaces/ISatellite.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {ILibSatellite} from "./ILibSatellite.sol";
import {IExtendedOwnershipModule} from "./modules/IOwnershipModule.sol";
import {ISatelliteRegistryModule} from "./modules/ISatelliteRegistryModule.sol";
import {IMmrCoreModule} from "./modules/IMmrCoreModule.sol";
import {ISatelliteInspectorModule} from "./modules/ISatelliteInspectorModule.sol";
import {ISatelliteMaintenanceModule} from "./modules/ISatelliteMaintenanceModule.sol";
import {IEvmSharpMmrGrowingModule} from "./modules/growing/IEvmSharpMmrGrowingModule.sol";
import {IStarknetSharpMmrGrowingModule} from "./modules/growing/IStarknetSharpMmrGrowingModule.sol";
import {IEvmFactRegistryModule} from "./modules/IEvmFactRegistryModule.sol";
import {ICairoFactRegistryModule} from "./modules/ICairoFactRegistryModule.sol";
import {INativeParentHashFetcherModule} from "./modules/parent-hash-fetching/INativeParentHashFetcherModule.sol";
import {IStarknetParentHashFetcherModule} from "./modules/parent-hash-fetching/IStarknetParentHashFetcherModule.sol";
import {IReceiverModule} from "./modules/messaging/receiver/IReceiverModule.sol";
import {IEvmOnChainGrowingModule} from "./modules/growing/IEvmOnChainGrowingModule.sol";
import {IDataProcessorModule} from "./modules/IDataProcessorModule.sol";
import {IUniversalSenderModule} from "./modules/messaging/sender/IUniversalSenderModule.sol";
import {IL1ToArbitrumSenderModule} from "./modules/messaging/sender/IL1ToArbitrumSenderModule.sol";
import {IL1ToOptimismSenderModule} from "./modules/messaging/sender/IL1ToOptimismSenderModule.sol";
import {IArbitrumToApeChainSenderModule} from "./modules/messaging/sender/IArbitrumToApeChainSenderModule.sol";
import {IL1ToStarknetSenderModule} from "./modules/messaging/sender/IL1ToStarknetSenderModule.sol";
import {ILegacyContractsInteractionModule} from "./modules/growing/ILegacyContractsInteractionModule.sol";
import {IArbitrumParentHashFetcherModule} from "./modules/parent-hash-fetching/IArbitrumParentHashFetcherModule.sol";

interface ISatellite is
    ILibSatellite,
    IExtendedOwnershipModule,
    ISatelliteRegistryModule,
    IMmrCoreModule,
    ISatelliteInspectorModule,
    ISatelliteMaintenanceModule,
    IEvmSharpMmrGrowingModule,
    IEvmFactRegistryModule,
    ICairoFactRegistryModule,
    INativeParentHashFetcherModule,
    IEvmOnChainGrowingModule,
    IStarknetSharpMmrGrowingModule,
    IReceiverModule,
    IUniversalSenderModule,
    IL1ToArbitrumSenderModule,
    IL1ToOptimismSenderModule,
    IStarknetParentHashFetcherModule,
    IArbitrumParentHashFetcherModule,
    IDataProcessorModule,
    IArbitrumToApeChainSenderModule,
    IL1ToStarknetSenderModule,
    ILegacyContractsInteractionModule
{}
"
    },
    "src/interfaces/modules/common/IFactsRegistryCommon.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

interface IFactsRegistryCommon {
    error InvalidFact();
}
"
    },
    "src/interfaces/modules/common/ISharpMmrGrowingCommon.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {IFactsRegistryCommon} from "./IFactsRegistryCommon.sol";

interface ISharpMmrGrowingCommon is IFactsRegistryCommon {
    // Custom errors for better error handling and clarity
    error NotEnoughJobs();
    error UnknownParentHash();
    error AggregationError(string message); // Generic error with a message
    error AggregationBlockMismatch(string message);
    error GenesisBlockReached();
}
"
    },
    "src/interfaces/modules/growing/IEvmOnChainGrowingModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {Lib_RLPReader as RLPReader} from "../../../libraries/external/optimism/rlp/Lib_RLPReader.sol";
import {StatelessMmr} from "@HerodotusDev/solidity-mmr/src/lib/StatelessMmr.sol";

interface IEvmOnChainGrowingModule {
    // ========================= Types ========================= //

    struct MMRGrowResult {
        uint256 firstAppendedBlock;
        uint256 lastAppendedBlock;
        uint256 newMMRSize;
        bytes32 newMMRRoot;
    }

    // ========================= Functions ========================= //

    function onchainEvmAppendBlocksBatch(
        uint256 accumulatedChainId,
        uint256 mmrId,
        bool processFromReceivedBlockHash,
        bytes calldata ctx,
        bytes[] calldata headersSerialized
    ) external;
}
"
    },
    "src/interfaces/modules/growing/IEvmSharpMmrGrowingModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {Uint256Splitter} from "../../../libraries/internal/Uint256Splitter.sol";
import {IEvmFactRegistryModule} from "../../../interfaces/modules/IEvmFactRegistryModule.sol";
import {ISharpMmrGrowingCommon} from "../../../interfaces/modules/common/ISharpMmrGrowingCommon.sol";

interface IEvmSharpMmrGrowingModule is ISharpMmrGrowingCommon {
    // Representation of the Cairo program's output (raw unpacked)
    struct EvmJobOutput {
        uint256 fromBlockNumberHigh;
        uint256 toBlockNumberLow;
        bytes32 blockNPlusOneParentHashLow;
        bytes32 blockNPlusOneParentHashHigh;
        bytes32 blockNMinusRPlusOneParentHashLow;
        bytes32 blockNMinusRPlusOneParentHashHigh;
        bytes32 mmrPreviousRootPoseidon;
        bytes32 mmrPreviousRootKeccakLow;
        bytes32 mmrPreviousRootKeccakHigh;
        uint256 mmrPreviousSize;
        bytes32 mmrNewRootPoseidon;
        bytes32 mmrNewRootKeccakLow;
        bytes32 mmrNewRootKeccakHigh;
        uint256 mmrNewSize;
    }

    // Packed representation of the Cairo program's output (for gas efficiency)
    struct JobOutputPacked {
        uint256 blockNumbersPacked;
        bytes32 blockNPlusOneParentHash;
        bytes32 blockNMinusRPlusOneParentHash;
        bytes32 mmrPreviousRootPoseidon;
        bytes32 mmrPreviousRootKeccak;
        bytes32 mmrNewRootPoseidon;
        bytes32 mmrNewRootKeccak;
        uint256 mmrSizesPacked;
    }

    struct EvmSharpMmrGrowingModuleStorage {
        address _unused;
        uint256 _unused2;
        // Cairo program hash calculated with Poseidon (i.e., the off-chain block headers accumulator program)
        uint256 programHash;
        mapping(uint256 => bool) chainIds;
    }

    event ChainIdEnabledForEvmSharpMmrGrowingModule(uint256 chainId);

    function enableChainIdForEvmSharpMmrGrowingModule(uint256 chainId) external;

    function setEvmSharpMmrGrowingModuleProgramHash(uint256 programHash) external;

    function getEvmSharpMmrGrowingModuleProgramHash() external view returns (uint256);

    function createEvmSharpMmr(uint256 chainId, uint256 newMmrId, uint256 originalMmrId, uint256 mmrSize) external;

    function aggregateEvmSharpJobs(uint256 chainId, uint256 mmrId, JobOutputPacked[] calldata outputs) external;

    function allowContinueEvmSharpGrowingFrom(uint256 chainId, IEvmFactRegistryModule.BlockHeaderProof calldata headerProof) external;
}
"
    },
    "src/interfaces/modules/growing/ILegacyContractsInteractionModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {IAggregatorsFactory} from "../../external/IAggregatorsFactory.sol";
import {RootForHashingFunction} from "../IMmrCoreModule.sol";

interface ILegacyContractsInteractionModule {
    function loadLegacyEvmAggregatorMmr(IAggregatorsFactory aggregatorsFactory, uint256 aggregatedChainId, uint256 legacyMmrId, uint256 newMmrId) external;
    function loadLegacyStarknetAggregatorMmr(IAggregatorsFactory aggregatorsFactory, uint256 aggregatedChainId, uint256 legacyMmrId, uint256 newMmrId) external;

    event LegacyEvmAggregatorMmrLoadedV2(
        RootForHashingFunction[] rootsForHashingFunctions,
        uint256 size,
        uint256 newMmrId,
        uint256 legacyMmrId,
        uint256 aggregatedChainId,
        address sharpFactsAggregatorAddress
    );
}
"
    },
    "src/interfaces/modules/growing/IStarknetSharpMmrGrowingModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {Uint256Splitter} from "../../../libraries/internal/Uint256Splitter.sol";
import {ISharpMmrGrowingCommon} from "../../../interfaces/modules/common/ISharpMmrGrowingCommon.sol";

interface IStarknetSharpMmrGrowingModule is ISharpMmrGrowingCommon {
    // Representation of the Cairo program's output
    struct StarknetJobOutput {
        uint256 fromBlockNumberHigh;
        uint256 toBlockNumberLow;
        bytes32 blockNPlusOneParentHash;
        bytes32 blockNMinusRPlusOneParentHash;
        bytes32 mmrPreviousRootPoseidon;
        uint256 mmrPreviousSize;
        bytes32 mmrNewRootPoseidon;
        uint256 mmrNewSize;
    }

    struct StarknetSharpMmrGrowingModuleStorage {
        address _unused;
        // Either Starknet or Starknet Sepolia chain ID
        uint256 aggregatedChainId;
        // Cairo program hash calculated with Poseidon (i.e., the off-chain block headers accumulator program)
        uint256 programHash;
    }

    function initStarknetSharpMmrGrowingModule(uint256 starknetChainId) external;

    function setStarknetSharpMmrGrowingModuleProgramHash(uint256 programHash) external;

    function getStarknetSharpMmrGrowingModuleProgramHash() external view returns (uint256);

    function createStarknetSharpMmr(uint256 newMmrId, uint256 originalMmrId, uint256 mmrSize) external;

    function aggregateStarknetSharpJobs(uint256 mmrId, StarknetJobOutput[] calldata outputs) external;
}
"
    },
    "src/interfaces/modules/ICairoFactRegistryModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

// This module stores fact hashes for verified or mocked facts.

interface ICairoFactRegistryModule {
    event CairoFactSet(bytes32 factHash);
    event CairoFactRegistryExternalContractSet(address externalFactRegistry);
    event CairoMockedFactSet(bytes32 factHash);
    event CairoMockedFactRegistryFallbackContractSet(address fallbackMockedContract);
    event IsMockedForInternalSet(bool isMocked);

    // ========= Main function for end user ========= //

    /// Whether given fact is valid (mocked or verified).
    function isCairoFactValid(bytes32 factHash, bool isMocked) external view returns (bool);

    // ========= Fact registry with real verification ========= //

    /// Whether given fact was verified (not necessarily stored locally).
    function isCairoVerifiedFactValid(bytes32 factHash) external view returns (bool);

    /// Whether given fact hash was verified and stored locally.
    /// Verified facts can be moved if and only if this function returns true.
    function isCairoVerifiedFactStored(bytes32 factHash) external view returns (bool);

    /// Returns address of the contract that stores verified facts.
    function getCairoVerifiedFactRegistryContract() external view returns (address);

    /// Sets address of the contract that stores verified facts.
    function setCairoVerifiedFactRegistryContract(address contractAddress) external;

    /// Moves verified fact from external (fallback) contract to local storage.
    function storeCairoVerifiedFact(bytes32 factHash) external;

    // ========= Mocked fact registry ========= //

    /// Whether given fact was mocked.
    function isCairoMockedFactValid(bytes32 factHash) external view returns (bool);

    /// Mocks given fact. Caller must be an admin.
    function setCairoMockedFact(bytes32 factHash) external;

    /// Returns address of the contract that stores mocked facts.
    function getCairoMockedFactRegistryFallbackContract() external view returns (address);

    /// Sets address of the contract that stores mocked facts.
    function setCairoMockedFactRegistryFallbackContract(address fallbackMockedContract) external;

    // ========= For internal use in grower and data processor ========= //

    function isCairoFactValidForInternal(bytes32 factHash) external view returns (bool);

    function isMockedForInternal() external view returns (bool);

    function setIsMockedForInternal(bool isMocked) external;

    // ========= Moving facts ========= //

    function _receiveCairoFactHash(bytes32 factHash, bool isMocked) external;

    function getStorageSlotForCairoFact(bytes32 factHash, bool isMocked) external pure returns (bytes32);

    function moveCairoFactFromStorageProof(uint256 originChainId, uint256 blockNumber, bytes32 factHash, bool isMocked) external;
}
"
    },
    "src/interfaces/modules/IDataProcessorModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;

import {ModuleTask} from "../../libraries/internal/data-processor/ModuleCodecs.sol";
import {IFactsRegistryCommon} from "../modules/common/IFactsRegistryCommon.sol";

interface IDataProcessorModule is IFactsRegistryCommon {
    /// @notice The status of a task
    enum TaskStatus {
        NONE,
        SCHEDULED,
        FINALIZED
    }

    /// @notice The struct representing a task result
    struct TaskResult {
        TaskStatus status;
        bytes32 result;
    }

    /// @notice Storage structure for the module
    struct DataProcessorModuleStorage {
        address _unused;
        mapping(bytes32 => TaskResult) cachedTasksResult;
        mapping(bytes32 => bool) authorizedProgramHashes;
    }

    struct MmrData {
        uint256 chainId;
        uint256 mmrId;
        uint256 mmrSize;
    }

    /// @param mmrData For each used MMR, its chain ID, ID and size
    /// @param taskResultLow The low part of the task result
    /// @param taskResultHigh The high part of the task result
    /// @param taskHashLow The low part of the task hash
    /// @param taskHashHigh The high part of the task hash
    /// @param programHash The program hash that was used to compute the task
    struct TaskData {
        MmrData[] mmrData;
        uint256 taskResultLow;
        uint256 taskResultHigh;
        uint256 taskHashLow;
        uint256 taskHashHigh;
        bytes32 programHash;
    }

    /// @notice emitted when a task already stored
    event TaskAlreadyStored(bytes32 result);

    /// @notice emitted when a new module task is scheduled
    event ModuleTaskScheduled(ModuleTask moduleTask);

    /// Task is already registered
    error DoubleRegistration();
    /// Element is not in the batch
    error NotInBatch();
    /// Task is not finalized
    error NotFinalized();
    /// Unauthorized or inactive program hash
    error UnauthorizedProgramHash();
    /// Invalid MMR root
    error InvalidMmrRoot();
    /// Task is already finalized
    error TaskAlreadyFinalized();

    /// @notice Emitted when a task is finalized
    event TaskFinalized(bytes32 taskHash, bytes32 taskResult);

    /// @notice Emitted when a program hash is enabled
    event ProgramHashEnabled(bytes32 enabledProgramHash);

    /// @notice Emitted when some program hashes are disabled
    event ProgramHashesDisabled(bytes32[] disabledProgramHashes);

    // ========================= Setup Functions ========================= //

    /// @notice Set the program hash for the HDP program
    function setDataProcessorProgramHash(bytes32 programHash) external;

    /// @notice Disable some program hashes
    function disableProgramHashes(bytes32[] calldata programHashes) external;

    /// @notice Checks if a program hash is currently authorized
    function isProgramHashAuthorized(bytes32 programHash) external view returns (bool);

    // ========================= Core Functions ========================= //

    /// @notice Requests the execution of a task with a module
    /// @param moduleTask module task
    function requestDataProcessorExecutionOfTask(ModuleTask calldata moduleTask) external;

    /// @notice Authenticates the execution of a task is finalized
    ///         by verifying the locally computed fact with the FactsRegistry
    /// @param taskData The task data
    function authenticateDataProcessorTaskExecution(TaskData calldata taskData) external;

    /// @notice Returns the status of a task
    function getDataProcessorTaskStatus(bytes32 taskCommitment) external view returns (TaskStatus);

    /// @notice Returns the result of a finalized task
    function getDataProcessorFinalizedTaskResult(bytes32 taskCommitment) external view returns (bytes32);
}
"
    },
    "src/interfaces/modules/IEvmFactRegistryModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

interface IEvmFactRegistryModule {
    struct BlockHeaderProof {
        uint256 mmrId;
        uint128 mmrSize;
        uint256 mmrLeafIndex;
        bytes32[] mmrPeaks;
        bytes32[] mmrInclusionProof;
        bytes blockHeaderRlp;
    }

    enum BlockHeaderField {
        PARENT_HASH, // 0
        OMMERS_HASH, // 1
        BENEFICIARY, // 2
        STATE_ROOT, // 3
        TRANSACTIONS_ROOT, // 4
        RECEIPTS_ROOT, // 5
        LOGS_BLOOM, // 6 - not supported
        DIFFICULTY, // 7
        NUMBER, // 8 - not supported
        GAS_LIMIT, // 9
        GAS_USED, // 10
        TIMESTAMP, // 11
        EXTRA_DATA, // 12
        MIX_HASH, // 13
        NONCE // 14
    }

    struct BlockHeader {
        /// @dev Bitmask of saved fields (15 bits) - i-th bit corresponds to i-th field in `BlockHeaderField` enum.
        uint16 savedFields;
        mapping(BlockHeaderField => bytes32) fields;
    }

    enum AccountField {
        NONCE,
        BALANCE,
        STORAGE_ROOT,
        CODE_HASH,
        APE_FLAGS,
        APE_FIXED,
        APE_SHARES,
        APE_DEBT,
        APE_DELEGATE
    }

    struct Account {
        /// @dev Bitmask of saved fields (5 bits on Apechain, 4 bits otherwise).
        /// @dev First 4 bits are for NONCE, BALANCE, STORAGE_ROOT, CODE_HASH.
        /// @dev 5th bit (2^4) is for all ApeChain fields, so either all ApeChain fields are saved or none.
        uint8 savedFields;
        mapping(AccountField => bytes32) fields;
    }

    struct StorageSlot {
        bytes32 value;
        bool exists;
    }

    struct EvmFactRegistryModuleStorage {
        mapping(uint256 chainId => mapping(address account => mapping(uint256 blockNumber => Account))) accountField;
        mapping(uint256 chainId => mapping(address account => mapping(uint256 blockNumber => mapping(bytes32 slot => StorageSlot)))) accountStorageSlotValues;
        mapping(uint256 chainId => mapping(uint256 timestamp => uint256 blockNumber)) timestampToBlockNumber;
        mapping(uint256 chainId => mapping(uint256 blockNumber => BlockHeader)) blockHeader;
    }

    function APECHAIN_SHARE_PRICE_ADDRESS() external view returns (address);
    function APECHAIN_SHARE_PRICE_SLOT() external view returns (bytes32);

    // =============== Functions for End Users (Reads proven values) ============== //

    /// @notice Fetches block header field (e.g. block hash, state root or timestamp) of a block with a given block number on a given chain id.
    /// @notice Returns (true, value) if the field is saved, (false, 0) otherwise.
    function headerFieldSafe(uint256 chainId, uint256 blockNumber, BlockHeaderField field) external view returns (bool, bytes32);

    /// @notice Returns block header field (e.g. block hash, state root or timestamp) of a block with a given block number on a given chain id.
    /// @notice Reverts with "STORAGE_PROOF_HEADER_FIELD_NOT_SAVED" if the field is not saved.
    function headerField(uint256 chainId, uint256 blockNumber, BlockHeaderField field) external view returns (bytes32);

    /// @notice Fetches account field (e.g. nonce, balance or storage root) of a given account, at a given block number on a given chain id.
    /// @notice Returns (true, value) if the field is saved, (false, 0) otherwise.
    function accountFieldSafe(uint256 chainId, uint256 blockNumber, address account, AccountField field) external view returns (bool, bytes32);

    /// @notice Returns account field (e.g. nonce, balance or storage root) of a given account, at a given block number on a given chain id.
    /// @notice Reverts with "STORAGE_PROOF_ACCOUNT_FIELD_NOT_SAVED" if the field is not saved.
    function accountField(uint256 chainId, uint256 blockNumber, address account, AccountField field) external view returns (bytes32);

    /// @notice Fetches value of a given storage slot of a given account, at a given block number on a given chain id.
    /// @notice Returns (true, value) if the slot is saved, (false, 0) otherwise.
    function storageSlotSafe(uint256 chainId, uint256 blockNumber, address account, bytes32 slot) external view returns (bool, bytes32);

    /// @notice Returns value of a given storage slot of a given account, at a given block number on a given chain id.
    /// @notice Reverts with "STORAGE_PROOF_SLOT_NOT_SAVED" if the slot is not saved.
    function storageSlot(uint256 chainId, uint256 blockNumber, address account, bytes32 slot) external view returns (bytes32);

    /// @notice Finds block number with a biggest timestamp that is less than or equal to the given timestamp.
    /// @notice In other words, it answers what was the latest block at a given timestamp (including block with equal timestamp).
    /// @notice Returns (true, block number) if the timestamp is saved, (false, 0) otherwise.
    function timestampSafe(uint256 chainId, uint256 timestamp) external view returns (bool, uint256);

    /// @notice Returns block number with a biggest timestamp that is less than or equal to the given timestamp.
    /// @notice In other words, it answers what was the latest block at a given timestamp (including block with equal timestamp).
    /// @notice Reverts with "STORAGE_PROOF_TIMESTAMP_NOT_SAVED" if the timestamp is not saved.
    function timestamp(uint256 chainId, uint256 timestamp) external view returns (uint256);

    /// @notice Fetches the ApeChain's share price at a given block number.
    /// @notice Returns (true, share price) if the share price is saved for the given block number, (false, 0) otherwise.
    /// @notice Reverts with "STORAGE_PROOF_NOT_APECHAIN" if the given chain id does not support ApeChain-like account balances. TODO: add link
    function getApechainSharePriceSafe(uint256 chainId, uint256 blockNumber) external view returns (bool, uint256);

    /// @notice Returns the ApeChain's share price at a given block number.
    /// @notice Reverts with "STORAGE_PROOF_SHARE_PRICE_NOT_SAVED" if the share price is not saved for the given block number.
    /// @notice Reverts with "STORAGE_PROOF_NOT_APECHAIN" if the given chain id does not support ApeChain-like account balances. TODO: add link
    function getApechainSharePrice(uint256 chainId, uint256 blockNumber) external view returns (uint256);

    // ====================== Proving (Saves verified values) ===================== //

    /// @notice Verifies the headerProof and saves selected fields in the satellite.
    /// @notice Saved fields can be read with `headerFieldSafe` and `headerField` functions.
    /// @param headerFieldsToSave Bitmask of fields to save. i-th bit corresponds to i-th field in `BlockHeaderField` enum.
    function proveHeader(uint256 chainId, uint16 headerFieldsToSave, BlockHeaderProof calldata headerProof) external;

    /// @notice Verifies the accountTrieProof and saves selected fields in the satellite.
    /// @notice Saved fields can be read with `accountFieldSafe` and `accountField` functions.
    /// @notice Requires desired block's STATE_ROOT to be proven first with `proveHeader` function.
    /// @notice Additionally, if chainId is ApeChain and BALANCE bit is set, ApeChain's share price also has to be proven before calling this function.
    /// @notice To prove share price, storage slot with index `APECHAIN_SHARE_PRICE_SLOT` of account `APECHAIN_SHARE_PRICE_ADDRESS` at desired block has to be proven first with `proveStorage` function.
    /// @param accountFieldsToSave Bitmask of fields to save. First 4 bits correspond to NONCE, BALANCE, STORAGE_ROOT and CODE_HASH fields. Last bit (2^4) is responsible for all ApeChain fields, i.e. APE_FLAGS, APE_FIXED, APE_SHARES, APE_DEBT, APE_DELEGATE.
    function proveAccount(uint256 chainId, uint256 blockNumber, address account, uint8 accountFieldsToSave, bytes calldata accountTrieProof) external;

    /// @notice Verifies the storageSlotMptProof and saves the storage slot value in the satellite.
    /// @notice Saved value can be read with `storageSlotSafe` and `storageSlot` functions.
    /// @notice Requires account's STORAGE_ROOT to be proven first with `proveAccount` function.
    function proveStorage(uint256 chainId, uint256 blockNumber, address account, bytes32 slot, bytes calldata storageSlotMptProof) external;

    /// @notice Verifies that block with number blockNumberLow is the latest block with timestamp less than or equal to the given timestamp.
    /// @notice Requires timestamps of block with number blockNumberLow and blockNumberLow + 1 to be proven first with `proveHeader` function.
    function proveTimestamp(uint256 chainId, uint256 timestamp, uint256 blockNumberLow) external;

    // ============ Verifying (Verifies that storage proof is correct) ============ //

    /// @notice Verifies whether block header given by headerProof is present in MMR at given chain id, which means that it is a valid block.
    /// @notice Returns array of block header fields.
    /// @notice After successful verification, it can be assumed that block header with fields returned from this function is part of the chain with given chain id.
    function verifyHeader(uint256 chainId, BlockHeaderProof calldata headerProof) external view returns (bytes32[15] memory fields);

    /// @notice Verifies the accountMptProof against block's state root.
    /// @notice Returns account fields.
    /// @notice Reverts with "STORAGE_PROOF_SHOULD_BE_NON_APECHAIN" if the given chain id is ApeChain. (For ApeChain, use verifyOnlyAccountApechain instead)
    /// @notice IMPORTANT: It DOES NOT check whether state root is valid given the chain id, block number and account address.
    /// @notice To verify state root, use verifyHeader function.
    function verifyOnlyAccount(
        uint256 chainId,
        address account,
        bytes32 stateRoot,
        bytes calldata accountMptProof
    ) external pure returns (uint256 nonce, uint256 accountBalance, bytes32 codeHash, bytes32 storageRoot);

    /// @notice Verifies the accountMptProof and whether block given by headerProof is present in MMR at given chain id.
    /// @notice Returns account fields.
    /// @notice After successful verification, it can be assumed that account at given block number and chain id has field values returned from this function.
    function verifyAccount(
        uint256 chainId,
        uint256 blockNumber,
        address account,
        BlockHeaderProof calldata headerProof,
        bytes calldata accountMptProof
    ) external view returns (uint256 nonce, uint256 accountBalance, bytes32 codeHash, bytes32 storageRoot);

    /// @notice Verifies the accountMptProof against block's state root.
    /// @notice Returns account fields.
    /// @notice IMPORTANT: It DOES NOT check whether state root is valid given the chain id, block number and account address.
    /// @notice To verify state root, use verifyHeader function.
    /// @notice Reverts with "STORAGE_PROOF_SHOULD_BE_APECHAIN" if the given chain id is not ApeChain. (For non-ApeChain, use verifyOnlyAccount instead)
    function verifyOnlyAccountApechain(
        uint256 chainId,
        address account,
        bytes32 stateRoot,
        bytes calldata accountMptProof
    ) external pure returns (uint256 nonce, uint256 flags, uint256 fixed_, uint256 shares, uint256 debt, uint256 delegate, bytes32 codeHash, bytes32 storageRoot);

    /// @notice Verifies the accountMptProof and whether block given by headerProof is present in MMR at given chain id.
    /// @notice Returns account fields.
    /// @notice After successful verification, it can be assumed that account at given block number and chain id has field values returned from this function.
    function verifyAccountApechain(
        uint256 chainId,
        uint256 blockNumber,
        address account,
        BlockHeaderProof calldata headerProof,
        bytes calldata accountMptProof
    ) external view returns (uint256 nonce, uint256 flags, uint256 fixed_, uint256 shares, uint256 debt, uint256 delegate, bytes32 codeHash, bytes32 storageRoot);

    /// @notice Verifies the storageSlotMptProof against account's storage root.
    /// @notice Returns storage slot value.
    /// @notice IMPORTANT: It DOES NOT check whether storage root is valid given the chain id, block number, account address and slot index.
    /// @notice To verify storage root, use verifyOnlyAccount function.
    function verifyOnlyStorage(bytes32 slot, bytes32 storageRoot, bytes calldata storageSlotMptProof) external pure returns (bytes32 slotValue);

    /// @notice Verifies the storageSlotMptProof, accountMptProof and whether block given by headerProof is present in MMR at given chain id.
    /// @notice Returns storage slot value.
    /// @notice After successful verification, it can be assumed that given slot index of the account at block number and chain id has value returned from this function.
    function verifyStorage(
        uint256 chainId,
        uint256 blockNumber,
        address account,
        bytes32 slot,
        BlockHeaderProof calldata headerProof,
        bytes calldata accountMptProof,
        bytes calldata storageSlotMptProof
    ) external view returns (bytes32 slotValue);

    /// @notice Verifies that block with number blockNumberLow is the latest block with timestamp less than or equal to the given timestamp.
    /// @notice IMPORTANT: It DOES NOT check if blockTimestampLow and High correspond to blockNumberLow and blockNumberLow + 1.
    /// @notice Additionally, following has to be verified:
    /// @notice - blockTimestampLow is the timestamp of block with number blockNumberLow - `headerField(chainId, blockNumberLow, BlockHeaderField.TIMESTAMP) == blockTimestampLow`
    /// @notice - blockTimestampHigh is the timestamp of block with number blockNumberLow + 1 - `headerField(chainId, blockNumberLow + 1, BlockHeaderField.TIMESTAMP) == blockTimestampHigh`
    /// @notice Both checks above can be done with `verifyHeader` (without needing to use additional storage in satellite contract).
    function verifyOnlyTimestamp(uint256 timestamp, uint256 blockNumberLow, uint256 blockTimestampLow, uint256 blockTimestampHigh) external pure;

    /// @notice Verifies that block with number blockNumberLow is the latest block with timestamp less than or equal to the given timestamp and that both header proofs are present in MMR.
    /// @notice Returns block number.
    function verifyTimestamp(
        uint256 chainId,
        uint256 timestamp,
        BlockHeaderProof calldata headerProofLow,
        BlockHeaderProof calldata headerProofHigh
    ) external view returns (uint256 blockNumber);

    // ========================= Events ========================= //

    /// @notice Emitted when block header fields are proven
    event ProvenHeader(uint256 chainId, uint256 blockNumber, uint16 savedFields);

    /// @notice Emitted when account fields are proven
    event ProvenAccount(uint256 chainId, uint256 blockNumber, address account, uint8 savedFields);

    /// @notice Emitted when storage slot value is proven
    event ProvenStorage(uint256 chainId, uint256 blockNumber, address account, bytes32 slot);

    /// @notice Emitted when timestamp is proven
    event ProvenTimestamp(uint256 chainId, uint256 timestamp);
}
"
    },
    "src/interfaces/modules/IMmrCoreModule.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import {Lib_RLPReader as RLPReader} from "../../libraries/external/optimism/rlp/Lib_RLPReader.sol";
import {StatelessMmr} from "@HerodotusDev/solidity-mmr/src/lib/StatelessMmr.sol";

struct RootForHashingFunction {
    bytes32 root;
    bytes32 hashingFunction;
}

enum GrownBy {
    /// @dev GrownBy.EVM_ON_CHAIN_GROWER - appended by EvmOnChainGrowingModule
    EVM_ON_CHAIN_GROWER,
    /// @dev GrownBy.EVM_SHARP_GROWER - appended by EvmSharpGrowingModule
    EVM_SHARP_GROWER,
    /// @dev GrownBy.STARKNET_SHARP_GROWER - appended by StarknetSharpMmrGrowingModule
    STARKNET_SHARP_GROWER
}

enum CreatedFrom {
    FOREIGN,
    DOMESTIC,
    STORAGE_PROOF
}

interface IMmrCoreModule {
    // ========================= Other Satellite Modules Only Functions ========================= //

    /// @notice Receives a parent hash for a given blockNumber and hashingFunction on chainId.
    /// @notice It can be obtained directly on-chain (via `blockhash` function or on parent hash) or sent from another chain (eg. L1 -> L2).
    /// @dev Saves the received parentHash in satellite storage for later access.
    /// @dev IMPORTANT: This function must only be called with data that is verified to be correct.
    function _receiveParentHash(uint256 chainId, bytes32 hashingFunction, uint256 blockNumber, bytes32 parentHash) external;

    /// @notice Creates a new MMR with given data by copying MMR data from another (foreign) chain.
    /// @dev Saves new MMR in satellite storage for later access.
    /// @dev IMPORTANT:
    /// @param newMmrId the ID of the MMR to create
    /// @param rootsForHashingFunctions the roots of the MMR -> ABI encoded hashing function => MMR root
    /// @param mmrSize the size of the MMR
    /// @param accumulatedChainId the ID of the chain that the MMR accumulates (where block is?)
    /// @param originChainId the ID of the chain from which the new MMR will be created (who is sending msg?)
    /// @param originalMmrId the ID of the MMR from which the new MMR will be created
    /// @param isOffchainGrown Whether the MMR can be grown with and only with either EVMSharpGrowingModule or StarknetSharpMmrGrowingModule
    function _createMmrFromForeign(
        uint256 newMmrId,
        RootForHashingFunction[] calldata rootsForHashingFunctions,
        uint256 mmrSize,
        uint256 accumulatedChainId,
        uint256 originChainId,
        uint256 originalMmrId,
        bool isOffchainGrown
    ) external;

    // ========================= Core Functions ========================= //

    /// @notice Creates a new MMR that is a clone of an already existing MMR or an empty MMR if originalMmrId is 0 (in that case mmrSize is ignored)
    /// @param newMmrId the ID of the new MMR
    /// @param originalMmrId the ID of the MMR from which the new MMR will be created - if 0 it means an empty MMR will be created
    /// @param accumulatedChainId the ID of the chain that the MMR accumulates
    /// @param mmrSize size at which the MMR will be copied
    /// @param hashingFunctions the hashing functions used in the MMR - if more than one, the MMR will be sibling synced and require being a satellite module to call
    function createMmrFromDomestic(
        uint256 newMmrId,
        uint256 originalMmrId,
        uint256 accumulatedChainId,
        uint256 mmrSize,
        bytes32[] calldata hashingFunctions,
        bool isOffchainGrown
    ) external;

    /// @notice Creates a new MMR that is a clone of MMR that exists in other satellite. Data about MMR is taken from storage slot proof for satellite at slot corresponding to `mmrs` mapping.
    /// @param newMmrId the ID of the new MMR
    /// @param originalMmrId the ID of the MMR from which the new MMR will be created, has to be non-zero
    /// @param accumulatedChainId the ID of the chain that the MMR accumulates
    /// @param mmrSize size at which the MMR will be copied
    /// @param hashingFunctions the hashing functions used in the MMR - if more than one, the MMR will be sibling synced and require being a satellite module to call
    /// @param originChainId the ID of the chain on which satellite that contains the MMR is deployed
    /// @param blockNumber the block number at which the storage proof is verified
    /// @param isOffchainGrown whether the new MMR can be grown with and only with either EVMSharpGrowingModule or StarknetSharpMmrGrowingModule
    /// @param storageSlotMptProofs mpt proofs for storage slots whose indices are given by getStorageSlotsForMmrCreation function. It can either be empty or has twice the length of `hashingFunctions`.
    /// @dev If non-empty array is provided, 2i indices correspond to isOffchainGrown slots and 2i+1 to mmrSizeToRoot slots. Also, STORAGE_ROOT field of the origin satellite account has to be proven.
    /// @dev If the array is empty, then all above storage slots have to be proven before calling this function.
    function createMmrFromStorageProof(
        uint256 newMmrId,
        uint256 originalMmrId,
        uint256 accumulatedChainId,
        uint256 mmrSize,
        bytes32[] calldata hashingFunctions,
        uint256 originChainId,
        uint256 blockNumber,
        bool isOffchainGrown,
        bytes[] calldata storageSlotMptProofs
    ) external;

    function getStorageSlotsForMmrCreation(
        uint256 chainId,
        uint256 mmrId,
        uint256 mmrSize,
        bytes32[] memory hashingFunctions
    ) external pure returns (uint256[] memory isOffchainGrownSlot, uint256[] memory mmrSizeToRootSlot);

    // ========================= View functions ========================= //

    function POSEIDON_HASHING_FUNCTION() external view returns (bytes32);

    function KECCAK_HASHING_FUNCTION() external view returns (bytes32);

    function POSEIDON_MMR_INITIAL_ROOT() external view returns (bytes32);

    function KECCAK_MMR_INITIAL_ROOT() external view returns (bytes32);

    function getMmrAtSize(uint256 chainId, uint256 mmrId, bytes32 hashingFunction, uint256 mmrSize) external view returns (bytes32, bool);

    function getLatestMmr(uint256 chainId, uint256 mmrId, bytes32 hashingFunction) external view returns (uint256, bytes32, bool);

    function getReceivedParentHash(uint256 chainId, bytes32 hashingFunction, uint256 blockNumber) external view returns (bytes32);

    // ========================= Events ========================= //

    /// @notice emitted when a block hash is received
    /// @param chainId the ID of the chain that the block hash is from
    /// @param blockNumber the block number
    /// @param parentHash the parent hash of the block number
    /// @param hashingFunction the hashing function use to hash the block, e.g. Keccak on Ethereum and Poseidon on Starknet
    /// @dev hashingFunction is a 32 byte keccak hash of the hashing function name, eg: keccak256("keccak256"), keccak256("poseidon")
    event ReceivedParentHash(uint256 chainId, uint256 blockNumber, bytes32 parentHash, bytes32 hashingFunction);

    /// @notice emitted when a new MMR is created from a domestic or foreign source
    /// @notice - foreign source - sent from another chain, or off-chain computation proven on-chain
    /// @notice - domestic source - created from another MMR on the same chain, or a standalone new empty MMR
    /// @param newMmrId the ID of the new MMR
    /// @param mmrSize the size of the MMR
    /// @param accumulatedChainId the ID of the chain that the MMR accumulates
    /// @param originalMmrId the ID of the MMR from which the new MMR is created - if 0, it means an new empty MMR was created
    /// @param rootsForHashingFunctions list of pairs (mmrRoot, hashingFunction) representing mmr roots for each hashing function
    /// @dev every hashingFunction should occur at most once in the list
    /// @dev hashingFunction is a 32 byte keccak hash of the hashing function name, eg: keccak256("keccak256"), keccak256("poseidon")
    /// @param originChainId the ID of the chain from which the new MM

Tags:
ERC165, Multisig, Voting, Upgradeable, Multi-Signature, Factory|addr:0xcb64ce02c466cbf7837c8f8b632e559235d4b8ae|verified:true|block:23675731|tx:0xdc2eddb658b4f0a2b5a310c9b376fa8f2ff6ff89553f55367d64efa75b1a4797|first_check:1761654394

Submitted on: 2025-10-28 13:26:36

Comments

Log in to comment.

No comments yet.