UNPKG

@settlemint/solidity-zeto

Version:

Smart contract set to build Zero Knowledge tokens in SettleMint

28 lines 28.9 MB
{ "id": "599fa6f17c1c1689b2df149f7fa3eea6", "_format": "hh-sol-build-info-1", "solcVersion": "0.8.27", "solcLongVersion": "0.8.27+commit.40a35a09", "input": { "language": "Solidity", "sources": { "@iden3/contracts/lib/ArrayUtils.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.27;\n\n/// @title A common functions for arrays.\nlibrary ArrayUtils {\n /**\n * @dev Calculates bounds for the slice of the array.\n * @param arrLength An array length.\n * @param start A start index.\n * @param length A length of the slice.\n * @param limit A limit for the length.\n * @return The bounds for the slice of the array.\n */\n function calculateBounds(\n uint256 arrLength,\n uint256 start,\n uint256 length,\n uint256 limit\n ) internal pure returns (uint256, uint256) {\n require(length > 0, \"Length should be greater than 0\");\n require(length <= limit, \"Length limit exceeded\");\n require(start < arrLength, \"Start index out of bounds\");\n\n uint256 end = start + length;\n if (end > arrLength) {\n end = arrLength;\n }\n\n return (start, end);\n }\n}\n" }, "@iden3/contracts/lib/Poseidon.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.27;\n\nlibrary PoseidonUnit1L {\n function poseidon(uint256[1] calldata) public pure returns (uint256) {}\n}\n\nlibrary PoseidonUnit2L {\n function poseidon(uint256[2] calldata) public pure returns (uint256) {}\n}\n\nlibrary PoseidonUnit3L {\n function poseidon(uint256[3] calldata) public pure returns (uint256) {}\n}\n\nlibrary PoseidonUnit4L {\n function poseidon(uint256[4] calldata) public pure returns (uint256) {}\n}\n\nlibrary PoseidonUnit5L {\n function poseidon(uint256[5] calldata) public pure returns (uint256) {}\n}\n\nlibrary PoseidonUnit6L {\n function poseidon(uint256[6] calldata) public pure returns (uint256) {}\n}\n\nlibrary SpongePoseidon {\n uint32 internal constant BATCH_SIZE = 6;\n\n function hash(uint256[] memory values) public pure returns (uint256) {\n uint256[BATCH_SIZE] memory frame = [uint256(0), 0, 0, 0, 0, 0];\n bool dirty = false;\n uint256 fullHash = 0;\n uint32 k = 0;\n for (uint32 i = 0; i < values.length; i++) {\n dirty = true;\n frame[k] = values[i];\n if (k == BATCH_SIZE - 1) {\n fullHash = PoseidonUnit6L.poseidon(frame);\n dirty = false;\n frame = [uint256(0), 0, 0, 0, 0, 0];\n frame[0] = fullHash;\n k = 1;\n } else {\n k++;\n }\n }\n if (dirty) {\n // we haven't hashed something in the main sponge loop and need to do hash here\n fullHash = PoseidonUnit6L.poseidon(frame);\n }\n return fullHash;\n }\n}\n\nlibrary PoseidonFacade {\n function poseidon1(uint256[1] calldata el) public pure returns (uint256) {\n return PoseidonUnit1L.poseidon(el);\n }\n\n function poseidon2(uint256[2] calldata el) public pure returns (uint256) {\n return PoseidonUnit2L.poseidon(el);\n }\n\n function poseidon3(uint256[3] calldata el) public pure returns (uint256) {\n return PoseidonUnit3L.poseidon(el);\n }\n\n function poseidon4(uint256[4] calldata el) public pure returns (uint256) {\n return PoseidonUnit4L.poseidon(el);\n }\n\n function poseidon5(uint256[5] calldata el) public pure returns (uint256) {\n return PoseidonUnit5L.poseidon(el);\n }\n\n function poseidon6(uint256[6] calldata el) public pure returns (uint256) {\n return PoseidonUnit6L.poseidon(el);\n }\n\n function poseidonSponge(uint256[] calldata el) public pure returns (uint256) {\n return SpongePoseidon.hash(el);\n }\n}\n" }, "@iden3/contracts/lib/SmtLib.sol": { "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.27;\n\nimport {PoseidonUnit2L, PoseidonUnit3L} from \"./Poseidon.sol\";\nimport {ArrayUtils} from \"./ArrayUtils.sol\";\n\n/// @title A sparse merkle tree implementation, which keeps tree history.\n// Note that this SMT implementation can manage duplicated roots in the history,\n// which may happen when some leaf change its value and then changes it back to the original value.\n// Leaves deletion is not supported, although it should be possible to implement it in the future\n// versions of this library, without changing the existing state variables\n// In this way all the SMT data may be preserved for the contracts already in production.\nlibrary SmtLib {\n /**\n * @dev Max return array length for SMT root history requests\n */\n uint256 public constant ROOT_INFO_LIST_RETURN_LIMIT = 1000;\n\n /**\n * @dev Max depth hard cap for SMT\n * We can't use depth > 256 because of bits number limitation in the uint256 data type.\n */\n uint256 public constant MAX_DEPTH_HARD_CAP = 256;\n\n /**\n * @dev Enum of SMT node types\n */\n enum NodeType {\n EMPTY,\n LEAF,\n MIDDLE\n }\n\n /**\n * @dev Sparse Merkle Tree data\n * Note that we count the SMT depth starting from 0, which is the root level.\n *\n * For example, the following tree has a maxDepth = 2:\n *\n * O <- root level (depth = 0)\n * / \\\n * O O <- depth = 1\n * / \\ / \\\n * O O O O <- depth = 2\n */\n struct Data {\n mapping(uint256 => Node) nodes;\n RootEntry[] rootEntries;\n mapping(uint256 => uint256[]) rootIndexes; // root => rootEntryIndex[]\n uint256 maxDepth;\n bool initialized;\n // This empty reserved space is put in place to allow future versions\n // of the SMT library to add new Data struct fields without shifting down\n // storage of upgradable contracts that use this struct as a state variable\n // (see https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps)\n uint256[45] __gap;\n }\n\n /**\n * @dev Struct of the node proof in the SMT.\n * @param root This SMT root.\n * @param existence A flag, which shows if the leaf index exists in the SMT.\n * @param siblings An array of SMT sibling node hashes.\n * @param index An index of the leaf in the SMT.\n * @param value A value of the leaf in the SMT.\n * @param auxExistence A flag, which shows if the auxiliary leaf exists in the SMT.\n * @param auxIndex An index of the auxiliary leaf in the SMT.\n * @param auxValue An value of the auxiliary leaf in the SMT.\n */\n struct Proof {\n uint256 root;\n bool existence;\n uint256[] siblings;\n uint256 index;\n uint256 value;\n bool auxExistence;\n uint256 auxIndex;\n uint256 auxValue;\n }\n\n /**\n * @dev Struct for SMT root internal storage representation.\n * @param root SMT root.\n * @param createdAtTimestamp A time, when the root was saved to blockchain.\n * @param createdAtBlock A number of block, when the root was saved to blockchain.\n */\n struct RootEntry {\n uint256 root;\n uint256 createdAtTimestamp;\n uint256 createdAtBlock;\n }\n\n /**\n * @dev Struct for public interfaces to represent SMT root info.\n * @param root This SMT root.\n * @param replacedByRoot A root, which replaced this root.\n * @param createdAtTimestamp A time, when the root was saved to blockchain.\n * @param replacedAtTimestamp A time, when the root was replaced by the next root in blockchain.\n * @param createdAtBlock A number of block, when the root was saved to blockchain.\n * @param replacedAtBlock A number of block, when the root was replaced by the next root in blockchain.\n */\n struct RootEntryInfo {\n uint256 root;\n uint256 replacedByRoot;\n uint256 createdAtTimestamp;\n uint256 replacedAtTimestamp;\n uint256 createdAtBlock;\n uint256 replacedAtBlock;\n }\n\n /**\n * @dev Struct of SMT node.\n * @param NodeType type of node.\n * @param childLeft left child of node.\n * @param childRight right child of node.\n * @param Index index of node.\n * @param Value value of node.\n */\n struct Node {\n NodeType nodeType;\n uint256 childLeft;\n uint256 childRight;\n uint256 index;\n uint256 value;\n }\n\n using BinarySearchSmtRoots for Data;\n using ArrayUtils for uint256[];\n\n /**\n * @dev Reverts if root does not exist in SMT roots history.\n * @param root SMT root.\n */\n modifier onlyExistingRoot(Data storage self, uint256 root) {\n require(rootExists(self, root), \"Root does not exist\");\n _;\n }\n\n /**\n * @dev Add a leaf to the SMT\n * @param i Index of a leaf\n * @param v Value of a leaf\n */\n function addLeaf(Data storage self, uint256 i, uint256 v) external onlyInitialized(self) {\n Node memory node = Node({\n nodeType: NodeType.LEAF,\n childLeft: 0,\n childRight: 0,\n index: i,\n value: v\n });\n\n uint256 prevRoot = getRoot(self);\n uint256 newRoot = _addLeaf(self, node, prevRoot, 0);\n\n _addEntry(self, newRoot, block.timestamp, block.number);\n }\n\n /**\n * @dev Get SMT root history length\n * @return SMT history length\n */\n function getRootHistoryLength(Data storage self) external view returns (uint256) {\n return self.rootEntries.length;\n }\n\n /**\n * @dev Get SMT root history\n * @param startIndex start index of history\n * @param length history length\n * @return array of RootEntryInfo structs\n */\n function getRootHistory(\n Data storage self,\n uint256 startIndex,\n uint256 length\n ) external view returns (RootEntryInfo[] memory) {\n (uint256 start, uint256 end) = ArrayUtils.calculateBounds(\n self.rootEntries.length,\n startIndex,\n length,\n ROOT_INFO_LIST_RETURN_LIMIT\n );\n\n RootEntryInfo[] memory result = new RootEntryInfo[](end - start);\n\n for (uint256 i = start; i < end; i++) {\n result[i - start] = _getRootInfoByIndex(self, i);\n }\n return result;\n }\n\n /**\n * @dev Get the SMT node by hash\n * @param nodeHash Hash of a node\n * @return A node struct\n */\n function getNode(Data storage self, uint256 nodeHash) public view returns (Node memory) {\n return self.nodes[nodeHash];\n }\n\n /**\n * @dev Get the proof if a node with specific index exists or not exists in the SMT.\n * @param index A node index.\n * @return SMT proof struct.\n */\n function getProof(Data storage self, uint256 index) external view returns (Proof memory) {\n return getProofByRoot(self, index, getRoot(self));\n }\n\n /**\n * @dev Get the proof if a node with specific index exists or not exists in the SMT for some historical tree state.\n * @param index A node index\n * @param historicalRoot Historical SMT roof to get proof for.\n * @return Proof struct.\n */\n function getProofByRoot(\n Data storage self,\n uint256 index,\n uint256 historicalRoot\n ) public view onlyExistingRoot(self, historicalRoot) returns (Proof memory) {\n uint256[] memory siblings = new uint256[](self.maxDepth);\n // Solidity does not guarantee that memory vars are zeroed out\n for (uint256 i = 0; i < self.maxDepth; i++) {\n siblings[i] = 0;\n }\n\n Proof memory proof = Proof({\n root: historicalRoot,\n existence: false,\n siblings: siblings,\n index: index,\n value: 0,\n auxExistence: false,\n auxIndex: 0,\n auxValue: 0\n });\n\n uint256 nextNodeHash = historicalRoot;\n Node memory node;\n\n for (uint256 i = 0; i <= self.maxDepth; i++) {\n node = getNode(self, nextNodeHash);\n if (node.nodeType == NodeType.EMPTY) {\n break;\n } else if (node.nodeType == NodeType.LEAF) {\n if (node.index == proof.index) {\n proof.existence = true;\n proof.value = node.value;\n break;\n } else {\n proof.auxExistence = true;\n proof.auxIndex = node.index;\n proof.auxValue = node.value;\n proof.value = node.value;\n break;\n }\n } else if (node.nodeType == NodeType.MIDDLE) {\n if ((proof.index >> i) & 1 == 1) {\n nextNodeHash = node.childRight;\n proof.siblings[i] = node.childLeft;\n } else {\n nextNodeHash = node.childLeft;\n proof.siblings[i] = node.childRight;\n }\n } else {\n revert(\"Invalid node type\");\n }\n }\n return proof;\n }\n\n /**\n * @dev Get the proof if a node with specific index exists or not exists in the SMT by some historical timestamp.\n * @param index Node index.\n * @param timestamp The latest timestamp to get proof for.\n * @return Proof struct.\n */\n function getProofByTime(\n Data storage self,\n uint256 index,\n uint256 timestamp\n ) public view returns (Proof memory) {\n RootEntryInfo memory rootInfo = getRootInfoByTime(self, timestamp);\n return getProofByRoot(self, index, rootInfo.root);\n }\n\n /**\n * @dev Get the proof if a node with specific index exists or not exists in the SMT by some historical block number.\n * @param index Node index.\n * @param blockNumber The latest block number to get proof for.\n * @return Proof struct.\n */\n function getProofByBlock(\n Data storage self,\n uint256 index,\n uint256 blockNumber\n ) external view returns (Proof memory) {\n RootEntryInfo memory rootInfo = getRootInfoByBlock(self, blockNumber);\n return getProofByRoot(self, index, rootInfo.root);\n }\n\n function getRoot(Data storage self) public view onlyInitialized(self) returns (uint256) {\n return self.rootEntries[self.rootEntries.length - 1].root;\n }\n\n /**\n * @dev Get root info by some historical timestamp.\n * @param timestamp The latest timestamp to get the root info for.\n * @return Root info struct\n */\n function getRootInfoByTime(\n Data storage self,\n uint256 timestamp\n ) public view returns (RootEntryInfo memory) {\n require(timestamp <= block.timestamp, \"No future timestamps allowed\");\n\n return\n _getRootInfoByTimestampOrBlock(\n self,\n timestamp,\n BinarySearchSmtRoots.SearchType.TIMESTAMP\n );\n }\n\n /**\n * @dev Get root info by some historical block number.\n * @param blockN The latest block number to get the root info for.\n * @return Root info struct\n */\n function getRootInfoByBlock(\n Data storage self,\n uint256 blockN\n ) public view returns (RootEntryInfo memory) {\n require(blockN <= block.number, \"No future blocks allowed\");\n\n return _getRootInfoByTimestampOrBlock(self, blockN, BinarySearchSmtRoots.SearchType.BLOCK);\n }\n\n /**\n * @dev Returns root info by root\n * @param root root\n * @return Root info struct\n */\n function getRootInfo(\n Data storage self,\n uint256 root\n ) public view onlyExistingRoot(self, root) returns (RootEntryInfo memory) {\n uint256[] storage indexes = self.rootIndexes[root];\n uint256 lastIndex = indexes[indexes.length - 1];\n return _getRootInfoByIndex(self, lastIndex);\n }\n\n /**\n * @dev Retrieve duplicate root quantity by id and state.\n * If the root repeats more that once, the length may be greater than 1.\n * @param root A root.\n * @return Root root entries quantity.\n */\n function getRootInfoListLengthByRoot(\n Data storage self,\n uint256 root\n ) public view returns (uint256) {\n return self.rootIndexes[root].length;\n }\n\n /**\n * @dev Retrieve root infos list of duplicated root by id and state.\n * If the root repeats more that once, the length list may be greater than 1.\n * @param root A root.\n * @param startIndex The index to start the list.\n * @param length The length of the list.\n * @return Root Root entries quantity.\n */\n function getRootInfoListByRoot(\n Data storage self,\n uint256 root,\n uint256 startIndex,\n uint256 length\n ) public view onlyExistingRoot(self, root) returns (RootEntryInfo[] memory) {\n uint256[] storage indexes = self.rootIndexes[root];\n (uint256 start, uint256 end) = ArrayUtils.calculateBounds(\n indexes.length,\n startIndex,\n length,\n ROOT_INFO_LIST_RETURN_LIMIT\n );\n\n RootEntryInfo[] memory result = new RootEntryInfo[](end - start);\n for (uint256 i = start; i < end; i++) {\n result[i - start] = _getRootInfoByIndex(self, indexes[i]);\n }\n\n return result;\n }\n\n /**\n * @dev Checks if root exists\n * @param root root\n * return true if root exists\n */\n function rootExists(Data storage self, uint256 root) public view returns (bool) {\n return self.rootIndexes[root].length > 0;\n }\n\n /**\n * @dev Sets max depth of the SMT\n * @param maxDepth max depth\n */\n function setMaxDepth(Data storage self, uint256 maxDepth) public {\n require(maxDepth > 0, \"Max depth must be greater than zero\");\n require(maxDepth > self.maxDepth, \"Max depth can only be increased\");\n require(maxDepth <= MAX_DEPTH_HARD_CAP, \"Max depth is greater than hard cap\");\n self.maxDepth = maxDepth;\n }\n\n /**\n * @dev Gets max depth of the SMT\n * return max depth\n */\n function getMaxDepth(Data storage self) external view returns (uint256) {\n return self.maxDepth;\n }\n\n /**\n * @dev Initialize SMT with max depth and root entry of an empty tree.\n * @param maxDepth Max depth of the SMT.\n */\n function initialize(Data storage self, uint256 maxDepth) external {\n require(!isInitialized(self), \"Smt is already initialized\");\n setMaxDepth(self, maxDepth);\n _addEntry(self, 0, 0, 0);\n self.initialized = true;\n }\n\n modifier onlyInitialized(Data storage self) {\n require(isInitialized(self), \"Smt is not initialized\");\n _;\n }\n\n function isInitialized(Data storage self) public view returns (bool) {\n return self.initialized;\n }\n\n function _addLeaf(\n Data storage self,\n Node memory newLeaf,\n uint256 nodeHash,\n uint256 depth\n ) internal returns (uint256) {\n if (depth > self.maxDepth) {\n revert(\"Max depth reached\");\n }\n\n Node memory node = self.nodes[nodeHash];\n uint256 nextNodeHash;\n uint256 leafHash = 0;\n\n if (node.nodeType == NodeType.EMPTY) {\n leafHash = _addNode(self, newLeaf);\n } else if (node.nodeType == NodeType.LEAF) {\n leafHash = node.index == newLeaf.index\n ? _addNode(self, newLeaf)\n : _pushLeaf(self, newLeaf, node, depth);\n } else if (node.nodeType == NodeType.MIDDLE) {\n Node memory newNodeMiddle;\n\n if ((newLeaf.index >> depth) & 1 == 1) {\n nextNodeHash = _addLeaf(self, newLeaf, node.childRight, depth + 1);\n\n newNodeMiddle = Node({\n nodeType: NodeType.MIDDLE,\n childLeft: node.childLeft,\n childRight: nextNodeHash,\n index: 0,\n value: 0\n });\n } else {\n nextNodeHash = _addLeaf(self, newLeaf, node.childLeft, depth + 1);\n\n newNodeMiddle = Node({\n nodeType: NodeType.MIDDLE,\n childLeft: nextNodeHash,\n childRight: node.childRight,\n index: 0,\n value: 0\n });\n }\n\n leafHash = _addNode(self, newNodeMiddle);\n }\n\n return leafHash;\n }\n\n function _pushLeaf(\n Data storage self,\n Node memory newLeaf,\n Node memory oldLeaf,\n uint256 depth\n ) internal returns (uint256) {\n // no reason to continue if we are at max possible depth\n // as, anyway, we exceed the depth going down the tree\n if (depth >= self.maxDepth) {\n revert(\"Max depth reached\");\n }\n\n Node memory newNodeMiddle;\n bool newLeafBitAtDepth = (newLeaf.index >> depth) & 1 == 1;\n bool oldLeafBitAtDepth = (oldLeaf.index >> depth) & 1 == 1;\n\n // Check if we need to go deeper if diverge at the depth's bit\n if (newLeafBitAtDepth == oldLeafBitAtDepth) {\n uint256 nextNodeHash = _pushLeaf(self, newLeaf, oldLeaf, depth + 1);\n\n if (newLeafBitAtDepth) {\n // go right\n newNodeMiddle = Node(NodeType.MIDDLE, 0, nextNodeHash, 0, 0);\n } else {\n // go left\n newNodeMiddle = Node(NodeType.MIDDLE, nextNodeHash, 0, 0, 0);\n }\n return _addNode(self, newNodeMiddle);\n }\n\n if (newLeafBitAtDepth) {\n newNodeMiddle = Node({\n nodeType: NodeType.MIDDLE,\n childLeft: _getNodeHash(oldLeaf),\n childRight: _getNodeHash(newLeaf),\n index: 0,\n value: 0\n });\n } else {\n newNodeMiddle = Node({\n nodeType: NodeType.MIDDLE,\n childLeft: _getNodeHash(newLeaf),\n childRight: _getNodeHash(oldLeaf),\n index: 0,\n value: 0\n });\n }\n\n _addNode(self, newLeaf);\n return _addNode(self, newNodeMiddle);\n }\n\n function _addNode(Data storage self, Node memory node) internal returns (uint256) {\n uint256 nodeHash = _getNodeHash(node);\n // We don't have any guarantees if the hash function attached is good enough.\n // So, if the node hash already exists, we need to check\n // if the node in the tree exactly matches the one we are trying to add.\n if (self.nodes[nodeHash].nodeType != NodeType.EMPTY) {\n assert(self.nodes[nodeHash].nodeType == node.nodeType);\n assert(self.nodes[nodeHash].childLeft == node.childLeft);\n assert(self.nodes[nodeHash].childRight == node.childRight);\n assert(self.nodes[nodeHash].index == node.index);\n assert(self.nodes[nodeHash].value == node.value);\n return nodeHash;\n }\n\n self.nodes[nodeHash] = node;\n return nodeHash;\n }\n\n function _getNodeHash(Node memory node) internal pure returns (uint256) {\n uint256 nodeHash = 0;\n if (node.nodeType == NodeType.LEAF) {\n uint256[3] memory params = [node.index, node.value, uint256(1)];\n nodeHash = PoseidonUnit3L.poseidon(params);\n } else if (node.nodeType == NodeType.MIDDLE) {\n nodeHash = PoseidonUnit2L.poseidon([node.childLeft, node.childRight]);\n }\n return nodeHash; // Note: expected to return 0 if NodeType.EMPTY, which is the only option left\n }\n\n function _getRootInfoByIndex(\n Data storage self,\n uint256 index\n ) internal view returns (RootEntryInfo memory) {\n bool isLastRoot = index == self.rootEntries.length - 1;\n RootEntry storage rootEntry = self.rootEntries[index];\n\n return\n RootEntryInfo({\n root: rootEntry.root,\n replacedByRoot: isLastRoot ? 0 : self.rootEntries[index + 1].root,\n createdAtTimestamp: rootEntry.createdAtTimestamp,\n replacedAtTimestamp: isLastRoot\n ? 0\n : self.rootEntries[index + 1].createdAtTimestamp,\n createdAtBlock: rootEntry.createdAtBlock,\n replacedAtBlock: isLastRoot ? 0 : self.rootEntries[index + 1].createdAtBlock\n });\n }\n\n function _getRootInfoByTimestampOrBlock(\n Data storage self,\n uint256 timestampOrBlock,\n BinarySearchSmtRoots.SearchType searchType\n ) internal view returns (RootEntryInfo memory) {\n (uint256 index, bool found) = self.binarySearchUint256(timestampOrBlock, searchType);\n\n // As far as we always have at least one root entry, we should always find it\n assert(found);\n\n return _getRootInfoByIndex(self, index);\n }\n\n function _addEntry(\n Data storage self,\n uint256 root,\n uint256 _timestamp,\n uint256 _block\n ) internal {\n self.rootEntries.push(\n RootEntry({root: root, createdAtTimestamp: _timestamp, createdAtBlock: _block})\n );\n\n self.rootIndexes[root].push(self.rootEntries.length - 1);\n }\n}\n\n/// @title A binary search for the sparse merkle tree root history\n// Implemented as a separate library for testing purposes\nlibrary BinarySearchSmtRoots {\n /**\n * @dev Enum for the SMT history field selection\n */\n enum SearchType {\n TIMESTAMP,\n BLOCK\n }\n\n /**\n * @dev Binary search method for the SMT history,\n * which searches for the index of the root entry saved by the given timestamp or block\n * @param value The timestamp or block to search for.\n * @param searchType The type of the search (timestamp or block).\n */\n function binarySearchUint256(\n SmtLib.Data storage self,\n uint256 value,\n SearchType searchType\n ) internal view returns (uint256, bool) {\n if (self.rootEntries.length == 0) {\n return (0, false);\n }\n\n uint256 min = 0;\n uint256 max = self.rootEntries.length - 1;\n uint256 mid;\n\n while (min <= max) {\n mid = (max + min) / 2;\n\n uint256 midValue = fieldSelector(self.rootEntries[mid], searchType);\n if (midValue == value) {\n while (mid < self.rootEntries.length - 1) {\n uint256 nextValue = fieldSelector(self.rootEntries[mid + 1], searchType);\n if (nextValue == value) {\n mid++;\n } else {\n return (mid, true);\n }\n }\n return (mid, true);\n } else if (value > midValue) {\n min = mid + 1;\n } else if (value < midValue && mid > 0) {\n // mid > 0 is to avoid underflow\n max = mid - 1;\n } else {\n // This means that value < midValue && mid == 0. So we found nothing.\n return (0, false);\n }\n }\n\n // The case when the searched value does not exist and we should take the closest smaller value\n // Index in the \"max\" var points to the root entry with max value smaller than the searched value\n return (max, true);\n }\n\n /**\n * @dev Selects either timestamp or block field from the root entry struct\n * depending on the search type\n * @param rti The root entry to select the field from.\n * @param st The search type.\n */\n function fieldSelector(\n SmtLib.RootEntry memory rti,\n SearchType st\n ) internal pure returns (uint256) {\n if (st == SearchType.BLOCK) {\n return rti.createdAtBlock;\n } else if (st == SearchType.TIMESTAMP) {\n return rti.createdAtTimestamp;\n } else {\n revert(\"Invalid search type\");\n }\n }\n}\n" }, "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n struct OwnableStorage {\n address _owner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n assembly {\n $.slot := OwnableStorageLocation\n }\n }\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n function __Ownable_init(address initialOwner) internal onlyInitializing {\n __Ownable_init_unchained(initialOwner);\n }\n\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n OwnableStorage storage $ = _getOwnableStorage();\n return $._owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n OwnableStorage storage $ = _getOwnableStorage();\n address oldOwner = $._owner;\n $._owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reinitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n *\n * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n */\n function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n return INITIALIZABLE_STORAGE;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n bytes32 slot = _initializableStorageSlot();\n assembly {\n $.slot := slot\n }\n }\n}\n" }, "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol)\n\npragma solidity ^0.8.22;\n\nimport {IERC1822Proxiable} from \"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\";\nimport {ERC1967Utils} from \"@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol\";\nimport {Initializable} from \"./Initializable.sol\";\n\n/**\n * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an\n * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.\n *\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\n * `UUPSUpgradeable` with a custom implementation of upgrades.\n *\n * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.\n */\nabstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address private immutable __self = address(this);\n\n /**\n * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`\n * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,\n * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.\n * If the getter returns `\"5.0.0\"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must\n * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function\n * during an upgrade.\n */\n string public constant UPGRADE_INTERFACE_VERSION = \"5.0.0\";\n\n /**\n * @dev The call is from an unauthorized context.\n */\n error UUPSUnauthorizedCallContext();\n\n /**\n * @dev The storage `slot` is unsupported as a UUID.\n */\n error UUPSUnsupportedProxiableUUID(bytes32 slot);\n\n /**\n * @dev Check that the execution is being performed through a delegatecall call and that the execution context is\n * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case\n * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a\n * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to\n * fail.\n */\n modifier onlyProxy() {\n _checkProxy();\n _;\n }\n\n /**\n * @dev Check that the execution is not being performed through a delegate call. This allows a function to be\n * callable on the implementing contract but not through proxies.\n */\n modifier notDelegated() {\n _checkNotDelegated();\n _;\n }\n\n function __UUPSUpgradeable_init() internal onlyInitializing {\n }\n\n function __UUPSUpgradeable_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the\n * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\n */\n function proxiableUUID() external view virtual notDelegated returns (bytes32) {\n return ERC1967Utils.IMPLEMENTATION_SLOT;\n }\n\n /**\n * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call\n * encoded in `data`.\n *\n * Calls {_authorizeUpgrade}.\n *\n * Emits an {Upgraded} event.\n *\n * @custom:oz-upgrades-unsafe-allow-reachable delegatecall\n */\n function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {\n _authorizeUpgrade(newImplementation);\n _upgradeToAndCallUUPS(newImplementation, data);\n }\n\n /**\n * @dev Reverts if the execution is not performed via delegatecall or the execution\n * context is not of a proxy with an ERC-1967 compliant implementation pointing to self.\n */\n function _checkProxy() internal view virtual {\n if (\n address(this) == __self || // Must be called through delegatecall\n ERC1967Utils.getImplementation() != __self // Must be called through an active proxy\n ) {\n revert UUPSUnauthorizedCallContext();\n }\n }\n\n /**\n * @dev Reverts if the execution is performed via delegatecall.\n * See {notDelegated}.\n */\n function _checkNotDelegated() internal view virtual {\n if (address(this) != __self) {\n // Must not be called through delegatecall\n revert UUPSUnauthorizedCallContext();\n }\n }\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeToAndCall}.\n *\n * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.\n *\n * ```solidity\n * function _authorizeUpgrade(address) internal onlyOwner {}\n * ```\n */\n function _authorizeUpgrade(address newImplementation) internal virtual;\n\n /**\n * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.\n *\n * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value\n * is expected to be the implementation slot in ERC-1967.\n *\n * Emits an {IERC1967-Upgraded} event.\n */\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {\n revert UUPSUnsupportedProxiableUUID(slot);\n }\n ERC1967Utils.upgradeToAndCall(newImplementation, data);\n } catch {\n // The implementation is not UUPS\n revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);\n }\n }\n}\n" }, "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are gener