creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/interfaces/IBasePolygonZkEVMGlobalExitRoot.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity ^0.8.20;\n\ninterface IBasePolygonZkEVMGlobalExitRoot {\n    /**\n     * @dev Thrown when the caller is not the allowed contracts\n     */\n    error OnlyAllowedContracts();\n\n    function updateExitRoot(bytes32 newRollupExitRoot) external;\n\n    function globalExitRootMap(\n        bytes32 globalExitRootNum\n    ) external returns (uint256);\n}\n"
      },
      "contracts/lib/GlobalExitRootLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity 0.8.20;\n\n/**\n * @dev A library that provides the necessary calculations to calculate the global exit root\n */\nlibrary GlobalExitRootLib {\n    function calculateGlobalExitRoot(\n        bytes32 mainnetExitRoot,\n        bytes32 rollupExitRoot\n    ) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(mainnetExitRoot, rollupExitRoot));\n    }\n}\n"
      },
      "contracts/v2/interfaces/IPolygonZkEVMGlobalExitRootV2.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity ^0.8.20;\nimport \"../../interfaces/IBasePolygonZkEVMGlobalExitRoot.sol\";\n\ninterface IPolygonZkEVMGlobalExitRootV2 is IBasePolygonZkEVMGlobalExitRoot {\n    function getLastGlobalExitRoot() external view returns (bytes32);\n\n    function getRoot() external view returns (bytes32);\n}\n"
      },
      "contracts/v2/lib/DepositContractBase.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.20;\n\n/**\n * This contract will be used as a helper for all the sparse merkle tree related functions\n * Based on the implementation of the deposit eth2.0 contract https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol\n */\ncontract DepositContractBase {\n    /**\n     * @dev Thrown when the merkle tree is full\n     */\n    error MerkleTreeFull();\n\n    // Merkle tree levels\n    uint256 internal constant _DEPOSIT_CONTRACT_TREE_DEPTH = 32;\n\n    // This ensures `depositCount` will fit into 32-bits\n    uint256 internal constant _MAX_DEPOSIT_COUNT =\n        2 ** _DEPOSIT_CONTRACT_TREE_DEPTH - 1;\n\n    // Branch array which contains the necessary sibilings to compute the next root when a new\n    // leaf is inserted\n    bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] internal _branch;\n\n    // Counter of current deposits\n    uint256 public depositCount;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     */\n    uint256[10] private _gap;\n\n    /**\n     * @notice Computes and returns the merkle root\n     */\n    function getRoot() public view virtual returns (bytes32) {\n        bytes32 node;\n        uint256 size = depositCount;\n        bytes32 currentZeroHashHeight = 0;\n\n        for (\n            uint256 height = 0;\n            height < _DEPOSIT_CONTRACT_TREE_DEPTH;\n            height++\n        ) {\n            if (((size >> height) & 1) == 1)\n                node = keccak256(abi.encodePacked(_branch[height], node));\n            else\n                node = keccak256(abi.encodePacked(node, currentZeroHashHeight));\n\n            currentZeroHashHeight = keccak256(\n                abi.encodePacked(currentZeroHashHeight, currentZeroHashHeight)\n            );\n        }\n        return node;\n    }\n\n    /**\n     * @notice Add a new leaf to the merkle tree\n     * @param leaf Leaf\n     */\n    function _addLeaf(bytes32 leaf) internal {\n        bytes32 node = leaf;\n\n        // Avoid overflowing the Merkle tree (and prevent edge case in computing `_branch`)\n        if (depositCount >= _MAX_DEPOSIT_COUNT) {\n            revert MerkleTreeFull();\n        }\n\n        // Add deposit data root to Merkle tree (update a single `_branch` node)\n        uint256 size = ++depositCount;\n        for (\n            uint256 height = 0;\n            height < _DEPOSIT_CONTRACT_TREE_DEPTH;\n            height++\n        ) {\n            if (((size >> height) & 1) == 1) {\n                _branch[height] = node;\n                return;\n            }\n            node = keccak256(abi.encodePacked(_branch[height], node));\n        }\n        // As the loop should always end prematurely with the `return` statement,\n        // this code should be unreachable. We assert `false` just to be safe.\n        assert(false);\n    }\n\n    /**\n     * @notice Verify merkle proof\n     * @param leafHash Leaf hash\n     * @param smtProof Smt proof\n     * @param index Index of the leaf\n     * @param root Merkle root\n     */\n    function verifyMerkleProof(\n        bytes32 leafHash,\n        bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,\n        uint32 index,\n        bytes32 root\n    ) public pure returns (bool) {\n        return calculateRoot(leafHash, smtProof, index) == root;\n    }\n\n    /**\n     * @notice Calculate root from merkle proof\n     * @param leafHash Leaf hash\n     * @param smtProof Smt proof\n     * @param index Index of the leaf\n     */\n    function calculateRoot(\n        bytes32 leafHash,\n        bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,\n        uint32 index\n    ) public pure returns (bytes32) {\n        bytes32 node = leafHash;\n\n        // Compute root\n        for (\n            uint256 height = 0;\n            height < _DEPOSIT_CONTRACT_TREE_DEPTH;\n            height++\n        ) {\n            if (((index >> height) & 1) == 1)\n                node = keccak256(abi.encodePacked(smtProof[height], node));\n            else node = keccak256(abi.encodePacked(node, smtProof[height]));\n        }\n\n        return node;\n    }\n}\n"
      },
      "contracts/v2/lib/PolygonZkEVMGlobalExitRootBaseStorage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity ^0.8.20;\nimport \"../interfaces/IPolygonZkEVMGlobalExitRootV2.sol\";\n\n/**\n * Since the current contract of PolygonZkEVMGlobalExitRoot will be upgraded to a PolygonZkEVMGlobalExitRootV2, and it will implement\n * the DepositContractBase, this base is needed to preserve the previous storage slots\n */\nabstract contract PolygonZkEVMGlobalExitRootBaseStorage is\n    IPolygonZkEVMGlobalExitRootV2\n{\n    // Rollup root, contains all exit roots of all rollups\n    bytes32 public lastRollupExitRoot;\n\n    // Mainnet exit root, this will be updated every time a deposit is made in mainnet\n    bytes32 public lastMainnetExitRoot;\n\n    // Store every global exit root: Root --> blockhash\n    // Note that previously recoded global exit roots in previous versions, timestamp was recorded instead of blockhash\n    mapping(bytes32 => uint256) public globalExitRootMap;\n}\n"
      },
      "contracts/v2/PolygonZkEVMGlobalExitRootV2.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity 0.8.20;\n\nimport \"./interfaces/IPolygonZkEVMGlobalExitRootV2.sol\";\nimport \"./lib/PolygonZkEVMGlobalExitRootBaseStorage.sol\";\nimport \"../lib/GlobalExitRootLib.sol\";\nimport \"./lib/DepositContractBase.sol\";\n\n/**\n * Contract responsible for managing the exit roots across multiple networks\n */\ncontract PolygonZkEVMGlobalExitRootV2 is\n    PolygonZkEVMGlobalExitRootBaseStorage,\n    DepositContractBase\n{\n    // PolygonZkEVMBridge address\n    address public immutable bridgeAddress;\n\n    // Rollup manager contract address\n    address public immutable rollupManager;\n\n    /**\n     * @dev Emitted when the global exit root is updated\n     */\n    event UpdateL1InfoTree(\n        bytes32 indexed mainnetExitRoot,\n        bytes32 indexed rollupExitRoot\n    );\n\n    /**\n     * @param _rollupManager Rollup manager contract address\n     * @param _bridgeAddress PolygonZkEVMBridge contract address\n     */\n    constructor(address _rollupManager, address _bridgeAddress) {\n        rollupManager = _rollupManager;\n        bridgeAddress = _bridgeAddress;\n    }\n\n    /**\n     * @notice Update the exit root of one of the networks and the global exit root\n     * @param newRoot new exit tree root\n     */\n    function updateExitRoot(bytes32 newRoot) external {\n        // Store storage variables into temporal variables since will be used multiple times\n        bytes32 cacheLastRollupExitRoot;\n        bytes32 cacheLastMainnetExitRoot;\n\n        if (msg.sender == bridgeAddress) {\n            lastMainnetExitRoot = newRoot;\n            cacheLastMainnetExitRoot = newRoot;\n            cacheLastRollupExitRoot = lastRollupExitRoot;\n        } else if (msg.sender == rollupManager) {\n            lastRollupExitRoot = newRoot;\n            cacheLastRollupExitRoot = newRoot;\n            cacheLastMainnetExitRoot = lastMainnetExitRoot;\n        } else {\n            revert OnlyAllowedContracts();\n        }\n\n        bytes32 newGlobalExitRoot = GlobalExitRootLib.calculateGlobalExitRoot(\n            cacheLastMainnetExitRoot,\n            cacheLastRollupExitRoot\n        );\n\n        // If it already exists, do not modify the blockhash\n        if (globalExitRootMap[newGlobalExitRoot] == 0) {\n            uint256 lastBlockHash = uint256(blockhash(block.number - 1));\n            globalExitRootMap[newGlobalExitRoot] = lastBlockHash;\n\n            // save new leaf in L1InfoTree\n            _addLeaf(\n                getLeafValue(\n                    newGlobalExitRoot,\n                    lastBlockHash,\n                    uint64(block.timestamp)\n                )\n            );\n\n            emit UpdateL1InfoTree(\n                cacheLastMainnetExitRoot,\n                cacheLastRollupExitRoot\n            );\n        }\n    }\n\n    /**\n     * @notice Return last global exit root\n     */\n    function getLastGlobalExitRoot() public view returns (bytes32) {\n        return\n            GlobalExitRootLib.calculateGlobalExitRoot(\n                lastMainnetExitRoot,\n                lastRollupExitRoot\n            );\n    }\n\n    /**\n     * @notice Computes and returns the merkle root of the L1InfoTree\n     */\n    function getRoot()\n        public\n        view\n        override(DepositContractBase, IPolygonZkEVMGlobalExitRootV2)\n        returns (bytes32)\n    {\n        return super.getRoot();\n    }\n\n    /**\n     * @notice Given the leaf data returns the leaf hash\n     * @param newGlobalExitRoot Last global exit root\n     * @param lastBlockHash Last accesible block hash\n     * @param timestamp Ethereum timestamp in seconds\n     */\n    function getLeafValue(\n        bytes32 newGlobalExitRoot,\n        uint256 lastBlockHash,\n        uint64 timestamp\n    ) public pure returns (bytes32) {\n        return\n            keccak256(\n                abi.encodePacked(newGlobalExitRoot, lastBlockHash, timestamp)\n            );\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 999999
      },
      "evmVersion": "shanghai",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}